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