1/*
2 * Copyright (C) ST-Ericsson SA 2010
3 *
4 * License Terms: GNU General Public License, version 2
5 * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
6 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
7 */
8
9#include <linux/module.h>
10#include <linux/init.h>
11#include <linux/platform_device.h>
12#include <linux/slab.h>
13#include <linux/gpio.h>
14#include <linux/of.h>
15#include <linux/interrupt.h>
16#include <linux/mfd/tc3589x.h>
17
18/*
19 * These registers are modified under the irq bus lock and cached to avoid
20 * unnecessary writes in bus_sync_unlock.
21 */
22enum { REG_IBE, REG_IEV, REG_IS, REG_IE };
23
24#define CACHE_NR_REGS	4
25#define CACHE_NR_BANKS	3
26
27struct tc3589x_gpio {
28	struct gpio_chip chip;
29	struct tc3589x *tc3589x;
30	struct device *dev;
31	struct mutex irq_lock;
32	/* Caches of interrupt control registers for bus_lock */
33	u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
34	u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
35};
36
37static inline struct tc3589x_gpio *to_tc3589x_gpio(struct gpio_chip *chip)
38{
39	return container_of(chip, struct tc3589x_gpio, chip);
40}
41
42static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset)
43{
44	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
45	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
46	u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
47	u8 mask = 1 << (offset % 8);
48	int ret;
49
50	ret = tc3589x_reg_read(tc3589x, reg);
51	if (ret < 0)
52		return ret;
53
54	return ret & mask;
55}
56
57static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
58{
59	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
60	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
61	u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
62	unsigned pos = offset % 8;
63	u8 data[] = {!!val << pos, 1 << pos};
64
65	tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data);
66}
67
68static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
69					 unsigned offset, int val)
70{
71	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
72	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
73	u8 reg = TC3589x_GPIODIR0 + offset / 8;
74	unsigned pos = offset % 8;
75
76	tc3589x_gpio_set(chip, offset, val);
77
78	return tc3589x_set_bits(tc3589x, reg, 1 << pos, 1 << pos);
79}
80
81static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
82					unsigned offset)
83{
84	struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
85	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
86	u8 reg = TC3589x_GPIODIR0 + offset / 8;
87	unsigned pos = offset % 8;
88
89	return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0);
90}
91
92static struct gpio_chip template_chip = {
93	.label			= "tc3589x",
94	.owner			= THIS_MODULE,
95	.direction_input	= tc3589x_gpio_direction_input,
96	.get			= tc3589x_gpio_get,
97	.direction_output	= tc3589x_gpio_direction_output,
98	.set			= tc3589x_gpio_set,
99	.can_sleep		= true,
100};
101
102static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
103{
104	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
105	struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
106	int offset = d->hwirq;
107	int regoffset = offset / 8;
108	int mask = 1 << (offset % 8);
109
110	if (type == IRQ_TYPE_EDGE_BOTH) {
111		tc3589x_gpio->regs[REG_IBE][regoffset] |= mask;
112		return 0;
113	}
114
115	tc3589x_gpio->regs[REG_IBE][regoffset] &= ~mask;
116
117	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
118		tc3589x_gpio->regs[REG_IS][regoffset] |= mask;
119	else
120		tc3589x_gpio->regs[REG_IS][regoffset] &= ~mask;
121
122	if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
123		tc3589x_gpio->regs[REG_IEV][regoffset] |= mask;
124	else
125		tc3589x_gpio->regs[REG_IEV][regoffset] &= ~mask;
126
127	return 0;
128}
129
130static void tc3589x_gpio_irq_lock(struct irq_data *d)
131{
132	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
133	struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
134
135	mutex_lock(&tc3589x_gpio->irq_lock);
136}
137
138static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
139{
140	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
141	struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
142	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
143	static const u8 regmap[] = {
144		[REG_IBE]	= TC3589x_GPIOIBE0,
145		[REG_IEV]	= TC3589x_GPIOIEV0,
146		[REG_IS]	= TC3589x_GPIOIS0,
147		[REG_IE]	= TC3589x_GPIOIE0,
148	};
149	int i, j;
150
151	for (i = 0; i < CACHE_NR_REGS; i++) {
152		for (j = 0; j < CACHE_NR_BANKS; j++) {
153			u8 old = tc3589x_gpio->oldregs[i][j];
154			u8 new = tc3589x_gpio->regs[i][j];
155
156			if (new == old)
157				continue;
158
159			tc3589x_gpio->oldregs[i][j] = new;
160			tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new);
161		}
162	}
163
164	mutex_unlock(&tc3589x_gpio->irq_lock);
165}
166
167static void tc3589x_gpio_irq_mask(struct irq_data *d)
168{
169	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
170	struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
171	int offset = d->hwirq;
172	int regoffset = offset / 8;
173	int mask = 1 << (offset % 8);
174
175	tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask;
176}
177
178static void tc3589x_gpio_irq_unmask(struct irq_data *d)
179{
180	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
181	struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
182	int offset = d->hwirq;
183	int regoffset = offset / 8;
184	int mask = 1 << (offset % 8);
185
186	tc3589x_gpio->regs[REG_IE][regoffset] |= mask;
187}
188
189static struct irq_chip tc3589x_gpio_irq_chip = {
190	.name			= "tc3589x-gpio",
191	.irq_bus_lock		= tc3589x_gpio_irq_lock,
192	.irq_bus_sync_unlock	= tc3589x_gpio_irq_sync_unlock,
193	.irq_mask		= tc3589x_gpio_irq_mask,
194	.irq_unmask		= tc3589x_gpio_irq_unmask,
195	.irq_set_type		= tc3589x_gpio_irq_set_type,
196};
197
198static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
199{
200	struct tc3589x_gpio *tc3589x_gpio = dev;
201	struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
202	u8 status[CACHE_NR_BANKS];
203	int ret;
204	int i;
205
206	ret = tc3589x_block_read(tc3589x, TC3589x_GPIOMIS0,
207				 ARRAY_SIZE(status), status);
208	if (ret < 0)
209		return IRQ_NONE;
210
211	for (i = 0; i < ARRAY_SIZE(status); i++) {
212		unsigned int stat = status[i];
213		if (!stat)
214			continue;
215
216		while (stat) {
217			int bit = __ffs(stat);
218			int line = i * 8 + bit;
219			int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain,
220						   line);
221
222			handle_nested_irq(irq);
223			stat &= ~(1 << bit);
224		}
225
226		tc3589x_reg_write(tc3589x, TC3589x_GPIOIC0 + i, status[i]);
227	}
228
229	return IRQ_HANDLED;
230}
231
232static int tc3589x_gpio_probe(struct platform_device *pdev)
233{
234	struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
235	struct device_node *np = pdev->dev.of_node;
236	struct tc3589x_gpio *tc3589x_gpio;
237	int ret;
238	int irq;
239
240	if (!np) {
241		dev_err(&pdev->dev, "No Device Tree node found\n");
242		return -EINVAL;
243	}
244
245	irq = platform_get_irq(pdev, 0);
246	if (irq < 0)
247		return irq;
248
249	tc3589x_gpio = devm_kzalloc(&pdev->dev, sizeof(struct tc3589x_gpio),
250				    GFP_KERNEL);
251	if (!tc3589x_gpio)
252		return -ENOMEM;
253
254	mutex_init(&tc3589x_gpio->irq_lock);
255
256	tc3589x_gpio->dev = &pdev->dev;
257	tc3589x_gpio->tc3589x = tc3589x;
258
259	tc3589x_gpio->chip = template_chip;
260	tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
261	tc3589x_gpio->chip.dev = &pdev->dev;
262	tc3589x_gpio->chip.base = -1;
263	tc3589x_gpio->chip.of_node = np;
264
265	/* Bring the GPIO module out of reset */
266	ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
267			       TC3589x_RSTCTRL_GPIRST, 0);
268	if (ret < 0)
269		return ret;
270
271	ret = devm_request_threaded_irq(&pdev->dev,
272					irq, NULL, tc3589x_gpio_irq,
273					IRQF_ONESHOT, "tc3589x-gpio",
274					tc3589x_gpio);
275	if (ret) {
276		dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
277		return ret;
278	}
279
280	ret = gpiochip_add(&tc3589x_gpio->chip);
281	if (ret) {
282		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
283		return ret;
284	}
285
286	ret =  gpiochip_irqchip_add(&tc3589x_gpio->chip,
287				    &tc3589x_gpio_irq_chip,
288				    0,
289				    handle_simple_irq,
290				    IRQ_TYPE_NONE);
291	if (ret) {
292		dev_err(&pdev->dev,
293			"could not connect irqchip to gpiochip\n");
294		return ret;
295	}
296
297	gpiochip_set_chained_irqchip(&tc3589x_gpio->chip,
298				     &tc3589x_gpio_irq_chip,
299				     irq,
300				     NULL);
301
302	platform_set_drvdata(pdev, tc3589x_gpio);
303
304	return 0;
305}
306
307static int tc3589x_gpio_remove(struct platform_device *pdev)
308{
309	struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev);
310
311	gpiochip_remove(&tc3589x_gpio->chip);
312
313	return 0;
314}
315
316static struct platform_driver tc3589x_gpio_driver = {
317	.driver.name	= "tc3589x-gpio",
318	.driver.owner	= THIS_MODULE,
319	.probe		= tc3589x_gpio_probe,
320	.remove		= tc3589x_gpio_remove,
321};
322
323static int __init tc3589x_gpio_init(void)
324{
325	return platform_driver_register(&tc3589x_gpio_driver);
326}
327subsys_initcall(tc3589x_gpio_init);
328
329static void __exit tc3589x_gpio_exit(void)
330{
331	platform_driver_unregister(&tc3589x_gpio_driver);
332}
333module_exit(tc3589x_gpio_exit);
334
335MODULE_LICENSE("GPL v2");
336MODULE_DESCRIPTION("TC3589x GPIO driver");
337MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
338