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