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