xref: /openbmc/linux/drivers/hwmon/oxp-sensors.c (revision ebd4bfee2b972d34a2f72f81767d0cf47e6c914b)
1ed264e8aSJoaquín Ignacio Aramendía // SPDX-License-Identifier: GPL-2.0+
2ed264e8aSJoaquín Ignacio Aramendía /*
3*ebd4bfeeSDerek J. Clark  * Platform driver for OneXPlayer, AOK ZOE, and Aya Neo Handhelds that expose
4*ebd4bfeeSDerek J. Clark  * fan reading and control via hwmon sysfs.
5ed264e8aSJoaquín Ignacio Aramendía  *
6*ebd4bfeeSDerek J. Clark  * Old OXP boards have the same DMI strings and they are told apart by
7*ebd4bfeeSDerek J. Clark  * the boot cpu vendor (Intel/AMD). Currently only AMD boards are
8*ebd4bfeeSDerek J. Clark  * supported but the code is made to be simple to add other handheld
9*ebd4bfeeSDerek 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*ebd4bfeeSDerek J. Clark 	aya_neo_air,
46*ebd4bfeeSDerek J. Clark 	aya_neo_air_pro,
473ca0f12aSJoaquín Ignacio Aramendía 	oxp_mini_amd,
483ca0f12aSJoaquín Ignacio Aramendía 	oxp_mini_amd_pro,
493ca0f12aSJoaquín Ignacio Aramendía };
503ca0f12aSJoaquín Ignacio Aramendía 
513ca0f12aSJoaquín Ignacio Aramendía static enum oxp_board board;
523ca0f12aSJoaquín Ignacio Aramendía 
53ed264e8aSJoaquín Ignacio Aramendía #define OXP_SENSOR_FAN_REG		0x76 /* Fan reading is 2 registers long */
54ed264e8aSJoaquín Ignacio Aramendía #define OXP_SENSOR_PWM_ENABLE_REG	0x4A /* PWM enable is 1 register long */
55ed264e8aSJoaquín Ignacio Aramendía #define OXP_SENSOR_PWM_REG		0x4B /* PWM reading is 1 register long */
56ed264e8aSJoaquín Ignacio Aramendía 
57ed264e8aSJoaquín Ignacio Aramendía static const struct dmi_system_id dmi_table[] = {
58ed264e8aSJoaquín Ignacio Aramendía 	{
59ed264e8aSJoaquín Ignacio Aramendía 		.matches = {
603ca0f12aSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
613ca0f12aSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"),
623ca0f12aSJoaquín Ignacio Aramendía 		},
633ca0f12aSJoaquín Ignacio Aramendía 		.driver_data = (void *) &(enum oxp_board) {aok_zoe_a1},
643ca0f12aSJoaquín Ignacio Aramendía 	},
653ca0f12aSJoaquín Ignacio Aramendía 	{
663ca0f12aSJoaquín Ignacio Aramendía 		.matches = {
67*ebd4bfeeSDerek J. Clark 			DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
68*ebd4bfeeSDerek J. Clark 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
69*ebd4bfeeSDerek J. Clark 		},
70*ebd4bfeeSDerek J. Clark 		.driver_data = (void *) &(enum oxp_board) {aya_neo_air},
71*ebd4bfeeSDerek J. Clark 	},
72*ebd4bfeeSDerek J. Clark 	{
73*ebd4bfeeSDerek J. Clark 		.matches = {
74*ebd4bfeeSDerek J. Clark 			DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
75*ebd4bfeeSDerek J. Clark 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
76*ebd4bfeeSDerek J. Clark 		},
77*ebd4bfeeSDerek J. Clark 		.driver_data = (void *) &(enum oxp_board) {aya_neo_air_pro},
78*ebd4bfeeSDerek J. Clark 	},
79*ebd4bfeeSDerek J. Clark 	{
80*ebd4bfeeSDerek J. Clark 		.matches = {
81ed264e8aSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
82ed264e8aSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
83ed264e8aSJoaquín Ignacio Aramendía 		},
843ca0f12aSJoaquín Ignacio Aramendía 		.driver_data = (void *) &(enum oxp_board) {oxp_mini_amd},
853ca0f12aSJoaquín Ignacio Aramendía 	},
863ca0f12aSJoaquín Ignacio Aramendía 	{
873ca0f12aSJoaquín Ignacio Aramendía 		.matches = {
883ca0f12aSJoaquín Ignacio Aramendía 			DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
893ca0f12aSJoaquín Ignacio Aramendía 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
903ca0f12aSJoaquín Ignacio Aramendía 		},
913ca0f12aSJoaquín Ignacio Aramendía 		.driver_data = (void *) &(enum oxp_board) {oxp_mini_amd_pro},
92ed264e8aSJoaquín Ignacio Aramendía 	},
93ed264e8aSJoaquín Ignacio Aramendía 	{},
94ed264e8aSJoaquín Ignacio Aramendía };
95ed264e8aSJoaquín Ignacio Aramendía 
96ed264e8aSJoaquín Ignacio Aramendía /* Helper functions to handle EC read/write */
97ed264e8aSJoaquín Ignacio Aramendía static int read_from_ec(u8 reg, int size, long *val)
98ed264e8aSJoaquín Ignacio Aramendía {
99ed264e8aSJoaquín Ignacio Aramendía 	int i;
100ed264e8aSJoaquín Ignacio Aramendía 	int ret;
101ed264e8aSJoaquín Ignacio Aramendía 	u8 buffer;
102ed264e8aSJoaquín Ignacio Aramendía 
103ed264e8aSJoaquín Ignacio Aramendía 	if (!lock_global_acpi_lock())
104ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
105ed264e8aSJoaquín Ignacio Aramendía 
106ed264e8aSJoaquín Ignacio Aramendía 	*val = 0;
107ed264e8aSJoaquín Ignacio Aramendía 	for (i = 0; i < size; i++) {
108ed264e8aSJoaquín Ignacio Aramendía 		ret = ec_read(reg + i, &buffer);
109ed264e8aSJoaquín Ignacio Aramendía 		if (ret)
110ed264e8aSJoaquín Ignacio Aramendía 			return ret;
111ed264e8aSJoaquín Ignacio Aramendía 		*val <<= i * 8;
112ed264e8aSJoaquín Ignacio Aramendía 		*val += buffer;
113ed264e8aSJoaquín Ignacio Aramendía 	}
114ed264e8aSJoaquín Ignacio Aramendía 
115ed264e8aSJoaquín Ignacio Aramendía 	if (!unlock_global_acpi_lock())
116ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
117ed264e8aSJoaquín Ignacio Aramendía 
118ed264e8aSJoaquín Ignacio Aramendía 	return 0;
119ed264e8aSJoaquín Ignacio Aramendía }
120ed264e8aSJoaquín Ignacio Aramendía 
121ed264e8aSJoaquín Ignacio Aramendía static int write_to_ec(const struct device *dev, u8 reg, u8 value)
122ed264e8aSJoaquín Ignacio Aramendía {
123ed264e8aSJoaquín Ignacio Aramendía 	int ret;
124ed264e8aSJoaquín Ignacio Aramendía 
125ed264e8aSJoaquín Ignacio Aramendía 	if (!lock_global_acpi_lock())
126ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
127ed264e8aSJoaquín Ignacio Aramendía 
128ed264e8aSJoaquín Ignacio Aramendía 	ret = ec_write(reg, value);
129ed264e8aSJoaquín Ignacio Aramendía 
130ed264e8aSJoaquín Ignacio Aramendía 	if (!unlock_global_acpi_lock())
131ed264e8aSJoaquín Ignacio Aramendía 		return -EBUSY;
132ed264e8aSJoaquín Ignacio Aramendía 
133ed264e8aSJoaquín Ignacio Aramendía 	return ret;
134ed264e8aSJoaquín Ignacio Aramendía }
135ed264e8aSJoaquín Ignacio Aramendía 
136ed264e8aSJoaquín Ignacio Aramendía static int oxp_pwm_enable(const struct device *dev)
137ed264e8aSJoaquín Ignacio Aramendía {
138ed264e8aSJoaquín Ignacio Aramendía 	return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x01);
139ed264e8aSJoaquín Ignacio Aramendía }
140ed264e8aSJoaquín Ignacio Aramendía 
141ed264e8aSJoaquín Ignacio Aramendía static int oxp_pwm_disable(const struct device *dev)
142ed264e8aSJoaquín Ignacio Aramendía {
143ed264e8aSJoaquín Ignacio Aramendía 	return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x00);
144ed264e8aSJoaquín Ignacio Aramendía }
145ed264e8aSJoaquín Ignacio Aramendía 
146ed264e8aSJoaquín Ignacio Aramendía /* Callbacks for hwmon interface */
147ed264e8aSJoaquín Ignacio Aramendía static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
148ed264e8aSJoaquín Ignacio Aramendía 				       enum hwmon_sensor_types type, u32 attr, int channel)
149ed264e8aSJoaquín Ignacio Aramendía {
150ed264e8aSJoaquín Ignacio Aramendía 	switch (type) {
151ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_fan:
152ed264e8aSJoaquín Ignacio Aramendía 		return 0444;
153ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_pwm:
154ed264e8aSJoaquín Ignacio Aramendía 		return 0644;
155ed264e8aSJoaquín Ignacio Aramendía 	default:
156ed264e8aSJoaquín Ignacio Aramendía 		return 0;
157ed264e8aSJoaquín Ignacio Aramendía 	}
158ed264e8aSJoaquín Ignacio Aramendía }
159ed264e8aSJoaquín Ignacio Aramendía 
160ed264e8aSJoaquín Ignacio Aramendía static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
161ed264e8aSJoaquín Ignacio Aramendía 			     u32 attr, int channel, long *val)
162ed264e8aSJoaquín Ignacio Aramendía {
163ed264e8aSJoaquín Ignacio Aramendía 	int ret;
164ed264e8aSJoaquín Ignacio Aramendía 
165ed264e8aSJoaquín Ignacio Aramendía 	switch (type) {
166ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_fan:
167ed264e8aSJoaquín Ignacio Aramendía 		switch (attr) {
168ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_fan_input:
169ed264e8aSJoaquín Ignacio Aramendía 			return read_from_ec(OXP_SENSOR_FAN_REG, 2, val);
170ed264e8aSJoaquín Ignacio Aramendía 		default:
171ed264e8aSJoaquín Ignacio Aramendía 			break;
172ed264e8aSJoaquín Ignacio Aramendía 		}
173ed264e8aSJoaquín Ignacio Aramendía 		break;
174ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_pwm:
175ed264e8aSJoaquín Ignacio Aramendía 		switch (attr) {
176ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_input:
1770cd3ba68SJoaquín Ignacio Aramendía 			ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
178ed264e8aSJoaquín Ignacio Aramendía 			if (ret)
179ed264e8aSJoaquín Ignacio Aramendía 				return ret;
180*ebd4bfeeSDerek J. Clark 			switch (board) {
181*ebd4bfeeSDerek J. Clark 			case aya_neo_air:
182*ebd4bfeeSDerek J. Clark 			case aya_neo_air_pro:
183*ebd4bfeeSDerek J. Clark 			case oxp_mini_amd:
184ed264e8aSJoaquín Ignacio Aramendía 				*val = (*val * 255) / 100;
185*ebd4bfeeSDerek J. Clark 				break;
186*ebd4bfeeSDerek J. Clark 			case oxp_mini_amd_pro:
187*ebd4bfeeSDerek J. Clark 			case aok_zoe_a1:
188*ebd4bfeeSDerek J. Clark 			default:
189*ebd4bfeeSDerek J. Clark 				break;
190*ebd4bfeeSDerek J. Clark 			}
191ed264e8aSJoaquín Ignacio Aramendía 			return 0;
192ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_enable:
193ed264e8aSJoaquín Ignacio Aramendía 			return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
194ed264e8aSJoaquín Ignacio Aramendía 		default:
195ed264e8aSJoaquín Ignacio Aramendía 			break;
196ed264e8aSJoaquín Ignacio Aramendía 		}
197ed264e8aSJoaquín Ignacio Aramendía 		break;
198ed264e8aSJoaquín Ignacio Aramendía 	default:
199ed264e8aSJoaquín Ignacio Aramendía 		break;
200ed264e8aSJoaquín Ignacio Aramendía 	}
201ed264e8aSJoaquín Ignacio Aramendía 	return -EOPNOTSUPP;
202ed264e8aSJoaquín Ignacio Aramendía }
203ed264e8aSJoaquín Ignacio Aramendía 
204ed264e8aSJoaquín Ignacio Aramendía static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
205ed264e8aSJoaquín Ignacio Aramendía 			      u32 attr, int channel, long val)
206ed264e8aSJoaquín Ignacio Aramendía {
207ed264e8aSJoaquín Ignacio Aramendía 	switch (type) {
208ed264e8aSJoaquín Ignacio Aramendía 	case hwmon_pwm:
209ed264e8aSJoaquín Ignacio Aramendía 		switch (attr) {
210ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_enable:
211ed264e8aSJoaquín Ignacio Aramendía 			if (val == 1)
212ed264e8aSJoaquín Ignacio Aramendía 				return oxp_pwm_enable(dev);
213ed264e8aSJoaquín Ignacio Aramendía 			else if (val == 0)
214ed264e8aSJoaquín Ignacio Aramendía 				return oxp_pwm_disable(dev);
215ed264e8aSJoaquín Ignacio Aramendía 			return -EINVAL;
216ed264e8aSJoaquín Ignacio Aramendía 		case hwmon_pwm_input:
217ed264e8aSJoaquín Ignacio Aramendía 			if (val < 0 || val > 255)
218ed264e8aSJoaquín Ignacio Aramendía 				return -EINVAL;
219*ebd4bfeeSDerek J. Clark 			switch (board) {
220*ebd4bfeeSDerek J. Clark 			case aya_neo_air:
221*ebd4bfeeSDerek J. Clark 			case aya_neo_air_pro:
222*ebd4bfeeSDerek J. Clark 			case oxp_mini_amd:
223ed264e8aSJoaquín Ignacio Aramendía 				val = (val * 100) / 255;
224*ebd4bfeeSDerek J. Clark 				break;
225*ebd4bfeeSDerek J. Clark 			case aok_zoe_a1:
226*ebd4bfeeSDerek J. Clark 			case oxp_mini_amd_pro:
227*ebd4bfeeSDerek J. Clark 			default:
228*ebd4bfeeSDerek J. Clark 				break;
229*ebd4bfeeSDerek J. Clark 			}
230ed264e8aSJoaquín Ignacio Aramendía 			return write_to_ec(dev, OXP_SENSOR_PWM_REG, val);
231ed264e8aSJoaquín Ignacio Aramendía 		default:
232ed264e8aSJoaquín Ignacio Aramendía 			break;
233ed264e8aSJoaquín Ignacio Aramendía 		}
234ed264e8aSJoaquín Ignacio Aramendía 		break;
235ed264e8aSJoaquín Ignacio Aramendía 	default:
236ed264e8aSJoaquín Ignacio Aramendía 		break;
237ed264e8aSJoaquín Ignacio Aramendía 	}
238ed264e8aSJoaquín Ignacio Aramendía 	return -EOPNOTSUPP;
239ed264e8aSJoaquín Ignacio Aramendía }
240ed264e8aSJoaquín Ignacio Aramendía 
241ed264e8aSJoaquín Ignacio Aramendía /* Known sensors in the OXP EC controllers */
242ed264e8aSJoaquín Ignacio Aramendía static const struct hwmon_channel_info *oxp_platform_sensors[] = {
243ed264e8aSJoaquín Ignacio Aramendía 	HWMON_CHANNEL_INFO(fan,
244ed264e8aSJoaquín Ignacio Aramendía 			   HWMON_F_INPUT),
245ed264e8aSJoaquín Ignacio Aramendía 	HWMON_CHANNEL_INFO(pwm,
246ed264e8aSJoaquín Ignacio Aramendía 			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
247ed264e8aSJoaquín Ignacio Aramendía 	NULL,
248ed264e8aSJoaquín Ignacio Aramendía };
249ed264e8aSJoaquín Ignacio Aramendía 
250ed264e8aSJoaquín Ignacio Aramendía static const struct hwmon_ops oxp_ec_hwmon_ops = {
251ed264e8aSJoaquín Ignacio Aramendía 	.is_visible = oxp_ec_hwmon_is_visible,
252ed264e8aSJoaquín Ignacio Aramendía 	.read = oxp_platform_read,
253ed264e8aSJoaquín Ignacio Aramendía 	.write = oxp_platform_write,
254ed264e8aSJoaquín Ignacio Aramendía };
255ed264e8aSJoaquín Ignacio Aramendía 
256ed264e8aSJoaquín Ignacio Aramendía static const struct hwmon_chip_info oxp_ec_chip_info = {
257ed264e8aSJoaquín Ignacio Aramendía 	.ops = &oxp_ec_hwmon_ops,
258ed264e8aSJoaquín Ignacio Aramendía 	.info = oxp_platform_sensors,
259ed264e8aSJoaquín Ignacio Aramendía };
260ed264e8aSJoaquín Ignacio Aramendía 
261ed264e8aSJoaquín Ignacio Aramendía /* Initialization logic */
262ed264e8aSJoaquín Ignacio Aramendía static int oxp_platform_probe(struct platform_device *pdev)
263ed264e8aSJoaquín Ignacio Aramendía {
264ed264e8aSJoaquín Ignacio Aramendía 	const struct dmi_system_id *dmi_entry;
265ed264e8aSJoaquín Ignacio Aramendía 	struct device *dev = &pdev->dev;
266ed264e8aSJoaquín Ignacio Aramendía 	struct device *hwdev;
267ed264e8aSJoaquín Ignacio Aramendía 
268ed264e8aSJoaquín Ignacio Aramendía 	/*
269ed264e8aSJoaquín Ignacio Aramendía 	 * Have to check for AMD processor here because DMI strings are the
270*ebd4bfeeSDerek J. Clark 	 * same between Intel and AMD boards, the only way to tell them apart
271ed264e8aSJoaquín Ignacio Aramendía 	 * is the CPU.
272ed264e8aSJoaquín Ignacio Aramendía 	 * Intel boards seem to have different EC registers and values to
273ed264e8aSJoaquín Ignacio Aramendía 	 * read/write.
274ed264e8aSJoaquín Ignacio Aramendía 	 */
275ed264e8aSJoaquín Ignacio Aramendía 	dmi_entry = dmi_first_match(dmi_table);
276ed264e8aSJoaquín Ignacio Aramendía 	if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
277ed264e8aSJoaquín Ignacio Aramendía 		return -ENODEV;
278ed264e8aSJoaquín Ignacio Aramendía 
2793ca0f12aSJoaquín Ignacio Aramendía 	board = *((enum oxp_board *) dmi_entry->driver_data);
2803ca0f12aSJoaquín Ignacio Aramendía 
281ed264e8aSJoaquín Ignacio Aramendía 	hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
282ed264e8aSJoaquín Ignacio Aramendía 						     &oxp_ec_chip_info, NULL);
283ed264e8aSJoaquín Ignacio Aramendía 
284ed264e8aSJoaquín Ignacio Aramendía 	return PTR_ERR_OR_ZERO(hwdev);
285ed264e8aSJoaquín Ignacio Aramendía }
286ed264e8aSJoaquín Ignacio Aramendía 
287ed264e8aSJoaquín Ignacio Aramendía static struct platform_driver oxp_platform_driver = {
288ed264e8aSJoaquín Ignacio Aramendía 	.driver = {
289ed264e8aSJoaquín Ignacio Aramendía 		.name = "oxp-platform",
290ed264e8aSJoaquín Ignacio Aramendía 	},
291ed264e8aSJoaquín Ignacio Aramendía 	.probe = oxp_platform_probe,
292ed264e8aSJoaquín Ignacio Aramendía };
293ed264e8aSJoaquín Ignacio Aramendía 
294ed264e8aSJoaquín Ignacio Aramendía static struct platform_device *oxp_platform_device;
295ed264e8aSJoaquín Ignacio Aramendía 
296ed264e8aSJoaquín Ignacio Aramendía static int __init oxp_platform_init(void)
297ed264e8aSJoaquín Ignacio Aramendía {
298ed264e8aSJoaquín Ignacio Aramendía 	oxp_platform_device =
299ed264e8aSJoaquín Ignacio Aramendía 		platform_create_bundle(&oxp_platform_driver,
300ed264e8aSJoaquín Ignacio Aramendía 				       oxp_platform_probe, NULL, 0, NULL, 0);
301ed264e8aSJoaquín Ignacio Aramendía 
302ed264e8aSJoaquín Ignacio Aramendía 	return PTR_ERR_OR_ZERO(oxp_platform_device);
303ed264e8aSJoaquín Ignacio Aramendía }
304ed264e8aSJoaquín Ignacio Aramendía 
305ed264e8aSJoaquín Ignacio Aramendía static void __exit oxp_platform_exit(void)
306ed264e8aSJoaquín Ignacio Aramendía {
307ed264e8aSJoaquín Ignacio Aramendía 	platform_device_unregister(oxp_platform_device);
308ed264e8aSJoaquín Ignacio Aramendía 	platform_driver_unregister(&oxp_platform_driver);
309ed264e8aSJoaquín Ignacio Aramendía }
310ed264e8aSJoaquín Ignacio Aramendía 
311ed264e8aSJoaquín Ignacio Aramendía MODULE_DEVICE_TABLE(dmi, dmi_table);
312ed264e8aSJoaquín Ignacio Aramendía 
313ed264e8aSJoaquín Ignacio Aramendía module_init(oxp_platform_init);
314ed264e8aSJoaquín Ignacio Aramendía module_exit(oxp_platform_exit);
315ed264e8aSJoaquín Ignacio Aramendía 
316ed264e8aSJoaquín Ignacio Aramendía MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>");
317ed264e8aSJoaquín Ignacio Aramendía MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices");
318ed264e8aSJoaquín Ignacio Aramendía MODULE_LICENSE("GPL");
319