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