portwell-ec.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * portwell-ec.c: Portwell embedded controller driver.
  4. *
  5. * Tested on:
  6. * - Portwell NANO-6064
  7. *
  8. * This driver supports Portwell boards with an ITE embedded controller (EC).
  9. * The EC is accessed through I/O ports and provides:
  10. * - Temperature and voltage readings (hwmon)
  11. * - 8 GPIO pins for control and monitoring
  12. * - Hardware watchdog with 1-15300 second timeout range
  13. *
  14. * It integrates with the Linux hwmon, GPIO and Watchdog subsystems.
  15. *
  16. * (C) Copyright 2025 Portwell, Inc.
  17. * Author: Yen-Chi Huang (jesse.huang@portwell.com.tw)
  18. */
  19. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  20. #include <linux/acpi.h>
  21. #include <linux/bits.h>
  22. #include <linux/bitfield.h>
  23. #include <linux/dmi.h>
  24. #include <linux/gpio/driver.h>
  25. #include <linux/hwmon.h>
  26. #include <linux/init.h>
  27. #include <linux/io.h>
  28. #include <linux/ioport.h>
  29. #include <linux/module.h>
  30. #include <linux/platform_device.h>
  31. #include <linux/pm.h>
  32. #include <linux/sizes.h>
  33. #include <linux/string.h>
  34. #include <linux/units.h>
  35. #include <linux/watchdog.h>
  36. #define PORTWELL_EC_IOSPACE 0xe300
  37. #define PORTWELL_EC_IOSPACE_LEN SZ_256
  38. #define PORTWELL_GPIO_PINS 8
  39. #define PORTWELL_GPIO_DIR_REG 0x2b
  40. #define PORTWELL_GPIO_VAL_REG 0x2c
  41. #define PORTWELL_HWMON_TEMP_NUM 3
  42. #define PORTWELL_HWMON_VOLT_NUM 5
  43. #define PORTWELL_WDT_EC_CONFIG_ADDR 0x06
  44. #define PORTWELL_WDT_CONFIG_ENABLE 0x1
  45. #define PORTWELL_WDT_CONFIG_DISABLE 0x0
  46. #define PORTWELL_WDT_EC_COUNT_MIN_ADDR 0x07
  47. #define PORTWELL_WDT_EC_COUNT_SEC_ADDR 0x08
  48. #define PORTWELL_WDT_EC_MAX_COUNT_SECOND (255 * 60)
  49. #define PORTWELL_EC_FW_VENDOR_ADDRESS 0x4d
  50. #define PORTWELL_EC_FW_VENDOR_LENGTH 3
  51. #define PORTWELL_EC_FW_VENDOR_NAME "PWG"
  52. #define PORTWELL_EC_ADC_MAX 1023
  53. static bool force;
  54. module_param(force, bool, 0444);
  55. MODULE_PARM_DESC(force, "Force loading EC driver without checking DMI boardname");
  56. /* A sensor's metadata (label, scale, and register) */
  57. struct pwec_sensor_prop {
  58. const char *label;
  59. u8 reg;
  60. u32 scale;
  61. };
  62. /* Master configuration with properties for all possible sensors */
  63. static const struct {
  64. const struct pwec_sensor_prop temp_props[PORTWELL_HWMON_TEMP_NUM];
  65. const struct pwec_sensor_prop in_props[PORTWELL_HWMON_VOLT_NUM];
  66. } pwec_master_data = {
  67. .temp_props = {
  68. { "CPU Temperature", 0x00, 0 },
  69. { "System Temperature", 0x02, 0 },
  70. { "Aux Temperature", 0x04, 0 },
  71. },
  72. .in_props = {
  73. { "Vcore", 0x20, 3000 },
  74. { "3.3V", 0x22, 6000 },
  75. { "5V", 0x24, 9600 },
  76. { "12V", 0x30, 19800 },
  77. { "VDIMM", 0x32, 3000 },
  78. },
  79. };
  80. struct pwec_board_info {
  81. u32 temp_mask; /* bit N = temperature channel N */
  82. u32 in_mask; /* bit N = voltage channel N */
  83. };
  84. static const struct pwec_board_info pwec_board_info_default = {
  85. .temp_mask = GENMASK(PORTWELL_HWMON_TEMP_NUM - 1, 0),
  86. .in_mask = GENMASK(PORTWELL_HWMON_VOLT_NUM - 1, 0),
  87. };
  88. static const struct pwec_board_info pwec_board_info_nano = {
  89. .temp_mask = BIT(0) | BIT(1),
  90. .in_mask = GENMASK(4, 0),
  91. };
  92. static const struct dmi_system_id pwec_dmi_table[] = {
  93. {
  94. .ident = "NANO-6064 series",
  95. .matches = {
  96. DMI_MATCH(DMI_BOARD_NAME, "NANO-6064"),
  97. },
  98. .driver_data = (void *)&pwec_board_info_nano,
  99. },
  100. { }
  101. };
  102. MODULE_DEVICE_TABLE(dmi, pwec_dmi_table);
  103. /* Functions for access EC via IOSPACE */
  104. static void pwec_write(u8 index, u8 data)
  105. {
  106. outb(data, PORTWELL_EC_IOSPACE + index);
  107. }
  108. static u8 pwec_read(u8 address)
  109. {
  110. return inb(PORTWELL_EC_IOSPACE + address);
  111. }
  112. /* Ensure consistent 16-bit read across potential MSB rollover. */
  113. static u16 pwec_read16_stable(u8 lsb_reg)
  114. {
  115. u8 lsb, msb, old_msb;
  116. do {
  117. old_msb = pwec_read(lsb_reg + 1);
  118. lsb = pwec_read(lsb_reg);
  119. msb = pwec_read(lsb_reg + 1);
  120. } while (msb != old_msb);
  121. return (msb << 8) | lsb;
  122. }
  123. /* GPIO functions */
  124. static int pwec_gpio_get(struct gpio_chip *chip, unsigned int offset)
  125. {
  126. return pwec_read(PORTWELL_GPIO_VAL_REG) & BIT(offset) ? 1 : 0;
  127. }
  128. static int pwec_gpio_set(struct gpio_chip *chip, unsigned int offset, int val)
  129. {
  130. u8 tmp = pwec_read(PORTWELL_GPIO_VAL_REG);
  131. if (val)
  132. tmp |= BIT(offset);
  133. else
  134. tmp &= ~BIT(offset);
  135. pwec_write(PORTWELL_GPIO_VAL_REG, tmp);
  136. return 0;
  137. }
  138. static int pwec_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
  139. {
  140. u8 direction = pwec_read(PORTWELL_GPIO_DIR_REG) & BIT(offset);
  141. if (direction)
  142. return GPIO_LINE_DIRECTION_IN;
  143. return GPIO_LINE_DIRECTION_OUT;
  144. }
  145. /*
  146. * Changing direction causes issues on some boards,
  147. * so direction_input and direction_output are disabled for now.
  148. */
  149. static int pwec_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
  150. {
  151. return -EOPNOTSUPP;
  152. }
  153. static int pwec_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
  154. {
  155. return -EOPNOTSUPP;
  156. }
  157. static struct gpio_chip pwec_gpio_chip = {
  158. .label = "portwell-ec-gpio",
  159. .get_direction = pwec_gpio_get_direction,
  160. .direction_input = pwec_gpio_direction_input,
  161. .direction_output = pwec_gpio_direction_output,
  162. .get = pwec_gpio_get,
  163. .set = pwec_gpio_set,
  164. .base = -1,
  165. .ngpio = PORTWELL_GPIO_PINS,
  166. };
  167. /* Watchdog functions */
  168. static void pwec_wdt_write_timeout(unsigned int timeout)
  169. {
  170. pwec_write(PORTWELL_WDT_EC_COUNT_MIN_ADDR, timeout / 60);
  171. pwec_write(PORTWELL_WDT_EC_COUNT_SEC_ADDR, timeout % 60);
  172. }
  173. static int pwec_wdt_trigger(struct watchdog_device *wdd)
  174. {
  175. pwec_wdt_write_timeout(wdd->timeout);
  176. pwec_write(PORTWELL_WDT_EC_CONFIG_ADDR, PORTWELL_WDT_CONFIG_ENABLE);
  177. return 0;
  178. }
  179. static int pwec_wdt_start(struct watchdog_device *wdd)
  180. {
  181. return pwec_wdt_trigger(wdd);
  182. }
  183. static int pwec_wdt_stop(struct watchdog_device *wdd)
  184. {
  185. pwec_write(PORTWELL_WDT_EC_CONFIG_ADDR, PORTWELL_WDT_CONFIG_DISABLE);
  186. return 0;
  187. }
  188. static int pwec_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
  189. {
  190. wdd->timeout = timeout;
  191. pwec_wdt_write_timeout(wdd->timeout);
  192. return 0;
  193. }
  194. /* Ensure consistent min/sec read in case of second rollover. */
  195. static unsigned int pwec_wdt_get_timeleft(struct watchdog_device *wdd)
  196. {
  197. u8 sec, min, old_min;
  198. do {
  199. old_min = pwec_read(PORTWELL_WDT_EC_COUNT_MIN_ADDR);
  200. sec = pwec_read(PORTWELL_WDT_EC_COUNT_SEC_ADDR);
  201. min = pwec_read(PORTWELL_WDT_EC_COUNT_MIN_ADDR);
  202. } while (min != old_min);
  203. return min * 60 + sec;
  204. }
  205. static const struct watchdog_ops pwec_wdt_ops = {
  206. .owner = THIS_MODULE,
  207. .start = pwec_wdt_start,
  208. .stop = pwec_wdt_stop,
  209. .ping = pwec_wdt_trigger,
  210. .set_timeout = pwec_wdt_set_timeout,
  211. .get_timeleft = pwec_wdt_get_timeleft,
  212. };
  213. static struct watchdog_device ec_wdt_dev = {
  214. .info = &(struct watchdog_info){
  215. .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
  216. .identity = "Portwell EC watchdog",
  217. },
  218. .ops = &pwec_wdt_ops,
  219. .timeout = 60,
  220. .min_timeout = 1,
  221. .max_timeout = PORTWELL_WDT_EC_MAX_COUNT_SECOND,
  222. };
  223. /* HWMON functions */
  224. static umode_t pwec_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
  225. u32 attr, int channel)
  226. {
  227. const struct pwec_board_info *info = drvdata;
  228. switch (type) {
  229. case hwmon_temp:
  230. return (info->temp_mask & BIT(channel)) ? 0444 : 0;
  231. case hwmon_in:
  232. return (info->in_mask & BIT(channel)) ? 0444 : 0;
  233. default:
  234. return 0;
  235. }
  236. }
  237. static int pwec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
  238. u32 attr, int channel, long *val)
  239. {
  240. u16 tmp16;
  241. switch (type) {
  242. case hwmon_temp:
  243. *val = pwec_read(pwec_master_data.temp_props[channel].reg) * MILLIDEGREE_PER_DEGREE;
  244. return 0;
  245. case hwmon_in:
  246. tmp16 = pwec_read16_stable(pwec_master_data.in_props[channel].reg);
  247. *val = (tmp16 * pwec_master_data.in_props[channel].scale) / PORTWELL_EC_ADC_MAX;
  248. return 0;
  249. default:
  250. return -EOPNOTSUPP;
  251. }
  252. }
  253. static int pwec_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
  254. u32 attr, int channel, const char **str)
  255. {
  256. switch (type) {
  257. case hwmon_temp:
  258. *str = pwec_master_data.temp_props[channel].label;
  259. return 0;
  260. case hwmon_in:
  261. *str = pwec_master_data.in_props[channel].label;
  262. return 0;
  263. default:
  264. return -EOPNOTSUPP;
  265. }
  266. }
  267. static const struct hwmon_channel_info *pwec_hwmon_info[] = {
  268. HWMON_CHANNEL_INFO(temp,
  269. HWMON_T_INPUT | HWMON_T_LABEL,
  270. HWMON_T_INPUT | HWMON_T_LABEL,
  271. HWMON_T_INPUT | HWMON_T_LABEL),
  272. HWMON_CHANNEL_INFO(in,
  273. HWMON_I_INPUT | HWMON_I_LABEL,
  274. HWMON_I_INPUT | HWMON_I_LABEL,
  275. HWMON_I_INPUT | HWMON_I_LABEL,
  276. HWMON_I_INPUT | HWMON_I_LABEL,
  277. HWMON_I_INPUT | HWMON_I_LABEL),
  278. NULL
  279. };
  280. static const struct hwmon_ops pwec_hwmon_ops = {
  281. .is_visible = pwec_hwmon_is_visible,
  282. .read = pwec_hwmon_read,
  283. .read_string = pwec_hwmon_read_string,
  284. };
  285. static const struct hwmon_chip_info pwec_chip_info = {
  286. .ops = &pwec_hwmon_ops,
  287. .info = pwec_hwmon_info,
  288. };
  289. static int pwec_firmware_vendor_check(void)
  290. {
  291. u8 buf[PORTWELL_EC_FW_VENDOR_LENGTH + 1];
  292. u8 i;
  293. for (i = 0; i < PORTWELL_EC_FW_VENDOR_LENGTH; i++)
  294. buf[i] = pwec_read(PORTWELL_EC_FW_VENDOR_ADDRESS + i);
  295. buf[PORTWELL_EC_FW_VENDOR_LENGTH] = '\0';
  296. return !strcmp(PORTWELL_EC_FW_VENDOR_NAME, buf) ? 0 : -ENODEV;
  297. }
  298. static int pwec_probe(struct platform_device *pdev)
  299. {
  300. struct device *hwmon_dev;
  301. void *drvdata = dev_get_platdata(&pdev->dev);
  302. int ret;
  303. if (!devm_request_region(&pdev->dev, PORTWELL_EC_IOSPACE,
  304. PORTWELL_EC_IOSPACE_LEN, dev_name(&pdev->dev))) {
  305. dev_err(&pdev->dev, "failed to get IO region\n");
  306. return -EBUSY;
  307. }
  308. ret = pwec_firmware_vendor_check();
  309. if (ret < 0)
  310. return ret;
  311. ret = devm_gpiochip_add_data(&pdev->dev, &pwec_gpio_chip, NULL);
  312. if (ret < 0) {
  313. dev_err(&pdev->dev, "failed to register Portwell EC GPIO\n");
  314. return ret;
  315. }
  316. if (IS_REACHABLE(CONFIG_HWMON)) {
  317. hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
  318. "portwell_ec", drvdata, &pwec_chip_info, NULL);
  319. ret = PTR_ERR_OR_ZERO(hwmon_dev);
  320. if (ret)
  321. return ret;
  322. }
  323. ec_wdt_dev.parent = &pdev->dev;
  324. return devm_watchdog_register_device(&pdev->dev, &ec_wdt_dev);
  325. }
  326. static int pwec_suspend(struct device *dev)
  327. {
  328. if (watchdog_active(&ec_wdt_dev))
  329. return pwec_wdt_stop(&ec_wdt_dev);
  330. return 0;
  331. }
  332. static int pwec_resume(struct device *dev)
  333. {
  334. if (watchdog_active(&ec_wdt_dev))
  335. return pwec_wdt_start(&ec_wdt_dev);
  336. return 0;
  337. }
  338. static DEFINE_SIMPLE_DEV_PM_OPS(pwec_dev_pm_ops, pwec_suspend, pwec_resume);
  339. static struct platform_driver pwec_driver = {
  340. .driver = {
  341. .name = "portwell-ec",
  342. .pm = pm_sleep_ptr(&pwec_dev_pm_ops),
  343. },
  344. .probe = pwec_probe,
  345. };
  346. static struct platform_device *pwec_dev;
  347. static int __init pwec_init(void)
  348. {
  349. const struct dmi_system_id *match;
  350. const struct pwec_board_info *hwmon_data;
  351. int ret;
  352. match = dmi_first_match(pwec_dmi_table);
  353. if (!match) {
  354. if (!force)
  355. return -ENODEV;
  356. hwmon_data = &pwec_board_info_default;
  357. pr_warn("force load portwell-ec without DMI check, using full display config\n");
  358. } else {
  359. hwmon_data = match->driver_data;
  360. }
  361. ret = platform_driver_register(&pwec_driver);
  362. if (ret)
  363. return ret;
  364. pwec_dev = platform_device_register_data(NULL, "portwell-ec", PLATFORM_DEVID_NONE,
  365. hwmon_data, sizeof(*hwmon_data));
  366. if (IS_ERR(pwec_dev)) {
  367. platform_driver_unregister(&pwec_driver);
  368. return PTR_ERR(pwec_dev);
  369. }
  370. return 0;
  371. }
  372. static void __exit pwec_exit(void)
  373. {
  374. platform_device_unregister(pwec_dev);
  375. platform_driver_unregister(&pwec_driver);
  376. }
  377. module_init(pwec_init);
  378. module_exit(pwec_exit);
  379. MODULE_AUTHOR("Yen-Chi Huang <jesse.huang@portwell.com.tw>");
  380. MODULE_DESCRIPTION("Portwell EC Driver");
  381. MODULE_LICENSE("GPL");