oxp-sensors.c (db6da59cf27b5661ced03754ae0550f8914eda9e) oxp-sensors.c (be144ee49127216b456da26f1a32b6ba281ac505)
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Platform driver for OneXPlayer, AOK ZOE, and Aya Neo Handhelds that expose
4 * fan reading and control via hwmon sysfs.
5 *
6 * Old OXP boards have the same DMI strings and they are told apart by
7 * the boot cpu vendor (Intel/AMD). Currently only AMD boards are
8 * supported but the code is made to be simple to add other handheld

--- 28 unchanged lines hidden (view full) ---

37
38static bool unlock_global_acpi_lock(void)
39{
40 return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex));
41}
42
43enum oxp_board {
44 aok_zoe_a1 = 1,
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Platform driver for OneXPlayer, AOK ZOE, and Aya Neo Handhelds that expose
4 * fan reading and control via hwmon sysfs.
5 *
6 * Old OXP boards have the same DMI strings and they are told apart by
7 * the boot cpu vendor (Intel/AMD). Currently only AMD boards are
8 * supported but the code is made to be simple to add other handheld

--- 28 unchanged lines hidden (view full) ---

37
38static bool unlock_global_acpi_lock(void)
39{
40 return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex));
41}
42
43enum oxp_board {
44 aok_zoe_a1 = 1,
45 aya_neo_2,
45 aya_neo_air,
46 aya_neo_air_pro,
46 aya_neo_air,
47 aya_neo_air_pro,
48 aya_neo_geek,
47 oxp_mini_amd,
49 oxp_mini_amd,
50 oxp_mini_amd_a07,
48 oxp_mini_amd_pro,
49};
50
51static enum oxp_board board;
52
51 oxp_mini_amd_pro,
52};
53
54static enum oxp_board board;
55
56/* Fan reading and PWM */
53#define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */
54#define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */
55#define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */
56
57#define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */
58#define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */
59#define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */
60
61/* Turbo button takeover function
62 * Older boards have different values and EC registers
63 * for the same function
64 */
65#define OXP_OLD_TURBO_SWITCH_REG 0x1E
66#define OXP_OLD_TURBO_TAKE_VAL 0x01
67#define OXP_OLD_TURBO_RETURN_VAL 0x00
68
69#define OXP_TURBO_SWITCH_REG 0xF1
70#define OXP_TURBO_TAKE_VAL 0x40
71#define OXP_TURBO_RETURN_VAL 0x00
72
57static const struct dmi_system_id dmi_table[] = {
58 {
59 .matches = {
60 DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
61 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"),
62 },
73static const struct dmi_system_id dmi_table[] = {
74 {
75 .matches = {
76 DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
77 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"),
78 },
63 .driver_data = (void *) &(enum oxp_board) {aok_zoe_a1},
79 .driver_data = (void *)aok_zoe_a1,
64 },
65 {
66 .matches = {
67 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
80 },
81 {
82 .matches = {
83 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
84 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
85 },
86 .driver_data = (void *)aya_neo_2,
87 },
88 {
89 .matches = {
90 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
68 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
69 },
91 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
92 },
70 .driver_data = (void *) &(enum oxp_board) {aya_neo_air},
93 .driver_data = (void *)aya_neo_air,
71 },
72 {
73 .matches = {
74 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
75 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
76 },
94 },
95 {
96 .matches = {
97 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
98 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
99 },
77 .driver_data = (void *) &(enum oxp_board) {aya_neo_air_pro},
100 .driver_data = (void *)aya_neo_air_pro,
78 },
79 {
80 .matches = {
101 },
102 {
103 .matches = {
104 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
105 DMI_EXACT_MATCH(DMI_BOARD_NAME, "GEEK"),
106 },
107 .driver_data = (void *)aya_neo_geek,
108 },
109 {
110 .matches = {
81 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
82 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
83 },
111 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
112 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
113 },
84 .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd},
114 .driver_data = (void *)oxp_mini_amd,
85 },
86 {
87 .matches = {
88 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
115 },
116 {
117 .matches = {
118 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
119 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"),
120 },
121 .driver_data = (void *)oxp_mini_amd_a07,
122 },
123 {
124 .matches = {
125 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
89 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
90 },
126 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
127 },
91 .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd_pro},
128 .driver_data = (void *)oxp_mini_amd_pro,
92 },
93 {},
94};
95
96/* Helper functions to handle EC read/write */
97static int read_from_ec(u8 reg, int size, long *val)
98{
99 int i;

--- 13 unchanged lines hidden (view full) ---

113 }
114
115 if (!unlock_global_acpi_lock())
116 return -EBUSY;
117
118 return 0;
119}
120
129 },
130 {},
131};
132
133/* Helper functions to handle EC read/write */
134static int read_from_ec(u8 reg, int size, long *val)
135{
136 int i;

--- 13 unchanged lines hidden (view full) ---

150 }
151
152 if (!unlock_global_acpi_lock())
153 return -EBUSY;
154
155 return 0;
156}
157
121static int write_to_ec(const struct device *dev, u8 reg, u8 value)
158static int write_to_ec(u8 reg, u8 value)
122{
123 int ret;
124
125 if (!lock_global_acpi_lock())
126 return -EBUSY;
127
128 ret = ec_write(reg, value);
129
130 if (!unlock_global_acpi_lock())
131 return -EBUSY;
132
133 return ret;
134}
135
159{
160 int ret;
161
162 if (!lock_global_acpi_lock())
163 return -EBUSY;
164
165 ret = ec_write(reg, value);
166
167 if (!unlock_global_acpi_lock())
168 return -EBUSY;
169
170 return ret;
171}
172
136static int oxp_pwm_enable(const struct device *dev)
173/* Turbo button toggle functions */
174static int tt_toggle_enable(void)
137{
175{
138 return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x01);
176 u8 reg;
177 u8 val;
178
179 switch (board) {
180 case oxp_mini_amd_a07:
181 reg = OXP_OLD_TURBO_SWITCH_REG;
182 val = OXP_OLD_TURBO_TAKE_VAL;
183 break;
184 case oxp_mini_amd_pro:
185 case aok_zoe_a1:
186 reg = OXP_TURBO_SWITCH_REG;
187 val = OXP_TURBO_TAKE_VAL;
188 break;
189 default:
190 return -EINVAL;
191 }
192 return write_to_ec(reg, val);
139}
140
193}
194
141static int oxp_pwm_disable(const struct device *dev)
195static int tt_toggle_disable(void)
142{
196{
143 return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x00);
197 u8 reg;
198 u8 val;
199
200 switch (board) {
201 case oxp_mini_amd_a07:
202 reg = OXP_OLD_TURBO_SWITCH_REG;
203 val = OXP_OLD_TURBO_RETURN_VAL;
204 break;
205 case oxp_mini_amd_pro:
206 case aok_zoe_a1:
207 reg = OXP_TURBO_SWITCH_REG;
208 val = OXP_TURBO_RETURN_VAL;
209 break;
210 default:
211 return -EINVAL;
212 }
213 return write_to_ec(reg, val);
144}
145
214}
215
216/* Callbacks for turbo toggle attribute */
217static ssize_t tt_toggle_store(struct device *dev,
218 struct device_attribute *attr, const char *buf,
219 size_t count)
220{
221 int rval;
222 bool value;
223
224 rval = kstrtobool(buf, &value);
225 if (rval)
226 return rval;
227
228 if (value) {
229 rval = tt_toggle_enable();
230 if (rval)
231 return rval;
232 } else {
233 rval = tt_toggle_disable();
234 if (rval)
235 return rval;
236 }
237 return count;
238}
239
240static ssize_t tt_toggle_show(struct device *dev,
241 struct device_attribute *attr, char *buf)
242{
243 int retval;
244 u8 reg;
245 long val;
246
247 switch (board) {
248 case oxp_mini_amd_a07:
249 reg = OXP_OLD_TURBO_SWITCH_REG;
250 break;
251 case oxp_mini_amd_pro:
252 case aok_zoe_a1:
253 reg = OXP_TURBO_SWITCH_REG;
254 break;
255 default:
256 return -EINVAL;
257 }
258
259 retval = read_from_ec(reg, 1, &val);
260 if (retval)
261 return retval;
262
263 return sysfs_emit(buf, "%d\n", !!val);
264}
265
266static DEVICE_ATTR_RW(tt_toggle);
267
268/* PWM enable/disable functions */
269static int oxp_pwm_enable(void)
270{
271 return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x01);
272}
273
274static int oxp_pwm_disable(void)
275{
276 return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x00);
277}
278
146/* Callbacks for hwmon interface */
147static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
148 enum hwmon_sensor_types type, u32 attr, int channel)
149{
150 switch (type) {
151 case hwmon_fan:
152 return 0444;
153 case hwmon_pwm:

--- 19 unchanged lines hidden (view full) ---

173 break;
174 case hwmon_pwm:
175 switch (attr) {
176 case hwmon_pwm_input:
177 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
178 if (ret)
179 return ret;
180 switch (board) {
279/* Callbacks for hwmon interface */
280static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
281 enum hwmon_sensor_types type, u32 attr, int channel)
282{
283 switch (type) {
284 case hwmon_fan:
285 return 0444;
286 case hwmon_pwm:

--- 19 unchanged lines hidden (view full) ---

306 break;
307 case hwmon_pwm:
308 switch (attr) {
309 case hwmon_pwm_input:
310 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
311 if (ret)
312 return ret;
313 switch (board) {
314 case aya_neo_2:
181 case aya_neo_air:
182 case aya_neo_air_pro:
315 case aya_neo_air:
316 case aya_neo_air_pro:
317 case aya_neo_geek:
183 case oxp_mini_amd:
318 case oxp_mini_amd:
319 case oxp_mini_amd_a07:
184 *val = (*val * 255) / 100;
185 break;
186 case oxp_mini_amd_pro:
187 case aok_zoe_a1:
188 default:
189 break;
190 }
191 return 0;

--- 12 unchanged lines hidden (view full) ---

204static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
205 u32 attr, int channel, long val)
206{
207 switch (type) {
208 case hwmon_pwm:
209 switch (attr) {
210 case hwmon_pwm_enable:
211 if (val == 1)
320 *val = (*val * 255) / 100;
321 break;
322 case oxp_mini_amd_pro:
323 case aok_zoe_a1:
324 default:
325 break;
326 }
327 return 0;

--- 12 unchanged lines hidden (view full) ---

340static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
341 u32 attr, int channel, long val)
342{
343 switch (type) {
344 case hwmon_pwm:
345 switch (attr) {
346 case hwmon_pwm_enable:
347 if (val == 1)
212 return oxp_pwm_enable(dev);
348 return oxp_pwm_enable();
213 else if (val == 0)
349 else if (val == 0)
214 return oxp_pwm_disable(dev);
350 return oxp_pwm_disable();
215 return -EINVAL;
216 case hwmon_pwm_input:
217 if (val < 0 || val > 255)
218 return -EINVAL;
219 switch (board) {
351 return -EINVAL;
352 case hwmon_pwm_input:
353 if (val < 0 || val > 255)
354 return -EINVAL;
355 switch (board) {
356 case aya_neo_2:
220 case aya_neo_air:
221 case aya_neo_air_pro:
357 case aya_neo_air:
358 case aya_neo_air_pro:
359 case aya_neo_geek:
222 case oxp_mini_amd:
360 case oxp_mini_amd:
361 case oxp_mini_amd_a07:
223 val = (val * 100) / 255;
224 break;
225 case aok_zoe_a1:
226 case oxp_mini_amd_pro:
227 default:
228 break;
229 }
362 val = (val * 100) / 255;
363 break;
364 case aok_zoe_a1:
365 case oxp_mini_amd_pro:
366 default:
367 break;
368 }
230 return write_to_ec(dev, OXP_SENSOR_PWM_REG, val);
369 return write_to_ec(OXP_SENSOR_PWM_REG, val);
231 default:
232 break;
233 }
234 break;
235 default:
236 break;
237 }
238 return -EOPNOTSUPP;
239}
240
241/* Known sensors in the OXP EC controllers */
242static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
243 HWMON_CHANNEL_INFO(fan,
244 HWMON_F_INPUT),
245 HWMON_CHANNEL_INFO(pwm,
246 HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
247 NULL,
248};
249
370 default:
371 break;
372 }
373 break;
374 default:
375 break;
376 }
377 return -EOPNOTSUPP;
378}
379
380/* Known sensors in the OXP EC controllers */
381static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
382 HWMON_CHANNEL_INFO(fan,
383 HWMON_F_INPUT),
384 HWMON_CHANNEL_INFO(pwm,
385 HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
386 NULL,
387};
388
389static struct attribute *oxp_ec_attrs[] = {
390 &dev_attr_tt_toggle.attr,
391 NULL
392};
393
394ATTRIBUTE_GROUPS(oxp_ec);
395
250static const struct hwmon_ops oxp_ec_hwmon_ops = {
251 .is_visible = oxp_ec_hwmon_is_visible,
252 .read = oxp_platform_read,
253 .write = oxp_platform_write,
254};
255
256static const struct hwmon_chip_info oxp_ec_chip_info = {
257 .ops = &oxp_ec_hwmon_ops,
258 .info = oxp_platform_sensors,
259};
260
261/* Initialization logic */
262static int oxp_platform_probe(struct platform_device *pdev)
263{
264 const struct dmi_system_id *dmi_entry;
265 struct device *dev = &pdev->dev;
266 struct device *hwdev;
396static const struct hwmon_ops oxp_ec_hwmon_ops = {
397 .is_visible = oxp_ec_hwmon_is_visible,
398 .read = oxp_platform_read,
399 .write = oxp_platform_write,
400};
401
402static const struct hwmon_chip_info oxp_ec_chip_info = {
403 .ops = &oxp_ec_hwmon_ops,
404 .info = oxp_platform_sensors,
405};
406
407/* Initialization logic */
408static int oxp_platform_probe(struct platform_device *pdev)
409{
410 const struct dmi_system_id *dmi_entry;
411 struct device *dev = &pdev->dev;
412 struct device *hwdev;
413 int ret;
267
268 /*
269 * Have to check for AMD processor here because DMI strings are the
270 * same between Intel and AMD boards, the only way to tell them apart
271 * is the CPU.
272 * Intel boards seem to have different EC registers and values to
273 * read/write.
274 */
275 dmi_entry = dmi_first_match(dmi_table);
276 if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
277 return -ENODEV;
278
414
415 /*
416 * Have to check for AMD processor here because DMI strings are the
417 * same between Intel and AMD boards, the only way to tell them apart
418 * is the CPU.
419 * Intel boards seem to have different EC registers and values to
420 * read/write.
421 */
422 dmi_entry = dmi_first_match(dmi_table);
423 if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
424 return -ENODEV;
425
279 board = *((enum oxp_board *) dmi_entry->driver_data);
426 board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
280
427
428 switch (board) {
429 case aok_zoe_a1:
430 case oxp_mini_amd_a07:
431 case oxp_mini_amd_pro:
432 ret = devm_device_add_groups(dev, oxp_ec_groups);
433 if (ret)
434 return ret;
435 break;
436 default:
437 break;
438 }
439
281 hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
282 &oxp_ec_chip_info, NULL);
283
284 return PTR_ERR_OR_ZERO(hwdev);
285}
286
287static struct platform_driver oxp_platform_driver = {
288 .driver = {

--- 30 unchanged lines hidden ---
440 hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
441 &oxp_ec_chip_info, NULL);
442
443 return PTR_ERR_OR_ZERO(hwdev);
444}
445
446static struct platform_driver oxp_platform_driver = {
447 .driver = {

--- 30 unchanged lines hidden ---