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