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