xref: /openbmc/linux/drivers/hwmon/oxp-sensors.c (revision f415cb6c0ffece69eb60eca9750a2877c7985c89)
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,
45*f415cb6cSJoaquín Ignacio Aramendía 	aya_neo_2,
46ebd4bfeeSDerek J. Clark 	aya_neo_air,
47ebd4bfeeSDerek J. Clark 	aya_neo_air_pro,
48*f415cb6cSJoaquí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 		},
653ca0f12aSJoaquín Ignacio Aramendía 		.driver_data = (void *) &(enum oxp_board) {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"),
70*f415cb6cSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
71*f415cb6cSJoaquín Ignacio Aramendía 		},
72*f415cb6cSJoaquín Ignacio Aramendía 		.driver_data = (void *) &(enum oxp_board) {aya_neo_2},
73*f415cb6cSJoaquín Ignacio Aramendía 	},
74*f415cb6cSJoaquín Ignacio Aramendía 	{
75*f415cb6cSJoaquín Ignacio Aramendía 		.matches = {
76*f415cb6cSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
77ebd4bfeeSDerek J. Clark 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
78ebd4bfeeSDerek J. Clark 		},
79ebd4bfeeSDerek J. Clark 		.driver_data = (void *) &(enum oxp_board) {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 		},
86ebd4bfeeSDerek J. Clark 		.driver_data = (void *) &(enum oxp_board) {aya_neo_air_pro},
87ebd4bfeeSDerek J. Clark 	},
88ebd4bfeeSDerek J. Clark 	{
89ebd4bfeeSDerek J. Clark 		.matches = {
90*f415cb6cSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
91*f415cb6cSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GEEK"),
92*f415cb6cSJoaquín Ignacio Aramendía 		},
93*f415cb6cSJoaquín Ignacio Aramendía 		.driver_data = (void *) &(enum oxp_board) {aya_neo_geek},
94*f415cb6cSJoaquín Ignacio Aramendía 	},
95*f415cb6cSJoaquín Ignacio Aramendía 	{
96*f415cb6cSJoaquí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 		},
1003ca0f12aSJoaquín Ignacio Aramendía 		.driver_data = (void *) &(enum oxp_board) {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"),
1053ca0f12aSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
1063ca0f12aSJoaquín Ignacio Aramendía 		},
1073ca0f12aSJoaquín Ignacio Aramendía 		.driver_data = (void *) &(enum oxp_board) {oxp_mini_amd_pro},
108ed264e8aSJoaquín Ignacio Aramendía 	},
109ed264e8aSJoaquín Ignacio Aramendía 	{},
110ed264e8aSJoaquín Ignacio Aramendía };
111ed264e8aSJoaquín Ignacio Aramendía 
112ed264e8aSJoaquín Ignacio Aramendía /* Helper functions to handle EC read/write */
113ed264e8aSJoaquín Ignacio Aramendía static int read_from_ec(u8 reg, int size, long *val)
114ed264e8aSJoaquín Ignacio Aramendía {
115ed264e8aSJoaquín Ignacio Aramendía 	int i;
116ed264e8aSJoaquín Ignacio Aramendía 	int ret;
117ed264e8aSJoaquín Ignacio Aramendía 	u8 buffer;
118ed264e8aSJoaquín Ignacio Aramendía 
119ed264e8aSJoaquín Ignacio Aramendía 	if (!lock_global_acpi_lock())
120ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
121ed264e8aSJoaquín Ignacio Aramendía 
122ed264e8aSJoaquín Ignacio Aramendía 	*val = 0;
123ed264e8aSJoaquín Ignacio Aramendía 	for (i = 0; i < size; i++) {
124ed264e8aSJoaquín Ignacio Aramendía 		ret = ec_read(reg + i, &buffer);
125ed264e8aSJoaquín Ignacio Aramendía 		if (ret)
126ed264e8aSJoaquín Ignacio Aramendía 			return ret;
127ed264e8aSJoaquín Ignacio Aramendía 		*val <<= i * 8;
128ed264e8aSJoaquín Ignacio Aramendía 		*val += buffer;
129ed264e8aSJoaquín Ignacio Aramendía 	}
130ed264e8aSJoaquín Ignacio Aramendía 
131ed264e8aSJoaquín Ignacio Aramendía 	if (!unlock_global_acpi_lock())
132ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
133ed264e8aSJoaquín Ignacio Aramendía 
134ed264e8aSJoaquín Ignacio Aramendía 	return 0;
135ed264e8aSJoaquín Ignacio Aramendía }
136ed264e8aSJoaquín Ignacio Aramendía 
137ed264e8aSJoaquín Ignacio Aramendía static int write_to_ec(const struct device *dev, u8 reg, u8 value)
138ed264e8aSJoaquín Ignacio Aramendía {
139ed264e8aSJoaquín Ignacio Aramendía 	int ret;
140ed264e8aSJoaquín Ignacio Aramendía 
141ed264e8aSJoaquín Ignacio Aramendía 	if (!lock_global_acpi_lock())
142ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
143ed264e8aSJoaquín Ignacio Aramendía 
144ed264e8aSJoaquín Ignacio Aramendía 	ret = ec_write(reg, value);
145ed264e8aSJoaquín Ignacio Aramendía 
146ed264e8aSJoaquín Ignacio Aramendía 	if (!unlock_global_acpi_lock())
147ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
148ed264e8aSJoaquín Ignacio Aramendía 
149ed264e8aSJoaquín Ignacio Aramendía 	return ret;
150ed264e8aSJoaquín Ignacio Aramendía }
151ed264e8aSJoaquín Ignacio Aramendía 
152ed264e8aSJoaquín Ignacio Aramendía static int oxp_pwm_enable(const struct device *dev)
153ed264e8aSJoaquín Ignacio Aramendía {
154ed264e8aSJoaquín Ignacio Aramendía 	return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x01);
155ed264e8aSJoaquín Ignacio Aramendía }
156ed264e8aSJoaquín Ignacio Aramendía 
157ed264e8aSJoaquín Ignacio Aramendía static int oxp_pwm_disable(const struct device *dev)
158ed264e8aSJoaquín Ignacio Aramendía {
159ed264e8aSJoaquín Ignacio Aramendía 	return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x00);
160ed264e8aSJoaquín Ignacio Aramendía }
161ed264e8aSJoaquín Ignacio Aramendía 
162ed264e8aSJoaquín Ignacio Aramendía /* Callbacks for hwmon interface */
163ed264e8aSJoaquín Ignacio Aramendía static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
164ed264e8aSJoaquín Ignacio Aramendía 				       enum hwmon_sensor_types type, u32 attr, int channel)
165ed264e8aSJoaquín Ignacio Aramendía {
166ed264e8aSJoaquín Ignacio Aramendía 	switch (type) {
167ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_fan:
168ed264e8aSJoaquín Ignacio Aramendía 		return 0444;
169ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_pwm:
170ed264e8aSJoaquín Ignacio Aramendía 		return 0644;
171ed264e8aSJoaquín Ignacio Aramendía 	default:
172ed264e8aSJoaquín Ignacio Aramendía 		return 0;
173ed264e8aSJoaquín Ignacio Aramendía 	}
174ed264e8aSJoaquín Ignacio Aramendía }
175ed264e8aSJoaquín Ignacio Aramendía 
176ed264e8aSJoaquín Ignacio Aramendía static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
177ed264e8aSJoaquín Ignacio Aramendía 			     u32 attr, int channel, long *val)
178ed264e8aSJoaquín Ignacio Aramendía {
179ed264e8aSJoaquín Ignacio Aramendía 	int ret;
180ed264e8aSJoaquín Ignacio Aramendía 
181ed264e8aSJoaquín Ignacio Aramendía 	switch (type) {
182ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_fan:
183ed264e8aSJoaquín Ignacio Aramendía 		switch (attr) {
184ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_fan_input:
185ed264e8aSJoaquín Ignacio Aramendía 			return read_from_ec(OXP_SENSOR_FAN_REG, 2, val);
186ed264e8aSJoaquín Ignacio Aramendía 		default:
187ed264e8aSJoaquín Ignacio Aramendía 			break;
188ed264e8aSJoaquín Ignacio Aramendía 		}
189ed264e8aSJoaquín Ignacio Aramendía 		break;
190ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_pwm:
191ed264e8aSJoaquín Ignacio Aramendía 		switch (attr) {
192ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_input:
1930cd3ba68SJoaquín Ignacio Aramendía 			ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
194ed264e8aSJoaquín Ignacio Aramendía 			if (ret)
195ed264e8aSJoaquín Ignacio Aramendía 				return ret;
196ebd4bfeeSDerek J. Clark 			switch (board) {
197*f415cb6cSJoaquín Ignacio Aramendía 			case aya_neo_2:
198ebd4bfeeSDerek J. Clark 			case aya_neo_air:
199ebd4bfeeSDerek J. Clark 			case aya_neo_air_pro:
200*f415cb6cSJoaquín Ignacio Aramendía 			case aya_neo_geek:
201ebd4bfeeSDerek J. Clark 			case oxp_mini_amd:
202ed264e8aSJoaquín Ignacio Aramendía 				*val = (*val * 255) / 100;
203ebd4bfeeSDerek J. Clark 				break;
204ebd4bfeeSDerek J. Clark 			case oxp_mini_amd_pro:
205ebd4bfeeSDerek J. Clark 			case aok_zoe_a1:
206ebd4bfeeSDerek J. Clark 			default:
207ebd4bfeeSDerek J. Clark 				break;
208ebd4bfeeSDerek J. Clark 			}
209ed264e8aSJoaquín Ignacio Aramendía 			return 0;
210ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_enable:
211ed264e8aSJoaquín Ignacio Aramendía 			return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
212ed264e8aSJoaquín Ignacio Aramendía 		default:
213ed264e8aSJoaquín Ignacio Aramendía 			break;
214ed264e8aSJoaquín Ignacio Aramendía 		}
215ed264e8aSJoaquín Ignacio Aramendía 		break;
216ed264e8aSJoaquín Ignacio Aramendía 	default:
217ed264e8aSJoaquín Ignacio Aramendía 		break;
218ed264e8aSJoaquín Ignacio Aramendía 	}
219ed264e8aSJoaquín Ignacio Aramendía 	return -EOPNOTSUPP;
220ed264e8aSJoaquín Ignacio Aramendía }
221ed264e8aSJoaquín Ignacio Aramendía 
222ed264e8aSJoaquín Ignacio Aramendía static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
223ed264e8aSJoaquín Ignacio Aramendía 			      u32 attr, int channel, long val)
224ed264e8aSJoaquín Ignacio Aramendía {
225ed264e8aSJoaquín Ignacio Aramendía 	switch (type) {
226ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_pwm:
227ed264e8aSJoaquín Ignacio Aramendía 		switch (attr) {
228ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_enable:
229ed264e8aSJoaquín Ignacio Aramendía 			if (val == 1)
230ed264e8aSJoaquín Ignacio Aramendía 				return oxp_pwm_enable(dev);
231ed264e8aSJoaquín Ignacio Aramendía 			else if (val == 0)
232ed264e8aSJoaquín Ignacio Aramendía 				return oxp_pwm_disable(dev);
233ed264e8aSJoaquín Ignacio Aramendía 			return -EINVAL;
234ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_input:
235ed264e8aSJoaquín Ignacio Aramendía 			if (val < 0 || val > 255)
236ed264e8aSJoaquín Ignacio Aramendía 				return -EINVAL;
237ebd4bfeeSDerek J. Clark 			switch (board) {
238*f415cb6cSJoaquín Ignacio Aramendía 			case aya_neo_2:
239ebd4bfeeSDerek J. Clark 			case aya_neo_air:
240ebd4bfeeSDerek J. Clark 			case aya_neo_air_pro:
241*f415cb6cSJoaquín Ignacio Aramendía 			case aya_neo_geek:
242ebd4bfeeSDerek J. Clark 			case oxp_mini_amd:
243ed264e8aSJoaquín Ignacio Aramendía 				val = (val * 100) / 255;
244ebd4bfeeSDerek J. Clark 				break;
245ebd4bfeeSDerek J. Clark 			case aok_zoe_a1:
246ebd4bfeeSDerek J. Clark 			case oxp_mini_amd_pro:
247ebd4bfeeSDerek J. Clark 			default:
248ebd4bfeeSDerek J. Clark 				break;
249ebd4bfeeSDerek J. Clark 			}
250ed264e8aSJoaquín Ignacio Aramendía 			return write_to_ec(dev, OXP_SENSOR_PWM_REG, val);
251ed264e8aSJoaquín Ignacio Aramendía 		default:
252ed264e8aSJoaquín Ignacio Aramendía 			break;
253ed264e8aSJoaquín Ignacio Aramendía 		}
254ed264e8aSJoaquín Ignacio Aramendía 		break;
255ed264e8aSJoaquín Ignacio Aramendía 	default:
256ed264e8aSJoaquín Ignacio Aramendía 		break;
257ed264e8aSJoaquín Ignacio Aramendía 	}
258ed264e8aSJoaquín Ignacio Aramendía 	return -EOPNOTSUPP;
259ed264e8aSJoaquín Ignacio Aramendía }
260ed264e8aSJoaquín Ignacio Aramendía 
261ed264e8aSJoaquín Ignacio Aramendía /* Known sensors in the OXP EC controllers */
262195030d3SKrzysztof Kozlowski static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
263ed264e8aSJoaquín Ignacio Aramendía 	HWMON_CHANNEL_INFO(fan,
264ed264e8aSJoaquín Ignacio Aramendía 			   HWMON_F_INPUT),
265ed264e8aSJoaquín Ignacio Aramendía 	HWMON_CHANNEL_INFO(pwm,
266ed264e8aSJoaquín Ignacio Aramendía 			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
267ed264e8aSJoaquín Ignacio Aramendía 	NULL,
268ed264e8aSJoaquín Ignacio Aramendía };
269ed264e8aSJoaquín Ignacio Aramendía 
270ed264e8aSJoaquín Ignacio Aramendía static const struct hwmon_ops oxp_ec_hwmon_ops = {
271ed264e8aSJoaquín Ignacio Aramendía 	.is_visible = oxp_ec_hwmon_is_visible,
272ed264e8aSJoaquín Ignacio Aramendía 	.read = oxp_platform_read,
273ed264e8aSJoaquín Ignacio Aramendía 	.write = oxp_platform_write,
274ed264e8aSJoaquín Ignacio Aramendía };
275ed264e8aSJoaquín Ignacio Aramendía 
276ed264e8aSJoaquín Ignacio Aramendía static const struct hwmon_chip_info oxp_ec_chip_info = {
277ed264e8aSJoaquín Ignacio Aramendía 	.ops = &oxp_ec_hwmon_ops,
278ed264e8aSJoaquín Ignacio Aramendía 	.info = oxp_platform_sensors,
279ed264e8aSJoaquín Ignacio Aramendía };
280ed264e8aSJoaquín Ignacio Aramendía 
281ed264e8aSJoaquín Ignacio Aramendía /* Initialization logic */
282ed264e8aSJoaquín Ignacio Aramendía static int oxp_platform_probe(struct platform_device *pdev)
283ed264e8aSJoaquín Ignacio Aramendía {
284ed264e8aSJoaquín Ignacio Aramendía 	const struct dmi_system_id *dmi_entry;
285ed264e8aSJoaquín Ignacio Aramendía 	struct device *dev = &pdev->dev;
286ed264e8aSJoaquín Ignacio Aramendía 	struct device *hwdev;
287ed264e8aSJoaquín Ignacio Aramendía 
288ed264e8aSJoaquín Ignacio Aramendía 	/*
289ed264e8aSJoaquín Ignacio Aramendía 	 * Have to check for AMD processor here because DMI strings are the
290ebd4bfeeSDerek J. Clark 	 * same between Intel and AMD boards, the only way to tell them apart
291ed264e8aSJoaquín Ignacio Aramendía 	 * is the CPU.
292ed264e8aSJoaquín Ignacio Aramendía 	 * Intel boards seem to have different EC registers and values to
293ed264e8aSJoaquín Ignacio Aramendía 	 * read/write.
294ed264e8aSJoaquín Ignacio Aramendía 	 */
295ed264e8aSJoaquín Ignacio Aramendía 	dmi_entry = dmi_first_match(dmi_table);
296ed264e8aSJoaquín Ignacio Aramendía 	if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
297ed264e8aSJoaquín Ignacio Aramendía 		return -ENODEV;
298ed264e8aSJoaquín Ignacio Aramendía 
2993ca0f12aSJoaquín Ignacio Aramendía 	board = *((enum oxp_board *) dmi_entry->driver_data);
3003ca0f12aSJoaquín Ignacio Aramendía 
301ed264e8aSJoaquín Ignacio Aramendía 	hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
302ed264e8aSJoaquín Ignacio Aramendía 						     &oxp_ec_chip_info, NULL);
303ed264e8aSJoaquín Ignacio Aramendía 
304ed264e8aSJoaquín Ignacio Aramendía 	return PTR_ERR_OR_ZERO(hwdev);
305ed264e8aSJoaquín Ignacio Aramendía }
306ed264e8aSJoaquín Ignacio Aramendía 
307ed264e8aSJoaquín Ignacio Aramendía static struct platform_driver oxp_platform_driver = {
308ed264e8aSJoaquín Ignacio Aramendía 	.driver = {
309ed264e8aSJoaquín Ignacio Aramendía 		.name = "oxp-platform",
310ed264e8aSJoaquín Ignacio Aramendía 	},
311ed264e8aSJoaquín Ignacio Aramendía 	.probe = oxp_platform_probe,
312ed264e8aSJoaquín Ignacio Aramendía };
313ed264e8aSJoaquín Ignacio Aramendía 
314ed264e8aSJoaquín Ignacio Aramendía static struct platform_device *oxp_platform_device;
315ed264e8aSJoaquín Ignacio Aramendía 
316ed264e8aSJoaquín Ignacio Aramendía static int __init oxp_platform_init(void)
317ed264e8aSJoaquín Ignacio Aramendía {
318ed264e8aSJoaquín Ignacio Aramendía 	oxp_platform_device =
319ed264e8aSJoaquín Ignacio Aramendía 		platform_create_bundle(&oxp_platform_driver,
320ed264e8aSJoaquín Ignacio Aramendía 				       oxp_platform_probe, NULL, 0, NULL, 0);
321ed264e8aSJoaquín Ignacio Aramendía 
322ed264e8aSJoaquín Ignacio Aramendía 	return PTR_ERR_OR_ZERO(oxp_platform_device);
323ed264e8aSJoaquín Ignacio Aramendía }
324ed264e8aSJoaquín Ignacio Aramendía 
325ed264e8aSJoaquín Ignacio Aramendía static void __exit oxp_platform_exit(void)
326ed264e8aSJoaquín Ignacio Aramendía {
327ed264e8aSJoaquín Ignacio Aramendía 	platform_device_unregister(oxp_platform_device);
328ed264e8aSJoaquín Ignacio Aramendía 	platform_driver_unregister(&oxp_platform_driver);
329ed264e8aSJoaquín Ignacio Aramendía }
330ed264e8aSJoaquín Ignacio Aramendía 
331ed264e8aSJoaquín Ignacio Aramendía MODULE_DEVICE_TABLE(dmi, dmi_table);
332ed264e8aSJoaquín Ignacio Aramendía 
333ed264e8aSJoaquín Ignacio Aramendía module_init(oxp_platform_init);
334ed264e8aSJoaquín Ignacio Aramendía module_exit(oxp_platform_exit);
335ed264e8aSJoaquín Ignacio Aramendía 
336ed264e8aSJoaquín Ignacio Aramendía MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>");
337ed264e8aSJoaquín Ignacio Aramendía MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices");
338ed264e8aSJoaquín Ignacio Aramendía MODULE_LICENSE("GPL");
339