xref: /linux/drivers/platform/x86/barco-p50-gpio.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1 // SPDX-License-Identifier: GPL-2.0+
2 
3 /*
4  * Support for EC-connected GPIOs for identify
5  * LED/button on Barco P50 board
6  *
7  * Copyright (C) 2021 Barco NV
8  * Author: Santosh Kumar Yadav <santoshkumar.yadav@barco.com>
9  */
10 
11 #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
12 
13 #include <linux/delay.h>
14 #include <linux/dev_printk.h>
15 #include <linux/dmi.h>
16 #include <linux/err.h>
17 #include <linux/io.h>
18 #include <linux/kernel.h>
19 #include <linux/leds.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
22 #include <linux/gpio/driver.h>
23 #include <linux/gpio/machine.h>
24 #include <linux/gpio/property.h>
25 #include <linux/input-event-codes.h>
26 #include <linux/property.h>
27 
28 
29 #define DRIVER_NAME		"barco-p50-gpio"
30 
31 /* GPIO lines */
32 #define P50_GPIO_LINE_LED	0
33 #define P50_GPIO_LINE_BTN	1
34 
35 /* GPIO IO Ports */
36 #define P50_GPIO_IO_PORT_BASE	0x299
37 
38 #define P50_PORT_DATA		0x00
39 #define P50_PORT_CMD		0x01
40 
41 #define P50_STATUS_OBF		0x01 /* EC output buffer full */
42 #define P50_STATUS_IBF		0x02 /* EC input buffer full */
43 
44 #define P50_CMD_READ		0xa0
45 #define P50_CMD_WRITE		0x50
46 
47 /* EC mailbox registers */
48 #define P50_MBOX_REG_CMD	0x00
49 #define P50_MBOX_REG_STATUS	0x01
50 #define P50_MBOX_REG_PARAM	0x02
51 #define P50_MBOX_REG_DATA	0x03
52 
53 #define P50_MBOX_CMD_READ_GPIO	0x11
54 #define P50_MBOX_CMD_WRITE_GPIO	0x12
55 #define P50_MBOX_CMD_CLEAR	0xff
56 
57 #define P50_MBOX_STATUS_SUCCESS	0x01
58 
59 #define P50_MBOX_PARAM_LED	0x12
60 #define P50_MBOX_PARAM_BTN	0x13
61 
62 
63 struct p50_gpio {
64 	struct gpio_chip gc;
65 	struct mutex lock;
66 	unsigned long base;
67 	struct platform_device *leds_pdev;
68 	struct platform_device *keys_pdev;
69 };
70 
71 static struct platform_device *gpio_pdev;
72 
73 static int gpio_params[] = {
74 	[P50_GPIO_LINE_LED] = P50_MBOX_PARAM_LED,
75 	[P50_GPIO_LINE_BTN] = P50_MBOX_PARAM_BTN,
76 };
77 
78 static const char * const gpio_names[] = {
79 	[P50_GPIO_LINE_LED] = "identify-led",
80 	[P50_GPIO_LINE_BTN] = "identify-button",
81 };
82 
83 static const struct software_node gpiochip_node = {
84 	.name = DRIVER_NAME,
85 };
86 
87 /* GPIO LEDs */
88 static const struct software_node gpio_leds_node = {
89 	.name = "gpio-leds-identify",
90 };
91 
92 static const struct property_entry identify_led_props[] = {
93 	PROPERTY_ENTRY_GPIO("gpios", &gpiochip_node, P50_GPIO_LINE_LED, GPIO_ACTIVE_HIGH),
94 	{ }
95 };
96 
97 static const struct software_node identify_led_node = {
98 	.parent = &gpio_leds_node,
99 	.name = "identify",
100 	.properties = identify_led_props,
101 };
102 
103 /* GPIO keyboard */
104 static const struct property_entry gpio_keys_props[] = {
105 	PROPERTY_ENTRY_STRING("label", "identify"),
106 	PROPERTY_ENTRY_U32("poll-interval", 100),
107 	{ }
108 };
109 
110 static const struct software_node gpio_keys_node = {
111 	.name = "gpio-keys-identify",
112 	.properties = gpio_keys_props,
113 };
114 
115 static struct property_entry vendor_key_props[] = {
116 	PROPERTY_ENTRY_U32("linux,code", KEY_VENDOR),
117 	PROPERTY_ENTRY_GPIO("gpios", &gpiochip_node, P50_GPIO_LINE_BTN, GPIO_ACTIVE_LOW),
118 	{ }
119 };
120 
121 static const struct software_node vendor_key_node = {
122 	.parent = &gpio_keys_node,
123 	.properties = vendor_key_props,
124 };
125 
126 static const struct software_node *p50_swnodes[] = {
127 	&gpiochip_node,
128 	&gpio_leds_node,
129 	&identify_led_node,
130 	&gpio_keys_node,
131 	&vendor_key_node,
132 	NULL
133 };
134 
135 /* low level access routines */
136 
p50_wait_ec(struct p50_gpio * p50,int mask,int expected)137 static int p50_wait_ec(struct p50_gpio *p50, int mask, int expected)
138 {
139 	int i, val;
140 
141 	for (i = 0; i < 100; i++) {
142 		val = inb(p50->base + P50_PORT_CMD) & mask;
143 		if (val == expected)
144 			return 0;
145 		usleep_range(500, 2000);
146 	}
147 
148 	dev_err(p50->gc.parent, "Timed out waiting for EC (0x%x)\n", val);
149 	return -ETIMEDOUT;
150 }
151 
152 
p50_read_mbox_reg(struct p50_gpio * p50,int reg)153 static int p50_read_mbox_reg(struct p50_gpio *p50, int reg)
154 {
155 	int ret;
156 
157 	ret = p50_wait_ec(p50, P50_STATUS_IBF, 0);
158 	if (ret)
159 		return ret;
160 
161 	/* clear output buffer flag, prevent unfinished commands */
162 	inb(p50->base + P50_PORT_DATA);
163 
164 	/* cmd/address */
165 	outb(P50_CMD_READ | reg, p50->base + P50_PORT_CMD);
166 
167 	ret = p50_wait_ec(p50, P50_STATUS_OBF, P50_STATUS_OBF);
168 	if (ret)
169 		return ret;
170 
171 	return inb(p50->base + P50_PORT_DATA);
172 }
173 
p50_write_mbox_reg(struct p50_gpio * p50,int reg,int val)174 static int p50_write_mbox_reg(struct p50_gpio *p50, int reg, int val)
175 {
176 	int ret;
177 
178 	ret = p50_wait_ec(p50, P50_STATUS_IBF, 0);
179 	if (ret)
180 		return ret;
181 
182 	/* cmd/address */
183 	outb(P50_CMD_WRITE | reg, p50->base + P50_PORT_CMD);
184 
185 	ret = p50_wait_ec(p50, P50_STATUS_IBF, 0);
186 	if (ret)
187 		return ret;
188 
189 	/* data */
190 	outb(val, p50->base + P50_PORT_DATA);
191 
192 	return 0;
193 }
194 
195 
196 /* mbox routines */
197 
p50_wait_mbox_idle(struct p50_gpio * p50)198 static int p50_wait_mbox_idle(struct p50_gpio *p50)
199 {
200 	int i, val;
201 
202 	for (i = 0; i < 1000; i++) {
203 		val = p50_read_mbox_reg(p50, P50_MBOX_REG_CMD);
204 		/* cmd is 0 when idle */
205 		if (val <= 0)
206 			return val;
207 
208 		usleep_range(500, 2000);
209 	}
210 
211 	dev_err(p50->gc.parent,	"Timed out waiting for EC mbox idle (CMD: 0x%x)\n", val);
212 
213 	return -ETIMEDOUT;
214 }
215 
p50_send_mbox_cmd(struct p50_gpio * p50,int cmd,int param,int data)216 static int p50_send_mbox_cmd(struct p50_gpio *p50, int cmd, int param, int data)
217 {
218 	int ret;
219 
220 	ret = p50_wait_mbox_idle(p50);
221 	if (ret)
222 		return ret;
223 
224 	ret = p50_write_mbox_reg(p50, P50_MBOX_REG_DATA, data);
225 	if (ret)
226 		return ret;
227 
228 	ret = p50_write_mbox_reg(p50, P50_MBOX_REG_PARAM, param);
229 	if (ret)
230 		return ret;
231 
232 	ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, cmd);
233 	if (ret)
234 		return ret;
235 
236 	ret = p50_wait_mbox_idle(p50);
237 	if (ret)
238 		return ret;
239 
240 	ret = p50_read_mbox_reg(p50, P50_MBOX_REG_STATUS);
241 	if (ret < 0)
242 		return ret;
243 
244 	if (ret == P50_MBOX_STATUS_SUCCESS)
245 		return 0;
246 
247 	dev_err(p50->gc.parent,	"Mbox command failed (CMD=0x%x STAT=0x%x PARAM=0x%x DATA=0x%x)\n",
248 		cmd, ret, param, data);
249 
250 	return -EIO;
251 }
252 
253 
254 /* gpio routines */
255 
p50_gpio_get_direction(struct gpio_chip * gc,unsigned int offset)256 static int p50_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
257 {
258 	switch (offset) {
259 	case P50_GPIO_LINE_BTN:
260 		return GPIO_LINE_DIRECTION_IN;
261 
262 	case P50_GPIO_LINE_LED:
263 		return GPIO_LINE_DIRECTION_OUT;
264 
265 	default:
266 		return -EINVAL;
267 	}
268 }
269 
p50_gpio_get(struct gpio_chip * gc,unsigned int offset)270 static int p50_gpio_get(struct gpio_chip *gc, unsigned int offset)
271 {
272 	struct p50_gpio *p50 = gpiochip_get_data(gc);
273 	int ret;
274 
275 	guard(mutex)(&p50->lock);
276 
277 	ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_READ_GPIO, gpio_params[offset], 0);
278 	if (ret < 0)
279 		return ret;
280 
281 	ret = p50_read_mbox_reg(p50, P50_MBOX_REG_DATA);
282 	if (ret < 0)
283 		return ret;
284 
285 	return !!ret;
286 }
287 
p50_gpio_set(struct gpio_chip * gc,unsigned int offset,int value)288 static int p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
289 {
290 	struct p50_gpio *p50 = gpiochip_get_data(gc);
291 
292 	guard(mutex)(&p50->lock);
293 
294 	return p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO,
295 				 gpio_params[offset], value);
296 }
297 
p50_gpio_probe(struct platform_device * pdev)298 static int p50_gpio_probe(struct platform_device *pdev)
299 {
300 	struct platform_device_info key_info = {
301 		.name	= "gpio-keys-polled",
302 		.id	= PLATFORM_DEVID_NONE,
303 		.parent	= &pdev->dev,
304 	};
305 	struct platform_device_info led_info = {
306 		.name	= "leds-gpio",
307 		.id	= PLATFORM_DEVID_NONE,
308 		.parent	= &pdev->dev,
309 	};
310 	struct p50_gpio *p50;
311 	struct resource *res;
312 	int ret;
313 
314 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
315 	if (!res) {
316 		dev_err(&pdev->dev, "Cannot get I/O ports\n");
317 		return -ENODEV;
318 	}
319 
320 	if (!devm_request_region(&pdev->dev, res->start, resource_size(res), pdev->name)) {
321 		dev_err(&pdev->dev, "Unable to reserve I/O region\n");
322 		return -EBUSY;
323 	}
324 
325 	p50 = devm_kzalloc(&pdev->dev, sizeof(*p50), GFP_KERNEL);
326 	if (!p50)
327 		return -ENOMEM;
328 
329 	platform_set_drvdata(pdev, p50);
330 	mutex_init(&p50->lock);
331 	p50->base = res->start;
332 	p50->gc.owner = THIS_MODULE;
333 	p50->gc.parent = &pdev->dev;
334 	p50->gc.label = dev_name(&pdev->dev);
335 	p50->gc.ngpio = ARRAY_SIZE(gpio_names);
336 	p50->gc.names = gpio_names;
337 	p50->gc.can_sleep = true;
338 	p50->gc.base = -1;
339 	p50->gc.get_direction = p50_gpio_get_direction;
340 	p50->gc.get = p50_gpio_get;
341 	p50->gc.set = p50_gpio_set;
342 
343 
344 	/* reset mbox */
345 	ret = p50_wait_mbox_idle(p50);
346 	if (ret)
347 		return ret;
348 
349 	ret = p50_write_mbox_reg(p50, P50_MBOX_REG_CMD, P50_MBOX_CMD_CLEAR);
350 	if (ret)
351 		return ret;
352 
353 	ret = p50_wait_mbox_idle(p50);
354 	if (ret)
355 		return ret;
356 
357 
358 	ret = devm_gpiochip_add_data(&pdev->dev, &p50->gc, p50);
359 	if (ret < 0) {
360 		dev_err(&pdev->dev, "Could not register gpiochip: %d\n", ret);
361 		return ret;
362 	}
363 
364 	ret = software_node_register_node_group(p50_swnodes);
365 	if (ret)
366 		return dev_err_probe(&pdev->dev, ret, "failed to register software nodes");
367 
368 	led_info.fwnode = software_node_fwnode(&gpio_leds_node);
369 	p50->leds_pdev = platform_device_register_full(&led_info);
370 	if (IS_ERR(p50->leds_pdev)) {
371 		ret = PTR_ERR(p50->leds_pdev);
372 		dev_err(&pdev->dev, "Could not register leds-gpio: %d\n", ret);
373 		goto err_leds;
374 	}
375 
376 	key_info.fwnode = software_node_fwnode(&gpio_keys_node);
377 	p50->keys_pdev = platform_device_register_full(&key_info);
378 	if (IS_ERR(p50->keys_pdev)) {
379 		ret = PTR_ERR(p50->keys_pdev);
380 		dev_err(&pdev->dev, "Could not register gpio-keys-polled: %d\n", ret);
381 		goto err_keys;
382 	}
383 
384 	return 0;
385 
386 err_keys:
387 	platform_device_unregister(p50->leds_pdev);
388 err_leds:
389 	software_node_unregister_node_group(p50_swnodes);
390 
391 	return ret;
392 }
393 
p50_gpio_remove(struct platform_device * pdev)394 static void p50_gpio_remove(struct platform_device *pdev)
395 {
396 	struct p50_gpio *p50 = platform_get_drvdata(pdev);
397 
398 	platform_device_unregister(p50->keys_pdev);
399 	platform_device_unregister(p50->leds_pdev);
400 
401 	software_node_unregister_node_group(p50_swnodes);
402 }
403 
404 static struct platform_driver p50_gpio_driver = {
405 	.driver = {
406 		.name = DRIVER_NAME,
407 	},
408 	.probe = p50_gpio_probe,
409 	.remove = p50_gpio_remove,
410 };
411 
412 /* Board setup */
413 static const struct dmi_system_id dmi_ids[] __initconst = {
414 	{
415 		.matches = {
416 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Barco"),
417 			DMI_EXACT_MATCH(DMI_PRODUCT_FAMILY, "P50")
418 		},
419 	},
420 	{}
421 };
422 MODULE_DEVICE_TABLE(dmi, dmi_ids);
423 
p50_module_init(void)424 static int __init p50_module_init(void)
425 {
426 	struct resource res = DEFINE_RES_IO(P50_GPIO_IO_PORT_BASE, P50_PORT_CMD + 1);
427 	int ret;
428 
429 	if (!dmi_first_match(dmi_ids))
430 		return -ENODEV;
431 
432 	ret = platform_driver_register(&p50_gpio_driver);
433 	if (ret)
434 		return ret;
435 
436 	gpio_pdev = platform_device_register_simple(DRIVER_NAME, PLATFORM_DEVID_NONE, &res, 1);
437 	if (IS_ERR(gpio_pdev)) {
438 		pr_err("failed registering %s: %ld\n", DRIVER_NAME, PTR_ERR(gpio_pdev));
439 		platform_driver_unregister(&p50_gpio_driver);
440 		return PTR_ERR(gpio_pdev);
441 	}
442 
443 	return 0;
444 }
445 
p50_module_exit(void)446 static void __exit p50_module_exit(void)
447 {
448 	platform_device_unregister(gpio_pdev);
449 	platform_driver_unregister(&p50_gpio_driver);
450 }
451 
452 module_init(p50_module_init);
453 module_exit(p50_module_exit);
454 
455 MODULE_AUTHOR("Santosh Kumar Yadav, Barco NV <santoshkumar.yadav@barco.com>");
456 MODULE_DESCRIPTION("Barco P50 identify GPIOs driver");
457 MODULE_LICENSE("GPL");
458