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