xref: /openbmc/linux/drivers/hwmon/oxp-sensors.c (revision 7590e659e063dc45a5743bb4e5eb4a21ee1fd651)
1ed264e8aSJoaquín Ignacio Aramendía // SPDX-License-Identifier: GPL-2.0+
2ed264e8aSJoaquín Ignacio Aramendía /*
3ebd4bfeeSDerek J. Clark  * Platform driver for OneXPlayer, AOK ZOE, and Aya Neo Handhelds that expose
4ebd4bfeeSDerek J. Clark  * fan reading and control via hwmon sysfs.
5ed264e8aSJoaquín Ignacio Aramendía  *
6ebd4bfeeSDerek J. Clark  * Old OXP boards have the same DMI strings and they are told apart by
7ebd4bfeeSDerek J. Clark  * the boot cpu vendor (Intel/AMD). Currently only AMD boards are
8ebd4bfeeSDerek J. Clark  * supported but the code is made to be simple to add other handheld
9ebd4bfeeSDerek J. Clark  * boards in the future.
103ca0f12aSJoaquín Ignacio Aramendía  * Fan control is provided via pwm interface in the range [0-255].
113ca0f12aSJoaquín Ignacio Aramendía  * Old AMD boards use [0-100] as range in the EC, the written value is
123ca0f12aSJoaquín Ignacio Aramendía  * scaled to accommodate for that. Newer boards like the mini PRO and
133ca0f12aSJoaquín Ignacio Aramendía  * AOK ZOE are not scaled but have the same EC layout.
14ed264e8aSJoaquín Ignacio Aramendía  *
15ed264e8aSJoaquín Ignacio Aramendía  * Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com>
16ed264e8aSJoaquín Ignacio Aramendía  */
17ed264e8aSJoaquín Ignacio Aramendía 
18ed264e8aSJoaquín Ignacio Aramendía #include <linux/acpi.h>
19ed264e8aSJoaquín Ignacio Aramendía #include <linux/dev_printk.h>
20ed264e8aSJoaquín Ignacio Aramendía #include <linux/dmi.h>
21ed264e8aSJoaquín Ignacio Aramendía #include <linux/hwmon.h>
22ed264e8aSJoaquín Ignacio Aramendía #include <linux/init.h>
23ed264e8aSJoaquín Ignacio Aramendía #include <linux/kernel.h>
24ed264e8aSJoaquín Ignacio Aramendía #include <linux/module.h>
25ed264e8aSJoaquín Ignacio Aramendía #include <linux/platform_device.h>
26ed264e8aSJoaquín Ignacio Aramendía #include <linux/processor.h>
27ed264e8aSJoaquín Ignacio Aramendía 
28ed264e8aSJoaquín Ignacio Aramendía /* Handle ACPI lock mechanism */
29ed264e8aSJoaquín Ignacio Aramendía static u32 oxp_mutex;
30ed264e8aSJoaquín Ignacio Aramendía 
31ed264e8aSJoaquín Ignacio Aramendía #define ACPI_LOCK_DELAY_MS	500
32ed264e8aSJoaquín Ignacio Aramendía 
33ed264e8aSJoaquín Ignacio Aramendía static bool lock_global_acpi_lock(void)
34ed264e8aSJoaquín Ignacio Aramendía {
35ed264e8aSJoaquín Ignacio Aramendía 	return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex));
36ed264e8aSJoaquín Ignacio Aramendía }
37ed264e8aSJoaquín Ignacio Aramendía 
38ed264e8aSJoaquín Ignacio Aramendía static bool unlock_global_acpi_lock(void)
39ed264e8aSJoaquín Ignacio Aramendía {
40ed264e8aSJoaquín Ignacio Aramendía 	return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex));
41ed264e8aSJoaquín Ignacio Aramendía }
42ed264e8aSJoaquín Ignacio Aramendía 
433ca0f12aSJoaquín Ignacio Aramendía enum oxp_board {
443ca0f12aSJoaquín Ignacio Aramendía 	aok_zoe_a1 = 1,
45f415cb6cSJoaquín Ignacio Aramendía 	aya_neo_2,
46ebd4bfeeSDerek J. Clark 	aya_neo_air,
47ebd4bfeeSDerek J. Clark 	aya_neo_air_pro,
48f415cb6cSJoaquín Ignacio Aramendía 	aya_neo_geek,
493ca0f12aSJoaquín Ignacio Aramendía 	oxp_mini_amd,
503ca0f12aSJoaquín Ignacio Aramendía 	oxp_mini_amd_pro,
513ca0f12aSJoaquín Ignacio Aramendía };
523ca0f12aSJoaquín Ignacio Aramendía 
533ca0f12aSJoaquín Ignacio Aramendía static enum oxp_board board;
543ca0f12aSJoaquín Ignacio Aramendía 
55ed264e8aSJoaquín Ignacio Aramendía #define OXP_SENSOR_FAN_REG		0x76 /* Fan reading is 2 registers long */
56ed264e8aSJoaquín Ignacio Aramendía #define OXP_SENSOR_PWM_ENABLE_REG	0x4A /* PWM enable is 1 register long */
57ed264e8aSJoaquín Ignacio Aramendía #define OXP_SENSOR_PWM_REG		0x4B /* PWM reading is 1 register long */
58ed264e8aSJoaquín Ignacio Aramendía 
59ed264e8aSJoaquín Ignacio Aramendía static const struct dmi_system_id dmi_table[] = {
60ed264e8aSJoaquín Ignacio Aramendía 	{
61ed264e8aSJoaquín Ignacio Aramendía 		.matches = {
623ca0f12aSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
633ca0f12aSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"),
643ca0f12aSJoaquín Ignacio Aramendía 		},
655d06ec42SJoaquín Ignacio Aramendía 		.driver_data = (void *)aok_zoe_a1,
663ca0f12aSJoaquín Ignacio Aramendía 	},
673ca0f12aSJoaquín Ignacio Aramendía 	{
683ca0f12aSJoaquín Ignacio Aramendía 		.matches = {
69ebd4bfeeSDerek J. Clark 			DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
70f415cb6cSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
71f415cb6cSJoaquín Ignacio Aramendía 		},
725d06ec42SJoaquín Ignacio Aramendía 		.driver_data = (void *)aya_neo_2,
73f415cb6cSJoaquín Ignacio Aramendía 	},
74f415cb6cSJoaquín Ignacio Aramendía 	{
75f415cb6cSJoaquín Ignacio Aramendía 		.matches = {
76f415cb6cSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
77ebd4bfeeSDerek J. Clark 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
78ebd4bfeeSDerek J. Clark 		},
795d06ec42SJoaquín Ignacio Aramendía 		.driver_data = (void *)aya_neo_air,
80ebd4bfeeSDerek J. Clark 	},
81ebd4bfeeSDerek J. Clark 	{
82ebd4bfeeSDerek J. Clark 		.matches = {
83ebd4bfeeSDerek J. Clark 			DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
84ebd4bfeeSDerek J. Clark 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
85ebd4bfeeSDerek J. Clark 		},
865d06ec42SJoaquín Ignacio Aramendía 		.driver_data = (void *)aya_neo_air_pro,
87ebd4bfeeSDerek J. Clark 	},
88ebd4bfeeSDerek J. Clark 	{
89ebd4bfeeSDerek J. Clark 		.matches = {
90f415cb6cSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
91f415cb6cSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GEEK"),
92f415cb6cSJoaquín Ignacio Aramendía 		},
935d06ec42SJoaquín Ignacio Aramendía 		.driver_data = (void *)aya_neo_geek,
94f415cb6cSJoaquín Ignacio Aramendía 	},
95f415cb6cSJoaquín Ignacio Aramendía 	{
96f415cb6cSJoaquín Ignacio Aramendía 		.matches = {
97ed264e8aSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
98ed264e8aSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
99ed264e8aSJoaquín Ignacio Aramendía 		},
1005d06ec42SJoaquín Ignacio Aramendía 		.driver_data = (void *)oxp_mini_amd,
1013ca0f12aSJoaquín Ignacio Aramendía 	},
1023ca0f12aSJoaquín Ignacio Aramendía 	{
1033ca0f12aSJoaquín Ignacio Aramendía 		.matches = {
1043ca0f12aSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
1057d0c2c61SJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"),
1067d0c2c61SJoaquín Ignacio Aramendía 		},
1077d0c2c61SJoaquín Ignacio Aramendía 		.driver_data = (void *)oxp_mini_amd,
1087d0c2c61SJoaquín Ignacio Aramendía 	},
1097d0c2c61SJoaquín Ignacio Aramendía 	{
1107d0c2c61SJoaquín Ignacio Aramendía 		.matches = {
1117d0c2c61SJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
1123ca0f12aSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
1133ca0f12aSJoaquín Ignacio Aramendía 		},
1145d06ec42SJoaquín Ignacio Aramendía 		.driver_data = (void *)oxp_mini_amd_pro,
115ed264e8aSJoaquín Ignacio Aramendía 	},
116ed264e8aSJoaquín Ignacio Aramendía 	{},
117ed264e8aSJoaquín Ignacio Aramendía };
118ed264e8aSJoaquín Ignacio Aramendía 
119ed264e8aSJoaquín Ignacio Aramendía /* Helper functions to handle EC read/write */
120ed264e8aSJoaquín Ignacio Aramendía static int read_from_ec(u8 reg, int size, long *val)
121ed264e8aSJoaquín Ignacio Aramendía {
122ed264e8aSJoaquín Ignacio Aramendía 	int i;
123ed264e8aSJoaquín Ignacio Aramendía 	int ret;
124ed264e8aSJoaquín Ignacio Aramendía 	u8 buffer;
125ed264e8aSJoaquín Ignacio Aramendía 
126ed264e8aSJoaquín Ignacio Aramendía 	if (!lock_global_acpi_lock())
127ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
128ed264e8aSJoaquín Ignacio Aramendía 
129ed264e8aSJoaquín Ignacio Aramendía 	*val = 0;
130ed264e8aSJoaquín Ignacio Aramendía 	for (i = 0; i < size; i++) {
131ed264e8aSJoaquín Ignacio Aramendía 		ret = ec_read(reg + i, &buffer);
132ed264e8aSJoaquín Ignacio Aramendía 		if (ret)
133ed264e8aSJoaquín Ignacio Aramendía 			return ret;
134ed264e8aSJoaquín Ignacio Aramendía 		*val <<= i * 8;
135ed264e8aSJoaquín Ignacio Aramendía 		*val += buffer;
136ed264e8aSJoaquín Ignacio Aramendía 	}
137ed264e8aSJoaquín Ignacio Aramendía 
138ed264e8aSJoaquín Ignacio Aramendía 	if (!unlock_global_acpi_lock())
139ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
140ed264e8aSJoaquín Ignacio Aramendía 
141ed264e8aSJoaquín Ignacio Aramendía 	return 0;
142ed264e8aSJoaquín Ignacio Aramendía }
143ed264e8aSJoaquín Ignacio Aramendía 
144*7590e659SJoaquín Ignacio Aramendía static int write_to_ec(u8 reg, u8 value)
145ed264e8aSJoaquín Ignacio Aramendía {
146ed264e8aSJoaquín Ignacio Aramendía 	int ret;
147ed264e8aSJoaquín Ignacio Aramendía 
148ed264e8aSJoaquín Ignacio Aramendía 	if (!lock_global_acpi_lock())
149ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
150ed264e8aSJoaquín Ignacio Aramendía 
151ed264e8aSJoaquín Ignacio Aramendía 	ret = ec_write(reg, value);
152ed264e8aSJoaquín Ignacio Aramendía 
153ed264e8aSJoaquín Ignacio Aramendía 	if (!unlock_global_acpi_lock())
154ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
155ed264e8aSJoaquín Ignacio Aramendía 
156ed264e8aSJoaquín Ignacio Aramendía 	return ret;
157ed264e8aSJoaquín Ignacio Aramendía }
158ed264e8aSJoaquín Ignacio Aramendía 
159*7590e659SJoaquín Ignacio Aramendía static int oxp_pwm_enable(void)
160ed264e8aSJoaquín Ignacio Aramendía {
161*7590e659SJoaquín Ignacio Aramendía 	return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x01);
162ed264e8aSJoaquín Ignacio Aramendía }
163ed264e8aSJoaquín Ignacio Aramendía 
164*7590e659SJoaquín Ignacio Aramendía static int oxp_pwm_disable(void)
165ed264e8aSJoaquín Ignacio Aramendía {
166*7590e659SJoaquín Ignacio Aramendía 	return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x00);
167ed264e8aSJoaquín Ignacio Aramendía }
168ed264e8aSJoaquín Ignacio Aramendía 
169ed264e8aSJoaquín Ignacio Aramendía /* Callbacks for hwmon interface */
170ed264e8aSJoaquín Ignacio Aramendía static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
171ed264e8aSJoaquín Ignacio Aramendía 				       enum hwmon_sensor_types type, u32 attr, int channel)
172ed264e8aSJoaquín Ignacio Aramendía {
173ed264e8aSJoaquín Ignacio Aramendía 	switch (type) {
174ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_fan:
175ed264e8aSJoaquín Ignacio Aramendía 		return 0444;
176ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_pwm:
177ed264e8aSJoaquín Ignacio Aramendía 		return 0644;
178ed264e8aSJoaquín Ignacio Aramendía 	default:
179ed264e8aSJoaquín Ignacio Aramendía 		return 0;
180ed264e8aSJoaquín Ignacio Aramendía 	}
181ed264e8aSJoaquín Ignacio Aramendía }
182ed264e8aSJoaquín Ignacio Aramendía 
183ed264e8aSJoaquín Ignacio Aramendía static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
184ed264e8aSJoaquín Ignacio Aramendía 			     u32 attr, int channel, long *val)
185ed264e8aSJoaquín Ignacio Aramendía {
186ed264e8aSJoaquín Ignacio Aramendía 	int ret;
187ed264e8aSJoaquín Ignacio Aramendía 
188ed264e8aSJoaquín Ignacio Aramendía 	switch (type) {
189ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_fan:
190ed264e8aSJoaquín Ignacio Aramendía 		switch (attr) {
191ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_fan_input:
192ed264e8aSJoaquín Ignacio Aramendía 			return read_from_ec(OXP_SENSOR_FAN_REG, 2, val);
193ed264e8aSJoaquín Ignacio Aramendía 		default:
194ed264e8aSJoaquín Ignacio Aramendía 			break;
195ed264e8aSJoaquín Ignacio Aramendía 		}
196ed264e8aSJoaquín Ignacio Aramendía 		break;
197ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_pwm:
198ed264e8aSJoaquín Ignacio Aramendía 		switch (attr) {
199ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_input:
2000cd3ba68SJoaquín Ignacio Aramendía 			ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
201ed264e8aSJoaquín Ignacio Aramendía 			if (ret)
202ed264e8aSJoaquín Ignacio Aramendía 				return ret;
203ebd4bfeeSDerek J. Clark 			switch (board) {
204f415cb6cSJoaquín Ignacio Aramendía 			case aya_neo_2:
205ebd4bfeeSDerek J. Clark 			case aya_neo_air:
206ebd4bfeeSDerek J. Clark 			case aya_neo_air_pro:
207f415cb6cSJoaquín Ignacio Aramendía 			case aya_neo_geek:
208ebd4bfeeSDerek J. Clark 			case oxp_mini_amd:
209ed264e8aSJoaquín Ignacio Aramendía 				*val = (*val * 255) / 100;
210ebd4bfeeSDerek J. Clark 				break;
211ebd4bfeeSDerek J. Clark 			case oxp_mini_amd_pro:
212ebd4bfeeSDerek J. Clark 			case aok_zoe_a1:
213ebd4bfeeSDerek J. Clark 			default:
214ebd4bfeeSDerek J. Clark 				break;
215ebd4bfeeSDerek J. Clark 			}
216ed264e8aSJoaquín Ignacio Aramendía 			return 0;
217ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_enable:
218ed264e8aSJoaquín Ignacio Aramendía 			return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
219ed264e8aSJoaquín Ignacio Aramendía 		default:
220ed264e8aSJoaquín Ignacio Aramendía 			break;
221ed264e8aSJoaquín Ignacio Aramendía 		}
222ed264e8aSJoaquín Ignacio Aramendía 		break;
223ed264e8aSJoaquín Ignacio Aramendía 	default:
224ed264e8aSJoaquín Ignacio Aramendía 		break;
225ed264e8aSJoaquín Ignacio Aramendía 	}
226ed264e8aSJoaquín Ignacio Aramendía 	return -EOPNOTSUPP;
227ed264e8aSJoaquín Ignacio Aramendía }
228ed264e8aSJoaquín Ignacio Aramendía 
229ed264e8aSJoaquín Ignacio Aramendía static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
230ed264e8aSJoaquín Ignacio Aramendía 			      u32 attr, int channel, long val)
231ed264e8aSJoaquín Ignacio Aramendía {
232ed264e8aSJoaquín Ignacio Aramendía 	switch (type) {
233ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_pwm:
234ed264e8aSJoaquín Ignacio Aramendía 		switch (attr) {
235ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_enable:
236ed264e8aSJoaquín Ignacio Aramendía 			if (val == 1)
237*7590e659SJoaquín Ignacio Aramendía 				return oxp_pwm_enable();
238ed264e8aSJoaquín Ignacio Aramendía 			else if (val == 0)
239*7590e659SJoaquín Ignacio Aramendía 				return oxp_pwm_disable();
240ed264e8aSJoaquín Ignacio Aramendía 			return -EINVAL;
241ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_input:
242ed264e8aSJoaquín Ignacio Aramendía 			if (val < 0 || val > 255)
243ed264e8aSJoaquín Ignacio Aramendía 				return -EINVAL;
244ebd4bfeeSDerek J. Clark 			switch (board) {
245f415cb6cSJoaquín Ignacio Aramendía 			case aya_neo_2:
246ebd4bfeeSDerek J. Clark 			case aya_neo_air:
247ebd4bfeeSDerek J. Clark 			case aya_neo_air_pro:
248f415cb6cSJoaquín Ignacio Aramendía 			case aya_neo_geek:
249ebd4bfeeSDerek J. Clark 			case oxp_mini_amd:
250ed264e8aSJoaquín Ignacio Aramendía 				val = (val * 100) / 255;
251ebd4bfeeSDerek J. Clark 				break;
252ebd4bfeeSDerek J. Clark 			case aok_zoe_a1:
253ebd4bfeeSDerek J. Clark 			case oxp_mini_amd_pro:
254ebd4bfeeSDerek J. Clark 			default:
255ebd4bfeeSDerek J. Clark 				break;
256ebd4bfeeSDerek J. Clark 			}
257*7590e659SJoaquín Ignacio Aramendía 			return write_to_ec(OXP_SENSOR_PWM_REG, val);
258ed264e8aSJoaquín Ignacio Aramendía 		default:
259ed264e8aSJoaquín Ignacio Aramendía 			break;
260ed264e8aSJoaquín Ignacio Aramendía 		}
261ed264e8aSJoaquín Ignacio Aramendía 		break;
262ed264e8aSJoaquín Ignacio Aramendía 	default:
263ed264e8aSJoaquín Ignacio Aramendía 		break;
264ed264e8aSJoaquín Ignacio Aramendía 	}
265ed264e8aSJoaquín Ignacio Aramendía 	return -EOPNOTSUPP;
266ed264e8aSJoaquín Ignacio Aramendía }
267ed264e8aSJoaquín Ignacio Aramendía 
268ed264e8aSJoaquín Ignacio Aramendía /* Known sensors in the OXP EC controllers */
269195030d3SKrzysztof Kozlowski static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
270ed264e8aSJoaquín Ignacio Aramendía 	HWMON_CHANNEL_INFO(fan,
271ed264e8aSJoaquín Ignacio Aramendía 			   HWMON_F_INPUT),
272ed264e8aSJoaquín Ignacio Aramendía 	HWMON_CHANNEL_INFO(pwm,
273ed264e8aSJoaquín Ignacio Aramendía 			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
274ed264e8aSJoaquín Ignacio Aramendía 	NULL,
275ed264e8aSJoaquín Ignacio Aramendía };
276ed264e8aSJoaquín Ignacio Aramendía 
277ed264e8aSJoaquín Ignacio Aramendía static const struct hwmon_ops oxp_ec_hwmon_ops = {
278ed264e8aSJoaquín Ignacio Aramendía 	.is_visible = oxp_ec_hwmon_is_visible,
279ed264e8aSJoaquín Ignacio Aramendía 	.read = oxp_platform_read,
280ed264e8aSJoaquín Ignacio Aramendía 	.write = oxp_platform_write,
281ed264e8aSJoaquín Ignacio Aramendía };
282ed264e8aSJoaquín Ignacio Aramendía 
283ed264e8aSJoaquín Ignacio Aramendía static const struct hwmon_chip_info oxp_ec_chip_info = {
284ed264e8aSJoaquín Ignacio Aramendía 	.ops = &oxp_ec_hwmon_ops,
285ed264e8aSJoaquín Ignacio Aramendía 	.info = oxp_platform_sensors,
286ed264e8aSJoaquín Ignacio Aramendía };
287ed264e8aSJoaquín Ignacio Aramendía 
288ed264e8aSJoaquín Ignacio Aramendía /* Initialization logic */
289ed264e8aSJoaquín Ignacio Aramendía static int oxp_platform_probe(struct platform_device *pdev)
290ed264e8aSJoaquín Ignacio Aramendía {
291ed264e8aSJoaquín Ignacio Aramendía 	const struct dmi_system_id *dmi_entry;
292ed264e8aSJoaquín Ignacio Aramendía 	struct device *dev = &pdev->dev;
293ed264e8aSJoaquín Ignacio Aramendía 	struct device *hwdev;
294ed264e8aSJoaquín Ignacio Aramendía 
295ed264e8aSJoaquín Ignacio Aramendía 	/*
296ed264e8aSJoaquín Ignacio Aramendía 	 * Have to check for AMD processor here because DMI strings are the
297ebd4bfeeSDerek J. Clark 	 * same between Intel and AMD boards, the only way to tell them apart
298ed264e8aSJoaquín Ignacio Aramendía 	 * is the CPU.
299ed264e8aSJoaquín Ignacio Aramendía 	 * Intel boards seem to have different EC registers and values to
300ed264e8aSJoaquín Ignacio Aramendía 	 * read/write.
301ed264e8aSJoaquín Ignacio Aramendía 	 */
302ed264e8aSJoaquín Ignacio Aramendía 	dmi_entry = dmi_first_match(dmi_table);
303ed264e8aSJoaquín Ignacio Aramendía 	if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
304ed264e8aSJoaquín Ignacio Aramendía 		return -ENODEV;
305ed264e8aSJoaquín Ignacio Aramendía 
3065d06ec42SJoaquín Ignacio Aramendía 	board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
3073ca0f12aSJoaquín Ignacio Aramendía 
308ed264e8aSJoaquín Ignacio Aramendía 	hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
309ed264e8aSJoaquín Ignacio Aramendía 						     &oxp_ec_chip_info, NULL);
310ed264e8aSJoaquín Ignacio Aramendía 
311ed264e8aSJoaquín Ignacio Aramendía 	return PTR_ERR_OR_ZERO(hwdev);
312ed264e8aSJoaquín Ignacio Aramendía }
313ed264e8aSJoaquín Ignacio Aramendía 
314ed264e8aSJoaquín Ignacio Aramendía static struct platform_driver oxp_platform_driver = {
315ed264e8aSJoaquín Ignacio Aramendía 	.driver = {
316ed264e8aSJoaquín Ignacio Aramendía 		.name = "oxp-platform",
317ed264e8aSJoaquín Ignacio Aramendía 	},
318ed264e8aSJoaquín Ignacio Aramendía 	.probe = oxp_platform_probe,
319ed264e8aSJoaquín Ignacio Aramendía };
320ed264e8aSJoaquín Ignacio Aramendía 
321ed264e8aSJoaquín Ignacio Aramendía static struct platform_device *oxp_platform_device;
322ed264e8aSJoaquín Ignacio Aramendía 
323ed264e8aSJoaquín Ignacio Aramendía static int __init oxp_platform_init(void)
324ed264e8aSJoaquín Ignacio Aramendía {
325ed264e8aSJoaquín Ignacio Aramendía 	oxp_platform_device =
326ed264e8aSJoaquín Ignacio Aramendía 		platform_create_bundle(&oxp_platform_driver,
327ed264e8aSJoaquín Ignacio Aramendía 				       oxp_platform_probe, NULL, 0, NULL, 0);
328ed264e8aSJoaquín Ignacio Aramendía 
329ed264e8aSJoaquín Ignacio Aramendía 	return PTR_ERR_OR_ZERO(oxp_platform_device);
330ed264e8aSJoaquín Ignacio Aramendía }
331ed264e8aSJoaquín Ignacio Aramendía 
332ed264e8aSJoaquín Ignacio Aramendía static void __exit oxp_platform_exit(void)
333ed264e8aSJoaquín Ignacio Aramendía {
334ed264e8aSJoaquín Ignacio Aramendía 	platform_device_unregister(oxp_platform_device);
335ed264e8aSJoaquín Ignacio Aramendía 	platform_driver_unregister(&oxp_platform_driver);
336ed264e8aSJoaquín Ignacio Aramendía }
337ed264e8aSJoaquín Ignacio Aramendía 
338ed264e8aSJoaquín Ignacio Aramendía MODULE_DEVICE_TABLE(dmi, dmi_table);
339ed264e8aSJoaquín Ignacio Aramendía 
340ed264e8aSJoaquín Ignacio Aramendía module_init(oxp_platform_init);
341ed264e8aSJoaquín Ignacio Aramendía module_exit(oxp_platform_exit);
342ed264e8aSJoaquín Ignacio Aramendía 
343ed264e8aSJoaquín Ignacio Aramendía MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>");
344ed264e8aSJoaquín Ignacio Aramendía MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices");
345ed264e8aSJoaquín Ignacio Aramendía MODULE_LICENSE("GPL");
346