xref: /linux/drivers/platform/x86/oxpec.c (revision 5b05bb3f6c5716fab6911e12d60dd1f43ad9806a)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Platform driver for OneXPlayer and AOKZOE devices.
4  *
5  * Fan control is provided via pwm interface in the range [0-255].
6  * Old AMD boards use [0-100] as range in the EC, the written value is
7  * scaled to accommodate for that. Newer boards like the mini PRO and
8  * AOKZOE are not scaled but have the same EC layout. Newer models
9  * like the 2 and X1 are [0-184] and are scaled to 0-255. OrangePi
10  * are [1-244] and scaled to 0-255.
11  *
12  * Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com>
13  * Copyright (C) 2024 Derek J. Clark <derekjohn.clark@gmail.com>
14  * Copyright (C) 2025-2026 Antheas Kapenekakis <lkml@antheas.dev>
15  */
16 
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 A2 Pro"),
121 		},
122 		.driver_data = (void *)aok_zoe_a1,
123 	},
124 	{
125 		.matches = {
126 			DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
127 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1X"),
128 		},
129 		.driver_data = (void *)oxp_fly,
130 	},
131 	{
132 		.matches = {
133 			DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"),
134 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "NEO-01"),
135 		},
136 		.driver_data = (void *)orange_pi_neo,
137 	},
138 	{
139 		.matches = {
140 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
141 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
142 		},
143 		.driver_data = (void *)oxp_mini_amd,
144 	},
145 	{
146 		.matches = {
147 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
148 			DMI_MATCH(DMI_BOARD_NAME, "ONEXPLAYER 2"),
149 		},
150 		.driver_data = (void *)oxp_2,
151 	},
152 	{
153 		.matches = {
154 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
155 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER APEX"),
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"),
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 F1 EVA-01"),
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 F1 OLED"),
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 F1L"),
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 F1Pro"),
191 		},
192 		.driver_data = (void *)oxp_fly,
193 	},
194 	{
195 		.matches = {
196 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
197 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 EVA-02"),
198 		},
199 		.driver_data = (void *)oxp_fly,
200 	},
201 	{
202 		.matches = {
203 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
204 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER G1 A"),
205 		},
206 		.driver_data = (void *)oxp_g1_a,
207 	},
208 	{
209 		.matches = {
210 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
211 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER SUPER X"),
212 		},
213 		.driver_data = (void *)oxp_g1_a,
214 	},
215 	{
216 		.matches = {
217 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
218 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER G1 i"),
219 		},
220 		.driver_data = (void *)oxp_g1_i,
221 	},
222 	{
223 		.matches = {
224 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
225 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"),
226 		},
227 		.driver_data = (void *)oxp_mini_amd_a07,
228 	},
229 	{
230 		.matches = {
231 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
232 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
233 		},
234 		.driver_data = (void *)oxp_mini_amd_pro,
235 	},
236 	{
237 		.matches = {
238 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
239 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1z"),
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 X1 A"),
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 X1 i"),
254 		},
255 		.driver_data = (void *)oxp_x1,
256 	},
257 	{
258 		.matches = {
259 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
260 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Air"),
261 		},
262 		.driver_data = (void *)oxp_x1,
263 	},
264 	{
265 		.matches = {
266 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
267 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 mini"),
268 		},
269 		.driver_data = (void *)oxp_x1,
270 	},
271 	{
272 		.matches = {
273 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
274 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Mini Pro"),
275 		},
276 		.driver_data = (void *)oxp_x1,
277 	},
278 	{
279 		.matches = {
280 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
281 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Pro"),
282 		},
283 		.driver_data = (void *)oxp_x1,
284 	},
285 	{
286 		.matches = {
287 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
288 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Pro EVA-02"),
289 		},
290 		.driver_data = (void *)oxp_x1,
291 	},
292 	{
293 		.matches = {
294 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
295 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X2Mini PRO"),
296 		},
297 		.driver_data = (void *)oxp_fly,
298 	},
299 	{},
300 };
301 
302 /* Helper functions to handle EC read/write */
read_from_ec(u8 reg,int size,long * val)303 static int read_from_ec(u8 reg, int size, long *val)
304 {
305 	u8 buffer;
306 	int ret;
307 	int i;
308 
309 	if (!lock_global_acpi_lock())
310 		return -EBUSY;
311 
312 	*val = 0;
313 	for (i = 0; i < size; i++) {
314 		ret = ec_read(reg + i, &buffer);
315 		if (ret)
316 			return ret;
317 		*val <<= i * 8;
318 		*val += buffer;
319 	}
320 
321 	if (!unlock_global_acpi_lock())
322 		return -EBUSY;
323 
324 	return 0;
325 }
326 
write_to_ec(u8 reg,u8 value)327 static int write_to_ec(u8 reg, u8 value)
328 {
329 	int ret;
330 
331 	if (!lock_global_acpi_lock())
332 		return -EBUSY;
333 
334 	ret = ec_write(reg, value);
335 
336 	if (!unlock_global_acpi_lock())
337 		return -EBUSY;
338 
339 	return ret;
340 }
341 
342 /* Callbacks for turbo toggle attribute */
tt_toggle_is_visible(struct kobject * kobj,struct attribute * attr,int n)343 static umode_t tt_toggle_is_visible(struct kobject *kobj,
344 				    struct attribute *attr, int n)
345 {
346 	switch (board) {
347 	case aok_zoe_a1:
348 	case oxp_2:
349 	case oxp_fly:
350 	case oxp_mini_amd_a07:
351 	case oxp_mini_amd_pro:
352 	case oxp_x1:
353 	case oxp_g1_i:
354 	case oxp_g1_a:
355 		return attr->mode;
356 	default:
357 		break;
358 	}
359 	return 0;
360 }
361 
tt_toggle_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)362 static ssize_t tt_toggle_store(struct device *dev,
363 			       struct device_attribute *attr, const char *buf,
364 			       size_t count)
365 {
366 	u8 reg, mask, val;
367 	long raw_val;
368 	bool enable;
369 	int ret;
370 
371 	ret = kstrtobool(buf, &enable);
372 	if (ret)
373 		return ret;
374 
375 	switch (board) {
376 	case oxp_mini_amd_a07:
377 		reg = OXP_MINI_TURBO_SWITCH_REG;
378 		mask = OXP_MINI_TURBO_TAKE_VAL;
379 		break;
380 	case aok_zoe_a1:
381 	case oxp_fly:
382 	case oxp_mini_amd_pro:
383 	case oxp_g1_a:
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_i:
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 	case oxp_g1_a:
430 		reg = OXP_TURBO_SWITCH_REG;
431 		mask = OXP_TURBO_TAKE_VAL;
432 		break;
433 	case oxp_2:
434 	case oxp_x1:
435 	case oxp_g1_i:
436 		reg = OXP_2_TURBO_SWITCH_REG;
437 		mask = OXP_TURBO_TAKE_VAL;
438 		break;
439 	default:
440 		return -EINVAL;
441 	}
442 
443 	retval = read_from_ec(reg, 1, &val);
444 	if (retval)
445 		return retval;
446 
447 	return sysfs_emit(buf, "%d\n", (val & mask) == mask);
448 }
449 
450 static DEVICE_ATTR_RW(tt_toggle);
451 
452 /* Callbacks for turbo LED attribute */
tt_led_is_visible(struct kobject * kobj,struct attribute * attr,int n)453 static umode_t tt_led_is_visible(struct kobject *kobj,
454 				 struct attribute *attr, int n)
455 {
456 	switch (board) {
457 	case oxp_x1:
458 		return attr->mode;
459 	default:
460 		break;
461 	}
462 	return 0;
463 }
464 
tt_led_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)465 static ssize_t tt_led_store(struct device *dev,
466 			    struct device_attribute *attr, const char *buf,
467 			    size_t count)
468 {
469 	u8 reg, val;
470 	bool value;
471 	int ret;
472 
473 	ret = kstrtobool(buf, &value);
474 	if (ret)
475 		return ret;
476 
477 	switch (board) {
478 	case oxp_x1:
479 		reg = OXP_X1_TURBO_LED_REG;
480 		val = value ? OXP_X1_TURBO_LED_ON : OXP_X1_TURBO_LED_OFF;
481 		break;
482 	default:
483 		return -EINVAL;
484 	}
485 
486 	ret = write_to_ec(reg, val);
487 	if (ret)
488 		return ret;
489 
490 	return count;
491 }
492 
tt_led_show(struct device * dev,struct device_attribute * attr,char * buf)493 static ssize_t tt_led_show(struct device *dev,
494 			   struct device_attribute *attr, char *buf)
495 {
496 	long enval;
497 	long val;
498 	int ret;
499 	u8 reg;
500 
501 	switch (board) {
502 	case oxp_x1:
503 		reg = OXP_X1_TURBO_LED_REG;
504 		enval = OXP_X1_TURBO_LED_ON;
505 		break;
506 	default:
507 		return -EINVAL;
508 	}
509 
510 	ret = read_from_ec(reg, 1, &val);
511 	if (ret)
512 		return ret;
513 
514 	return sysfs_emit(buf, "%d\n", val == enval);
515 }
516 
517 static DEVICE_ATTR_RW(tt_led);
518 
519 /* Callbacks for charge behaviour attributes */
oxp_psy_ext_supported(void)520 static bool oxp_psy_ext_supported(void)
521 {
522 	switch (board) {
523 	case oxp_x1:
524 	case oxp_g1_i:
525 	case oxp_g1_a:
526 	case oxp_fly:
527 		return true;
528 	default:
529 		break;
530 	}
531 	return false;
532 }
533 
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)534 static int oxp_psy_ext_get_prop(struct power_supply *psy,
535 				const struct power_supply_ext *ext,
536 				void *data,
537 				enum power_supply_property psp,
538 				union power_supply_propval *val)
539 {
540 	long raw_val;
541 	int ret;
542 
543 	switch (psp) {
544 	case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
545 		ret = read_from_ec(OXP_X1_CHARGE_LIMIT_REG, 1, &raw_val);
546 		if (ret)
547 			return ret;
548 		if (raw_val < 0 || raw_val > 100)
549 			return -EINVAL;
550 		val->intval = raw_val;
551 		return 0;
552 	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
553 		ret = read_from_ec(OXP_X1_CHARGE_INHIBIT_REG, 1, &raw_val);
554 		if (ret)
555 			return ret;
556 		if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) ==
557 		    OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS)
558 			val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
559 		else if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) ==
560 			 OXP_X1_CHARGE_INHIBIT_MASK_AWAKE)
561 			val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE;
562 		else
563 			val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
564 		return 0;
565 	default:
566 		return -EINVAL;
567 	}
568 }
569 
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)570 static int oxp_psy_ext_set_prop(struct power_supply *psy,
571 				const struct power_supply_ext *ext,
572 				void *data,
573 				enum power_supply_property psp,
574 				const union power_supply_propval *val)
575 {
576 	long raw_val;
577 
578 	switch (psp) {
579 	case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
580 		if (val->intval < 0 || val->intval > 100)
581 			return -EINVAL;
582 		return write_to_ec(OXP_X1_CHARGE_LIMIT_REG, val->intval);
583 	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
584 		switch (val->intval) {
585 		case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
586 			raw_val = 0;
587 			break;
588 		case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE:
589 			raw_val = OXP_X1_CHARGE_INHIBIT_MASK_AWAKE;
590 			break;
591 		case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
592 			raw_val = OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS;
593 			break;
594 		default:
595 			return -EINVAL;
596 		}
597 
598 		return write_to_ec(OXP_X1_CHARGE_INHIBIT_REG, raw_val);
599 	default:
600 		return -EINVAL;
601 	}
602 }
603 
oxp_psy_prop_is_writeable(struct power_supply * psy,const struct power_supply_ext * ext,void * data,enum power_supply_property psp)604 static int oxp_psy_prop_is_writeable(struct power_supply *psy,
605 				     const struct power_supply_ext *ext,
606 				     void *data,
607 				     enum power_supply_property psp)
608 {
609 	return true;
610 }
611 
612 static const enum power_supply_property oxp_psy_ext_props[] = {
613 	POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
614 	POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
615 };
616 
617 static const struct power_supply_ext oxp_psy_ext = {
618 	.name			= "oxp-charge-control",
619 	.properties		= oxp_psy_ext_props,
620 	.num_properties		= ARRAY_SIZE(oxp_psy_ext_props),
621 	.charge_behaviours	= EC_CHARGE_CONTROL_BEHAVIOURS,
622 	.get_property		= oxp_psy_ext_get_prop,
623 	.set_property		= oxp_psy_ext_set_prop,
624 	.property_is_writeable	= oxp_psy_prop_is_writeable,
625 };
626 
oxp_add_battery(struct power_supply * battery,struct acpi_battery_hook * hook)627 static int oxp_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
628 {
629 	return power_supply_register_extension(battery, &oxp_psy_ext, oxp_dev, NULL);
630 }
631 
oxp_remove_battery(struct power_supply * battery,struct acpi_battery_hook * hook)632 static int oxp_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
633 {
634 	power_supply_unregister_extension(battery, &oxp_psy_ext);
635 	return 0;
636 }
637 
638 static struct acpi_battery_hook battery_hook = {
639 	.add_battery	= oxp_add_battery,
640 	.remove_battery	= oxp_remove_battery,
641 	.name		= "OneXPlayer Battery",
642 };
643 
644 /* PWM enable/disable functions */
oxp_pwm_enable(void)645 static int oxp_pwm_enable(void)
646 {
647 	switch (board) {
648 	case orange_pi_neo:
649 		return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
650 	case aok_zoe_a1:
651 	case oxp_2:
652 	case oxp_fly:
653 	case oxp_mini_amd:
654 	case oxp_mini_amd_a07:
655 	case oxp_mini_amd_pro:
656 	case oxp_x1:
657 	case oxp_g1_i:
658 	case oxp_g1_a:
659 		return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
660 	default:
661 		return -EINVAL;
662 	}
663 }
664 
oxp_pwm_disable(void)665 static int oxp_pwm_disable(void)
666 {
667 	switch (board) {
668 	case orange_pi_neo:
669 		return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
670 	case aok_zoe_a1:
671 	case oxp_2:
672 	case oxp_fly:
673 	case oxp_mini_amd:
674 	case oxp_mini_amd_a07:
675 	case oxp_mini_amd_pro:
676 	case oxp_x1:
677 	case oxp_g1_i:
678 	case oxp_g1_a:
679 		return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
680 	default:
681 		return -EINVAL;
682 	}
683 }
684 
oxp_pwm_read(long * val)685 static int oxp_pwm_read(long *val)
686 {
687 	switch (board) {
688 	case orange_pi_neo:
689 		return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val);
690 	case aok_zoe_a1:
691 	case oxp_2:
692 	case oxp_fly:
693 	case oxp_mini_amd:
694 	case oxp_mini_amd_a07:
695 	case oxp_mini_amd_pro:
696 	case oxp_x1:
697 	case oxp_g1_i:
698 	case oxp_g1_a:
699 		return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
700 	default:
701 		return -EOPNOTSUPP;
702 	}
703 }
704 
705 /* Callbacks for hwmon interface */
oxp_ec_hwmon_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)706 static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
707 				       enum hwmon_sensor_types type, u32 attr, int channel)
708 {
709 	switch (type) {
710 	case hwmon_fan:
711 		return 0444;
712 	case hwmon_pwm:
713 		return 0644;
714 	default:
715 		return 0;
716 	}
717 }
718 
719 /* Fan speed read function */
oxp_pwm_fan_speed(long * val)720 static int oxp_pwm_fan_speed(long *val)
721 {
722 	switch (board) {
723 	case orange_pi_neo:
724 		return read_from_ec(ORANGEPI_SENSOR_FAN_REG, 2, val);
725 	case oxp_2:
726 	case oxp_x1:
727 	case oxp_g1_i:
728 		return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val);
729 	case aok_zoe_a1:
730 	case oxp_fly:
731 	case oxp_mini_amd:
732 	case oxp_mini_amd_a07:
733 	case oxp_mini_amd_pro:
734 	case oxp_g1_a:
735 		return read_from_ec(OXP_SENSOR_FAN_REG, 2, val);
736 	default:
737 		return -EOPNOTSUPP;
738 	}
739 }
740 
741 /* PWM input read/write functions */
oxp_pwm_input_write(long val)742 static int oxp_pwm_input_write(long val)
743 {
744 	if (val < 0 || val > 255)
745 		return -EINVAL;
746 
747 	switch (board) {
748 	case orange_pi_neo:
749 		/* scale to range [1-244] */
750 		val = ((val - 1) * 243 / 254) + 1;
751 		return write_to_ec(ORANGEPI_SENSOR_PWM_REG, val);
752 	case oxp_2:
753 	case oxp_x1:
754 	case oxp_g1_i:
755 		/* scale to range [0-184] */
756 		val = (val * 184) / 255;
757 		return write_to_ec(OXP_SENSOR_PWM_REG, val);
758 	case oxp_mini_amd:
759 	case oxp_mini_amd_a07:
760 		/* scale to range [0-100] */
761 		val = (val * 100) / 255;
762 		return write_to_ec(OXP_SENSOR_PWM_REG, val);
763 	case aok_zoe_a1:
764 	case oxp_fly:
765 	case oxp_mini_amd_pro:
766 	case oxp_g1_a:
767 		return write_to_ec(OXP_SENSOR_PWM_REG, val);
768 	default:
769 		return -EOPNOTSUPP;
770 	}
771 }
772 
oxp_pwm_input_read(long * val)773 static int oxp_pwm_input_read(long *val)
774 {
775 	int ret;
776 
777 	switch (board) {
778 	case orange_pi_neo:
779 		ret = read_from_ec(ORANGEPI_SENSOR_PWM_REG, 1, val);
780 		if (ret)
781 			return ret;
782 		/* scale from range [1-244] */
783 		*val = ((*val - 1) * 254 / 243) + 1;
784 		break;
785 	case oxp_2:
786 	case oxp_x1:
787 	case oxp_g1_i:
788 		ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
789 		if (ret)
790 			return ret;
791 		/* scale from range [0-184] */
792 		*val = (*val * 255) / 184;
793 		break;
794 	case oxp_mini_amd:
795 	case oxp_mini_amd_a07:
796 		ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
797 		if (ret)
798 			return ret;
799 		/* scale from range [0-100] */
800 		*val = (*val * 255) / 100;
801 		break;
802 	case aok_zoe_a1:
803 	case oxp_fly:
804 	case oxp_mini_amd_pro:
805 	case oxp_g1_a:
806 	default:
807 		ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
808 		if (ret)
809 			return ret;
810 		break;
811 	}
812 	return 0;
813 }
814 
oxp_platform_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)815 static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
816 			     u32 attr, int channel, long *val)
817 {
818 	int ret;
819 
820 	switch (type) {
821 	case hwmon_fan:
822 		switch (attr) {
823 		case hwmon_fan_input:
824 			return oxp_pwm_fan_speed(val);
825 		default:
826 			break;
827 		}
828 		break;
829 	case hwmon_pwm:
830 		switch (attr) {
831 		case hwmon_pwm_input:
832 			return oxp_pwm_input_read(val);
833 		case hwmon_pwm_enable:
834 			ret = oxp_pwm_read(val);
835 			if (ret)
836 				return ret;
837 
838 			/* Check for auto and return 2 */
839 			if (!*val) {
840 				*val = 2;
841 				return 0;
842 			}
843 
844 			/* Return 0 if at full fan speed, 1 otherwise */
845 			ret = oxp_pwm_fan_speed(val);
846 			if (ret)
847 				return ret;
848 
849 			if (*val == 255)
850 				*val = 0;
851 			else
852 				*val = 1;
853 
854 			return 0;
855 		default:
856 			break;
857 		}
858 		break;
859 	default:
860 		break;
861 	}
862 	return -EOPNOTSUPP;
863 }
864 
oxp_platform_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)865 static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
866 			      u32 attr, int channel, long val)
867 {
868 	int ret;
869 
870 	switch (type) {
871 	case hwmon_pwm:
872 		switch (attr) {
873 		case hwmon_pwm_enable:
874 			if (val == 1)
875 				return oxp_pwm_enable();
876 			else if (val == 2)
877 				return oxp_pwm_disable();
878 			else if (val != 0)
879 				return -EINVAL;
880 
881 			/* Enable PWM and set to max speed */
882 			ret = oxp_pwm_enable();
883 			if (ret)
884 				return ret;
885 			return oxp_pwm_input_write(255);
886 		case hwmon_pwm_input:
887 			return oxp_pwm_input_write(val);
888 		default:
889 			break;
890 		}
891 		break;
892 	default:
893 		break;
894 	}
895 	return -EOPNOTSUPP;
896 }
897 
898 /* Known sensors in the OXP EC controllers */
899 static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
900 	HWMON_CHANNEL_INFO(fan,
901 			   HWMON_F_INPUT),
902 	HWMON_CHANNEL_INFO(pwm,
903 			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
904 	NULL,
905 };
906 
907 static struct attribute *oxp_tt_toggle_attrs[] = {
908 	&dev_attr_tt_toggle.attr,
909 	NULL
910 };
911 
912 static const struct attribute_group oxp_tt_toggle_attribute_group = {
913 	.is_visible = tt_toggle_is_visible,
914 	.attrs = oxp_tt_toggle_attrs,
915 };
916 
917 static struct attribute *oxp_tt_led_attrs[] = {
918 	&dev_attr_tt_led.attr,
919 	NULL
920 };
921 
922 static const struct attribute_group oxp_tt_led_attribute_group = {
923 	.is_visible = tt_led_is_visible,
924 	.attrs = oxp_tt_led_attrs,
925 };
926 
927 static const struct attribute_group *oxp_ec_groups[] = {
928 	&oxp_tt_toggle_attribute_group,
929 	&oxp_tt_led_attribute_group,
930 	NULL
931 };
932 
933 static const struct hwmon_ops oxp_ec_hwmon_ops = {
934 	.is_visible = oxp_ec_hwmon_is_visible,
935 	.read = oxp_platform_read,
936 	.write = oxp_platform_write,
937 };
938 
939 static const struct hwmon_chip_info oxp_ec_chip_info = {
940 	.ops = &oxp_ec_hwmon_ops,
941 	.info = oxp_platform_sensors,
942 };
943 
944 /* Initialization logic */
oxp_platform_probe(struct platform_device * pdev)945 static int oxp_platform_probe(struct platform_device *pdev)
946 {
947 	struct device *dev = &pdev->dev;
948 	struct device *hwdev;
949 	int ret;
950 
951 	oxp_dev = dev;
952 	hwdev = devm_hwmon_device_register_with_info(dev, "oxp_ec", NULL,
953 						     &oxp_ec_chip_info, NULL);
954 
955 	if (IS_ERR(hwdev))
956 		return PTR_ERR(hwdev);
957 
958 	if (oxp_psy_ext_supported()) {
959 		ret = devm_battery_hook_register(dev, &battery_hook);
960 		if (ret)
961 			return ret;
962 	}
963 
964 	return 0;
965 }
966 
967 static struct platform_driver oxp_platform_driver = {
968 	.driver = {
969 		.name = "oxp-platform",
970 		.dev_groups = oxp_ec_groups,
971 	},
972 	.probe = oxp_platform_probe,
973 };
974 
975 static struct platform_device *oxp_platform_device;
976 
oxp_platform_init(void)977 static int __init oxp_platform_init(void)
978 {
979 	const struct dmi_system_id *dmi_entry;
980 
981 	dmi_entry = dmi_first_match(dmi_table);
982 	if (!dmi_entry)
983 		return -ENODEV;
984 
985 	board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
986 
987 	/*
988 	 * Have to check for AMD processor here because DMI strings are the same
989 	 * between Intel and AMD boards on older OneXPlayer devices, the only way
990 	 * to tell them apart is the CPU. Old Intel boards have an unsupported EC.
991 	 */
992 	if (board == oxp_mini_amd && boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
993 		return -ENODEV;
994 
995 	oxp_platform_device =
996 		platform_create_bundle(&oxp_platform_driver,
997 				       oxp_platform_probe, NULL, 0, NULL, 0);
998 
999 	return PTR_ERR_OR_ZERO(oxp_platform_device);
1000 }
1001 
oxp_platform_exit(void)1002 static void __exit oxp_platform_exit(void)
1003 {
1004 	platform_device_unregister(oxp_platform_device);
1005 	platform_driver_unregister(&oxp_platform_driver);
1006 }
1007 
1008 MODULE_DEVICE_TABLE(dmi, dmi_table);
1009 
1010 module_init(oxp_platform_init);
1011 module_exit(oxp_platform_exit);
1012 
1013 MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>");
1014 MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices");
1015 MODULE_LICENSE("GPL");
1016