oxpec.c 22 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Platform driver for OneXPlayer and AOKZOE devices.
  4. *
  5. * Fan control is provided via pwm interface in the range [0-255].
  6. * Old AMD boards use [0-100] as range in the EC, the written value is
  7. * scaled to accommodate for that. Newer boards like the mini PRO and
  8. * AOKZOE are not scaled but have the same EC layout. Newer models
  9. * like the 2 and X1 are [0-184] and are scaled to 0-255. OrangePi
  10. * are [1-244] and scaled to 0-255.
  11. *
  12. * Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com>
  13. * Copyright (C) 2024 Derek J. Clark <derekjohn.clark@gmail.com>
  14. * Copyright (C) 2025-2026 Antheas Kapenekakis <lkml@antheas.dev>
  15. */
  16. #include <linux/acpi.h>
  17. #include <linux/dmi.h>
  18. #include <linux/hwmon.h>
  19. #include <linux/init.h>
  20. #include <linux/kernel.h>
  21. #include <linux/module.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/processor.h>
  24. #include <acpi/battery.h>
  25. /* Handle ACPI lock mechanism */
  26. static u32 oxp_mutex;
  27. #define ACPI_LOCK_DELAY_MS 500
  28. static bool lock_global_acpi_lock(void)
  29. {
  30. return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex));
  31. }
  32. static bool unlock_global_acpi_lock(void)
  33. {
  34. return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex));
  35. }
  36. enum oxp_board {
  37. aok_zoe_a1 = 1,
  38. orange_pi_neo,
  39. oxp_2,
  40. oxp_fly,
  41. oxp_mini_amd,
  42. oxp_mini_amd_a07,
  43. oxp_mini_amd_pro,
  44. oxp_x1,
  45. oxp_g1_i,
  46. oxp_g1_a,
  47. };
  48. static enum oxp_board board;
  49. static struct device *oxp_dev;
  50. /* Fan reading and PWM */
  51. #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */
  52. #define OXP_2_SENSOR_FAN_REG 0x58 /* Fan reading is 2 registers long */
  53. #define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */
  54. #define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */
  55. #define PWM_MODE_AUTO 0x00
  56. #define PWM_MODE_MANUAL 0x01
  57. /* OrangePi fan reading and PWM */
  58. #define ORANGEPI_SENSOR_FAN_REG 0x78 /* Fan reading is 2 registers long */
  59. #define ORANGEPI_SENSOR_PWM_ENABLE_REG 0x40 /* PWM enable is 1 register long */
  60. #define ORANGEPI_SENSOR_PWM_REG 0x38 /* PWM reading is 1 register long */
  61. /* Turbo button takeover function
  62. * Different boards have different values and EC registers
  63. * for the same function
  64. */
  65. #define OXP_TURBO_SWITCH_REG 0xF1 /* Mini Pro, OneXFly, AOKZOE */
  66. #define OXP_2_TURBO_SWITCH_REG 0xEB /* OXP2 and X1 */
  67. #define OXP_MINI_TURBO_SWITCH_REG 0x1E /* Mini AO7 */
  68. #define OXP_MINI_TURBO_TAKE_VAL 0x01 /* Mini AO7 */
  69. #define OXP_TURBO_TAKE_VAL 0x40 /* All other models */
  70. /* X1 Turbo LED */
  71. #define OXP_X1_TURBO_LED_REG 0x57
  72. #define OXP_X1_TURBO_LED_OFF 0x01
  73. #define OXP_X1_TURBO_LED_ON 0x02
  74. /* Battery extension settings */
  75. #define EC_CHARGE_CONTROL_BEHAVIOURS (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \
  76. BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE) | \
  77. BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE))
  78. #define OXP_X1_CHARGE_LIMIT_REG 0xA3 /* X1 charge limit (%) */
  79. #define OXP_X1_CHARGE_INHIBIT_REG 0xA4 /* X1 bypass charging */
  80. #define OXP_X1_CHARGE_INHIBIT_MASK_AWAKE 0x01
  81. /* X1 Mask is 0x0A, F1Pro is 0x02 but the extra bit on the X1 does nothing. */
  82. #define OXP_X1_CHARGE_INHIBIT_MASK_OFF 0x02
  83. #define OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS (OXP_X1_CHARGE_INHIBIT_MASK_AWAKE | \
  84. OXP_X1_CHARGE_INHIBIT_MASK_OFF)
  85. static const struct dmi_system_id dmi_table[] = {
  86. {
  87. .matches = {
  88. DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
  89. DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"),
  90. },
  91. .driver_data = (void *)aok_zoe_a1,
  92. },
  93. {
  94. .matches = {
  95. DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
  96. DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 Pro"),
  97. },
  98. .driver_data = (void *)aok_zoe_a1,
  99. },
  100. {
  101. .matches = {
  102. DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
  103. DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A2 Pro"),
  104. },
  105. .driver_data = (void *)aok_zoe_a1,
  106. },
  107. {
  108. .matches = {
  109. DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
  110. DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1X"),
  111. },
  112. .driver_data = (void *)oxp_fly,
  113. },
  114. {
  115. .matches = {
  116. DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"),
  117. DMI_EXACT_MATCH(DMI_BOARD_NAME, "NEO-01"),
  118. },
  119. .driver_data = (void *)orange_pi_neo,
  120. },
  121. {
  122. .matches = {
  123. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  124. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
  125. },
  126. .driver_data = (void *)oxp_mini_amd,
  127. },
  128. {
  129. .matches = {
  130. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  131. DMI_MATCH(DMI_BOARD_NAME, "ONEXPLAYER 2"),
  132. },
  133. .driver_data = (void *)oxp_2,
  134. },
  135. {
  136. .matches = {
  137. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  138. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER APEX"),
  139. },
  140. .driver_data = (void *)oxp_fly,
  141. },
  142. {
  143. .matches = {
  144. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  145. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1"),
  146. },
  147. .driver_data = (void *)oxp_fly,
  148. },
  149. {
  150. .matches = {
  151. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  152. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 EVA-01"),
  153. },
  154. .driver_data = (void *)oxp_fly,
  155. },
  156. {
  157. .matches = {
  158. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  159. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 OLED"),
  160. },
  161. .driver_data = (void *)oxp_fly,
  162. },
  163. {
  164. .matches = {
  165. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  166. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1L"),
  167. },
  168. .driver_data = (void *)oxp_fly,
  169. },
  170. {
  171. .matches = {
  172. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  173. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1Pro"),
  174. },
  175. .driver_data = (void *)oxp_fly,
  176. },
  177. {
  178. .matches = {
  179. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  180. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 EVA-02"),
  181. },
  182. .driver_data = (void *)oxp_fly,
  183. },
  184. {
  185. .matches = {
  186. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  187. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER G1 A"),
  188. },
  189. .driver_data = (void *)oxp_g1_a,
  190. },
  191. {
  192. .matches = {
  193. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  194. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER G1 i"),
  195. },
  196. .driver_data = (void *)oxp_g1_i,
  197. },
  198. {
  199. .matches = {
  200. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  201. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"),
  202. },
  203. .driver_data = (void *)oxp_mini_amd_a07,
  204. },
  205. {
  206. .matches = {
  207. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  208. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
  209. },
  210. .driver_data = (void *)oxp_mini_amd_pro,
  211. },
  212. {
  213. .matches = {
  214. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  215. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1z"),
  216. },
  217. .driver_data = (void *)oxp_x1,
  218. },
  219. {
  220. .matches = {
  221. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  222. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 A"),
  223. },
  224. .driver_data = (void *)oxp_x1,
  225. },
  226. {
  227. .matches = {
  228. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  229. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 i"),
  230. },
  231. .driver_data = (void *)oxp_x1,
  232. },
  233. {
  234. .matches = {
  235. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  236. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Air"),
  237. },
  238. .driver_data = (void *)oxp_x1,
  239. },
  240. {
  241. .matches = {
  242. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  243. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 mini"),
  244. },
  245. .driver_data = (void *)oxp_x1,
  246. },
  247. {
  248. .matches = {
  249. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  250. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Mini Pro"),
  251. },
  252. .driver_data = (void *)oxp_x1,
  253. },
  254. {
  255. .matches = {
  256. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  257. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Pro"),
  258. },
  259. .driver_data = (void *)oxp_x1,
  260. },
  261. {
  262. .matches = {
  263. DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
  264. DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Pro EVA-02"),
  265. },
  266. .driver_data = (void *)oxp_x1,
  267. },
  268. {},
  269. };
  270. /* Helper functions to handle EC read/write */
  271. static int read_from_ec(u8 reg, int size, long *val)
  272. {
  273. u8 buffer;
  274. int ret;
  275. int i;
  276. if (!lock_global_acpi_lock())
  277. return -EBUSY;
  278. *val = 0;
  279. for (i = 0; i < size; i++) {
  280. ret = ec_read(reg + i, &buffer);
  281. if (ret)
  282. return ret;
  283. *val <<= i * 8;
  284. *val += buffer;
  285. }
  286. if (!unlock_global_acpi_lock())
  287. return -EBUSY;
  288. return 0;
  289. }
  290. static int write_to_ec(u8 reg, u8 value)
  291. {
  292. int ret;
  293. if (!lock_global_acpi_lock())
  294. return -EBUSY;
  295. ret = ec_write(reg, value);
  296. if (!unlock_global_acpi_lock())
  297. return -EBUSY;
  298. return ret;
  299. }
  300. /* Callbacks for turbo toggle attribute */
  301. static umode_t tt_toggle_is_visible(struct kobject *kobj,
  302. struct attribute *attr, int n)
  303. {
  304. switch (board) {
  305. case aok_zoe_a1:
  306. case oxp_2:
  307. case oxp_fly:
  308. case oxp_mini_amd_a07:
  309. case oxp_mini_amd_pro:
  310. case oxp_x1:
  311. case oxp_g1_i:
  312. case oxp_g1_a:
  313. return attr->mode;
  314. default:
  315. break;
  316. }
  317. return 0;
  318. }
  319. static ssize_t tt_toggle_store(struct device *dev,
  320. struct device_attribute *attr, const char *buf,
  321. size_t count)
  322. {
  323. u8 reg, mask, val;
  324. long raw_val;
  325. bool enable;
  326. int ret;
  327. ret = kstrtobool(buf, &enable);
  328. if (ret)
  329. return ret;
  330. switch (board) {
  331. case oxp_mini_amd_a07:
  332. reg = OXP_MINI_TURBO_SWITCH_REG;
  333. mask = OXP_MINI_TURBO_TAKE_VAL;
  334. break;
  335. case aok_zoe_a1:
  336. case oxp_fly:
  337. case oxp_mini_amd_pro:
  338. case oxp_g1_a:
  339. reg = OXP_TURBO_SWITCH_REG;
  340. mask = OXP_TURBO_TAKE_VAL;
  341. break;
  342. case oxp_2:
  343. case oxp_x1:
  344. case oxp_g1_i:
  345. reg = OXP_2_TURBO_SWITCH_REG;
  346. mask = OXP_TURBO_TAKE_VAL;
  347. break;
  348. default:
  349. return -EINVAL;
  350. }
  351. ret = read_from_ec(reg, 1, &raw_val);
  352. if (ret)
  353. return ret;
  354. val = raw_val;
  355. if (enable)
  356. val |= mask;
  357. else
  358. val &= ~mask;
  359. ret = write_to_ec(reg, val);
  360. if (ret)
  361. return ret;
  362. return count;
  363. }
  364. static ssize_t tt_toggle_show(struct device *dev,
  365. struct device_attribute *attr, char *buf)
  366. {
  367. u8 reg, mask;
  368. int retval;
  369. long val;
  370. switch (board) {
  371. case oxp_mini_amd_a07:
  372. reg = OXP_MINI_TURBO_SWITCH_REG;
  373. mask = OXP_MINI_TURBO_TAKE_VAL;
  374. break;
  375. case aok_zoe_a1:
  376. case oxp_fly:
  377. case oxp_mini_amd_pro:
  378. case oxp_g1_a:
  379. reg = OXP_TURBO_SWITCH_REG;
  380. mask = OXP_TURBO_TAKE_VAL;
  381. break;
  382. case oxp_2:
  383. case oxp_x1:
  384. case oxp_g1_i:
  385. reg = OXP_2_TURBO_SWITCH_REG;
  386. mask = OXP_TURBO_TAKE_VAL;
  387. break;
  388. default:
  389. return -EINVAL;
  390. }
  391. retval = read_from_ec(reg, 1, &val);
  392. if (retval)
  393. return retval;
  394. return sysfs_emit(buf, "%d\n", (val & mask) == mask);
  395. }
  396. static DEVICE_ATTR_RW(tt_toggle);
  397. /* Callbacks for turbo LED attribute */
  398. static umode_t tt_led_is_visible(struct kobject *kobj,
  399. struct attribute *attr, int n)
  400. {
  401. switch (board) {
  402. case oxp_x1:
  403. return attr->mode;
  404. default:
  405. break;
  406. }
  407. return 0;
  408. }
  409. static ssize_t tt_led_store(struct device *dev,
  410. struct device_attribute *attr, const char *buf,
  411. size_t count)
  412. {
  413. u8 reg, val;
  414. bool value;
  415. int ret;
  416. ret = kstrtobool(buf, &value);
  417. if (ret)
  418. return ret;
  419. switch (board) {
  420. case oxp_x1:
  421. reg = OXP_X1_TURBO_LED_REG;
  422. val = value ? OXP_X1_TURBO_LED_ON : OXP_X1_TURBO_LED_OFF;
  423. break;
  424. default:
  425. return -EINVAL;
  426. }
  427. ret = write_to_ec(reg, val);
  428. if (ret)
  429. return ret;
  430. return count;
  431. }
  432. static ssize_t tt_led_show(struct device *dev,
  433. struct device_attribute *attr, char *buf)
  434. {
  435. long enval;
  436. long val;
  437. int ret;
  438. u8 reg;
  439. switch (board) {
  440. case oxp_x1:
  441. reg = OXP_X1_TURBO_LED_REG;
  442. enval = OXP_X1_TURBO_LED_ON;
  443. break;
  444. default:
  445. return -EINVAL;
  446. }
  447. ret = read_from_ec(reg, 1, &val);
  448. if (ret)
  449. return ret;
  450. return sysfs_emit(buf, "%d\n", val == enval);
  451. }
  452. static DEVICE_ATTR_RW(tt_led);
  453. /* Callbacks for charge behaviour attributes */
  454. static bool oxp_psy_ext_supported(void)
  455. {
  456. switch (board) {
  457. case oxp_x1:
  458. case oxp_g1_i:
  459. case oxp_g1_a:
  460. case oxp_fly:
  461. return true;
  462. default:
  463. break;
  464. }
  465. return false;
  466. }
  467. static int oxp_psy_ext_get_prop(struct power_supply *psy,
  468. const struct power_supply_ext *ext,
  469. void *data,
  470. enum power_supply_property psp,
  471. union power_supply_propval *val)
  472. {
  473. long raw_val;
  474. int ret;
  475. switch (psp) {
  476. case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
  477. ret = read_from_ec(OXP_X1_CHARGE_LIMIT_REG, 1, &raw_val);
  478. if (ret)
  479. return ret;
  480. if (raw_val < 0 || raw_val > 100)
  481. return -EINVAL;
  482. val->intval = raw_val;
  483. return 0;
  484. case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
  485. ret = read_from_ec(OXP_X1_CHARGE_INHIBIT_REG, 1, &raw_val);
  486. if (ret)
  487. return ret;
  488. if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) ==
  489. OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS)
  490. val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
  491. else if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) ==
  492. OXP_X1_CHARGE_INHIBIT_MASK_AWAKE)
  493. val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE;
  494. else
  495. val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
  496. return 0;
  497. default:
  498. return -EINVAL;
  499. }
  500. }
  501. static int oxp_psy_ext_set_prop(struct power_supply *psy,
  502. const struct power_supply_ext *ext,
  503. void *data,
  504. enum power_supply_property psp,
  505. const union power_supply_propval *val)
  506. {
  507. long raw_val;
  508. switch (psp) {
  509. case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
  510. if (val->intval < 0 || val->intval > 100)
  511. return -EINVAL;
  512. return write_to_ec(OXP_X1_CHARGE_LIMIT_REG, val->intval);
  513. case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
  514. switch (val->intval) {
  515. case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
  516. raw_val = 0;
  517. break;
  518. case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE:
  519. raw_val = OXP_X1_CHARGE_INHIBIT_MASK_AWAKE;
  520. break;
  521. case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
  522. raw_val = OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS;
  523. break;
  524. default:
  525. return -EINVAL;
  526. }
  527. return write_to_ec(OXP_X1_CHARGE_INHIBIT_REG, raw_val);
  528. default:
  529. return -EINVAL;
  530. }
  531. }
  532. static int oxp_psy_prop_is_writeable(struct power_supply *psy,
  533. const struct power_supply_ext *ext,
  534. void *data,
  535. enum power_supply_property psp)
  536. {
  537. return true;
  538. }
  539. static const enum power_supply_property oxp_psy_ext_props[] = {
  540. POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
  541. POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
  542. };
  543. static const struct power_supply_ext oxp_psy_ext = {
  544. .name = "oxp-charge-control",
  545. .properties = oxp_psy_ext_props,
  546. .num_properties = ARRAY_SIZE(oxp_psy_ext_props),
  547. .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS,
  548. .get_property = oxp_psy_ext_get_prop,
  549. .set_property = oxp_psy_ext_set_prop,
  550. .property_is_writeable = oxp_psy_prop_is_writeable,
  551. };
  552. static int oxp_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
  553. {
  554. return power_supply_register_extension(battery, &oxp_psy_ext, oxp_dev, NULL);
  555. }
  556. static int oxp_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
  557. {
  558. power_supply_unregister_extension(battery, &oxp_psy_ext);
  559. return 0;
  560. }
  561. static struct acpi_battery_hook battery_hook = {
  562. .add_battery = oxp_add_battery,
  563. .remove_battery = oxp_remove_battery,
  564. .name = "OneXPlayer Battery",
  565. };
  566. /* PWM enable/disable functions */
  567. static int oxp_pwm_enable(void)
  568. {
  569. switch (board) {
  570. case orange_pi_neo:
  571. return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
  572. case aok_zoe_a1:
  573. case oxp_2:
  574. case oxp_fly:
  575. case oxp_mini_amd:
  576. case oxp_mini_amd_a07:
  577. case oxp_mini_amd_pro:
  578. case oxp_x1:
  579. case oxp_g1_i:
  580. case oxp_g1_a:
  581. return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
  582. default:
  583. return -EINVAL;
  584. }
  585. }
  586. static int oxp_pwm_disable(void)
  587. {
  588. switch (board) {
  589. case orange_pi_neo:
  590. return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
  591. case aok_zoe_a1:
  592. case oxp_2:
  593. case oxp_fly:
  594. case oxp_mini_amd:
  595. case oxp_mini_amd_a07:
  596. case oxp_mini_amd_pro:
  597. case oxp_x1:
  598. case oxp_g1_i:
  599. case oxp_g1_a:
  600. return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
  601. default:
  602. return -EINVAL;
  603. }
  604. }
  605. static int oxp_pwm_read(long *val)
  606. {
  607. switch (board) {
  608. case orange_pi_neo:
  609. return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val);
  610. case aok_zoe_a1:
  611. case oxp_2:
  612. case oxp_fly:
  613. case oxp_mini_amd:
  614. case oxp_mini_amd_a07:
  615. case oxp_mini_amd_pro:
  616. case oxp_x1:
  617. case oxp_g1_i:
  618. case oxp_g1_a:
  619. return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
  620. default:
  621. return -EOPNOTSUPP;
  622. }
  623. }
  624. /* Callbacks for hwmon interface */
  625. static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
  626. enum hwmon_sensor_types type, u32 attr, int channel)
  627. {
  628. switch (type) {
  629. case hwmon_fan:
  630. return 0444;
  631. case hwmon_pwm:
  632. return 0644;
  633. default:
  634. return 0;
  635. }
  636. }
  637. /* Fan speed read function */
  638. static int oxp_pwm_fan_speed(long *val)
  639. {
  640. switch (board) {
  641. case orange_pi_neo:
  642. return read_from_ec(ORANGEPI_SENSOR_FAN_REG, 2, val);
  643. case oxp_2:
  644. case oxp_x1:
  645. case oxp_g1_i:
  646. return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val);
  647. case aok_zoe_a1:
  648. case oxp_fly:
  649. case oxp_mini_amd:
  650. case oxp_mini_amd_a07:
  651. case oxp_mini_amd_pro:
  652. case oxp_g1_a:
  653. return read_from_ec(OXP_SENSOR_FAN_REG, 2, val);
  654. default:
  655. return -EOPNOTSUPP;
  656. }
  657. }
  658. /* PWM input read/write functions */
  659. static int oxp_pwm_input_write(long val)
  660. {
  661. if (val < 0 || val > 255)
  662. return -EINVAL;
  663. switch (board) {
  664. case orange_pi_neo:
  665. /* scale to range [1-244] */
  666. val = ((val - 1) * 243 / 254) + 1;
  667. return write_to_ec(ORANGEPI_SENSOR_PWM_REG, val);
  668. case oxp_2:
  669. case oxp_x1:
  670. case oxp_g1_i:
  671. /* scale to range [0-184] */
  672. val = (val * 184) / 255;
  673. return write_to_ec(OXP_SENSOR_PWM_REG, val);
  674. case oxp_mini_amd:
  675. case oxp_mini_amd_a07:
  676. /* scale to range [0-100] */
  677. val = (val * 100) / 255;
  678. return write_to_ec(OXP_SENSOR_PWM_REG, val);
  679. case aok_zoe_a1:
  680. case oxp_fly:
  681. case oxp_mini_amd_pro:
  682. case oxp_g1_a:
  683. return write_to_ec(OXP_SENSOR_PWM_REG, val);
  684. default:
  685. return -EOPNOTSUPP;
  686. }
  687. }
  688. static int oxp_pwm_input_read(long *val)
  689. {
  690. int ret;
  691. switch (board) {
  692. case orange_pi_neo:
  693. ret = read_from_ec(ORANGEPI_SENSOR_PWM_REG, 1, val);
  694. if (ret)
  695. return ret;
  696. /* scale from range [1-244] */
  697. *val = ((*val - 1) * 254 / 243) + 1;
  698. break;
  699. case oxp_2:
  700. case oxp_x1:
  701. case oxp_g1_i:
  702. ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
  703. if (ret)
  704. return ret;
  705. /* scale from range [0-184] */
  706. *val = (*val * 255) / 184;
  707. break;
  708. case oxp_mini_amd:
  709. case oxp_mini_amd_a07:
  710. ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
  711. if (ret)
  712. return ret;
  713. /* scale from range [0-100] */
  714. *val = (*val * 255) / 100;
  715. break;
  716. case aok_zoe_a1:
  717. case oxp_fly:
  718. case oxp_mini_amd_pro:
  719. case oxp_g1_a:
  720. default:
  721. ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
  722. if (ret)
  723. return ret;
  724. break;
  725. }
  726. return 0;
  727. }
  728. static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
  729. u32 attr, int channel, long *val)
  730. {
  731. int ret;
  732. switch (type) {
  733. case hwmon_fan:
  734. switch (attr) {
  735. case hwmon_fan_input:
  736. return oxp_pwm_fan_speed(val);
  737. default:
  738. break;
  739. }
  740. break;
  741. case hwmon_pwm:
  742. switch (attr) {
  743. case hwmon_pwm_input:
  744. return oxp_pwm_input_read(val);
  745. case hwmon_pwm_enable:
  746. ret = oxp_pwm_read(val);
  747. if (ret)
  748. return ret;
  749. /* Check for auto and return 2 */
  750. if (!*val) {
  751. *val = 2;
  752. return 0;
  753. }
  754. /* Return 0 if at full fan speed, 1 otherwise */
  755. ret = oxp_pwm_fan_speed(val);
  756. if (ret)
  757. return ret;
  758. if (*val == 255)
  759. *val = 0;
  760. else
  761. *val = 1;
  762. return 0;
  763. default:
  764. break;
  765. }
  766. break;
  767. default:
  768. break;
  769. }
  770. return -EOPNOTSUPP;
  771. }
  772. static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
  773. u32 attr, int channel, long val)
  774. {
  775. int ret;
  776. switch (type) {
  777. case hwmon_pwm:
  778. switch (attr) {
  779. case hwmon_pwm_enable:
  780. if (val == 1)
  781. return oxp_pwm_enable();
  782. else if (val == 2)
  783. return oxp_pwm_disable();
  784. else if (val != 0)
  785. return -EINVAL;
  786. /* Enable PWM and set to max speed */
  787. ret = oxp_pwm_enable();
  788. if (ret)
  789. return ret;
  790. return oxp_pwm_input_write(255);
  791. case hwmon_pwm_input:
  792. return oxp_pwm_input_write(val);
  793. default:
  794. break;
  795. }
  796. break;
  797. default:
  798. break;
  799. }
  800. return -EOPNOTSUPP;
  801. }
  802. /* Known sensors in the OXP EC controllers */
  803. static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
  804. HWMON_CHANNEL_INFO(fan,
  805. HWMON_F_INPUT),
  806. HWMON_CHANNEL_INFO(pwm,
  807. HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
  808. NULL,
  809. };
  810. static struct attribute *oxp_tt_toggle_attrs[] = {
  811. &dev_attr_tt_toggle.attr,
  812. NULL
  813. };
  814. static const struct attribute_group oxp_tt_toggle_attribute_group = {
  815. .is_visible = tt_toggle_is_visible,
  816. .attrs = oxp_tt_toggle_attrs,
  817. };
  818. static struct attribute *oxp_tt_led_attrs[] = {
  819. &dev_attr_tt_led.attr,
  820. NULL
  821. };
  822. static const struct attribute_group oxp_tt_led_attribute_group = {
  823. .is_visible = tt_led_is_visible,
  824. .attrs = oxp_tt_led_attrs,
  825. };
  826. static const struct attribute_group *oxp_ec_groups[] = {
  827. &oxp_tt_toggle_attribute_group,
  828. &oxp_tt_led_attribute_group,
  829. NULL
  830. };
  831. static const struct hwmon_ops oxp_ec_hwmon_ops = {
  832. .is_visible = oxp_ec_hwmon_is_visible,
  833. .read = oxp_platform_read,
  834. .write = oxp_platform_write,
  835. };
  836. static const struct hwmon_chip_info oxp_ec_chip_info = {
  837. .ops = &oxp_ec_hwmon_ops,
  838. .info = oxp_platform_sensors,
  839. };
  840. /* Initialization logic */
  841. static int oxp_platform_probe(struct platform_device *pdev)
  842. {
  843. struct device *dev = &pdev->dev;
  844. struct device *hwdev;
  845. int ret;
  846. oxp_dev = dev;
  847. hwdev = devm_hwmon_device_register_with_info(dev, "oxp_ec", NULL,
  848. &oxp_ec_chip_info, NULL);
  849. if (IS_ERR(hwdev))
  850. return PTR_ERR(hwdev);
  851. if (oxp_psy_ext_supported()) {
  852. ret = devm_battery_hook_register(dev, &battery_hook);
  853. if (ret)
  854. return ret;
  855. }
  856. return 0;
  857. }
  858. static struct platform_driver oxp_platform_driver = {
  859. .driver = {
  860. .name = "oxp-platform",
  861. .dev_groups = oxp_ec_groups,
  862. },
  863. .probe = oxp_platform_probe,
  864. };
  865. static struct platform_device *oxp_platform_device;
  866. static int __init oxp_platform_init(void)
  867. {
  868. const struct dmi_system_id *dmi_entry;
  869. dmi_entry = dmi_first_match(dmi_table);
  870. if (!dmi_entry)
  871. return -ENODEV;
  872. board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
  873. /*
  874. * Have to check for AMD processor here because DMI strings are the same
  875. * between Intel and AMD boards on older OneXPlayer devices, the only way
  876. * to tell them apart is the CPU. Old Intel boards have an unsupported EC.
  877. */
  878. if (board == oxp_mini_amd && boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
  879. return -ENODEV;
  880. oxp_platform_device =
  881. platform_create_bundle(&oxp_platform_driver,
  882. oxp_platform_probe, NULL, 0, NULL, 0);
  883. return PTR_ERR_OR_ZERO(oxp_platform_device);
  884. }
  885. static void __exit oxp_platform_exit(void)
  886. {
  887. platform_device_unregister(oxp_platform_device);
  888. platform_driver_unregister(&oxp_platform_driver);
  889. }
  890. MODULE_DEVICE_TABLE(dmi, dmi_table);
  891. module_init(oxp_platform_init);
  892. module_exit(oxp_platform_exit);
  893. MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>");
  894. MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices");
  895. MODULE_LICENSE("GPL");