1164633Ssam/*
2164633Ssam * Support for the GPIO/IRQ expander chips present on several HTC phones.
3164633Ssam * These are implemented in CPLD chips present on the board.
4206358Srpaulo *
5164633Ssam * Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net>
6164633Ssam * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
7164633Ssam *
8164633Ssam * This file may be distributed under the terms of the GNU GPL license.
9164633Ssam */
10164633Ssam
11164633Ssam#include <linux/kernel.h>
12164633Ssam#include <linux/errno.h>
13164633Ssam#include <linux/interrupt.h>
14164633Ssam#include <linux/irq.h>
15164633Ssam#include <linux/io.h>
16164633Ssam#include <linux/spinlock.h>
17164633Ssam#include <linux/platform_data/gpio-htc-egpio.h>
18164633Ssam#include <linux/platform_device.h>
19164633Ssam#include <linux/slab.h>
20164633Ssam#include <linux/init.h>
21164633Ssam#include <linux/gpio/driver.h>
22164633Ssam
23164633Ssamstruct egpio_chip {
24164633Ssam	int              reg_start;
25164633Ssam	int              cached_values;
26164633Ssam	unsigned long    is_out;
27164633Ssam	struct device    *dev;
28164633Ssam	struct gpio_chip chip;
29164633Ssam};
30164633Ssam
31164633Ssamstruct egpio_info {
32178354Ssam	spinlock_t        lock;
33178354Ssam
34164633Ssam	/* iomem info */
35164633Ssam	void __iomem      *base_addr;
36295126Sglebius	int               bus_shift;	/* byte shift */
37164633Ssam	int               reg_shift;	/* bit shift */
38296925Sadrian	int               reg_mask;
39164633Ssam
40164633Ssam	/* irq info */
41164633Ssam	int               ack_register;
42164633Ssam	int               ack_write;
43257176Sglebius	u16               irqs_enabled;
44164633Ssam	uint              irq_start;
45257241Sglebius	int               nirqs;
46164633Ssam	uint              chained_irq;
47164633Ssam
48164633Ssam	/* egpio info */
49164633Ssam	struct egpio_chip *chip;
50164633Ssam	int               nchips;
51164633Ssam};
52164633Ssam
53252727Sadrianstatic inline void egpio_writew(u16 value, struct egpio_info *ei, int reg)
54164633Ssam{
55206358Srpaulo	writew(value, ei->base_addr + (reg << ei->bus_shift));
56164633Ssam}
57164633Ssam
58164633Ssamstatic inline u16 egpio_readw(struct egpio_info *ei, int reg)
59164633Ssam{
60164633Ssam	return readw(ei->base_addr + (reg << ei->bus_shift));
61164633Ssam}
62164633Ssam
63164633Ssam/*
64206358Srpaulo * IRQs
65206358Srpaulo */
66206358Srpaulo
67206358Srpaulostatic inline void ack_irqs(struct egpio_info *ei)
68206358Srpaulo{
69206358Srpaulo	egpio_writew(ei->ack_write, ei, ei->ack_register);
70206358Srpaulo	pr_debug("EGPIO ack - write %x to base+%x\n",
71206358Srpaulo			ei->ack_write, ei->ack_register << ei->bus_shift);
72206358Srpaulo}
73206358Srpaulo
74206358Srpaulostatic void egpio_ack(struct irq_data *data)
75206358Srpaulo{
76206358Srpaulo}
77206358Srpaulo
78206358Srpaulo/* There does not appear to be a way to proactively mask interrupts
79296925Sadrian * on the egpio chip itself.  So, we simply ignore interrupts that
80178354Ssam * aren't desired. */
81178354Ssamstatic void egpio_mask(struct irq_data *data)
82178354Ssam{
83178354Ssam	struct egpio_info *ei = irq_data_get_irq_chip_data(data);
84206358Srpaulo	ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start));
85206358Srpaulo	pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled);
86206358Srpaulo}
87206358Srpaulo
88206358Srpaulostatic void egpio_unmask(struct irq_data *data)
89206358Srpaulo{
90206358Srpaulo	struct egpio_info *ei = irq_data_get_irq_chip_data(data);
91206358Srpaulo	ei->irqs_enabled |= 1 << (data->irq - ei->irq_start);
92206358Srpaulo	pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled);
93206358Srpaulo}
94206358Srpaulo
95206358Srpaulostatic struct irq_chip egpio_muxed_chip = {
96296925Sadrian	.name		= "htc-egpio",
97206358Srpaulo	.irq_ack	= egpio_ack,
98206358Srpaulo	.irq_mask	= egpio_mask,
99206358Srpaulo	.irq_unmask	= egpio_unmask,
100206358Srpaulo};
101206358Srpaulo
102206358Srpaulostatic void egpio_handler(struct irq_desc *desc)
103178354Ssam{
104206358Srpaulo	struct egpio_info *ei = irq_desc_get_handler_data(desc);
105178354Ssam	int irqpin;
106178354Ssam
107343035Savos	/* Read current pins. */
108343035Savos	unsigned long readval = egpio_readw(ei, ei->ack_register);
109343035Savos	pr_debug("IRQ reg: %x\n", (unsigned int)readval);
110178354Ssam	/* Ack/unmask interrupts. */
111178354Ssam	ack_irqs(ei);
112178354Ssam	/* Process all set pins. */
113178354Ssam	readval &= ei->irqs_enabled;
114178354Ssam	for_each_set_bit(irqpin, &readval, ei->nirqs) {
115178354Ssam		/* Run irq handler */
116206358Srpaulo		pr_debug("got IRQ %d\n", irqpin);
117206358Srpaulo		generic_handle_irq(ei->irq_start + irqpin);
118164633Ssam	}
119206358Srpaulo}
120178354Ssam
121206358Srpaulostatic inline int egpio_pos(struct egpio_info *ei, int bit)
122206358Srpaulo{
123321724Savos	return bit >> ei->reg_shift;
124283538Sadrian}
125283538Sadrian
126206419Srpaulostatic inline int egpio_bit(struct egpio_info *ei, int bit)
127206419Srpaulo{
128206419Srpaulo	return 1 << (bit & ((1 << ei->reg_shift)-1));
129206419Srpaulo}
130206358Srpaulo
131206358Srpaulo/*
132206358Srpaulo * Input pins
133206358Srpaulo */
134164633Ssam
135164633Ssamstatic int egpio_get(struct gpio_chip *chip, unsigned offset)
136206358Srpaulo{
137206358Srpaulo	struct egpio_chip *egpio;
138178354Ssam	struct egpio_info *ei;
139283538Sadrian	unsigned           bit;
140321724Savos	int                reg;
141321724Savos	int                value;
142178354Ssam
143178354Ssam	pr_debug("egpio_get_value(%d)\n", chip->base + offset);
144257412Sadrian
145257412Sadrian	egpio = gpiochip_get_data(chip);
146257412Sadrian	ei    = dev_get_drvdata(egpio->dev);
147257412Sadrian	bit   = egpio_bit(ei, offset);
148257412Sadrian	reg   = egpio->reg_start + egpio_pos(ei, offset);
149257412Sadrian
150252727Sadrian	if (test_bit(offset, &egpio->is_out)) {
151252727Sadrian		return !!(egpio->cached_values & (1 << offset));
152252727Sadrian	} else {
153252727Sadrian		value = egpio_readw(ei, reg);
154252727Sadrian		pr_debug("readw(%p + %x) = %x\n",
155252727Sadrian			 ei->base_addr, reg << ei->bus_shift, value);
156252727Sadrian		return !!(value & bit);
157252727Sadrian	}
158257412Sadrian}
159257412Sadrian
160252727Sadrianstatic int egpio_direction_input(struct gpio_chip *chip, unsigned offset)
161252727Sadrian{
162252727Sadrian	struct egpio_chip *egpio;
163206358Srpaulo
164206358Srpaulo	egpio = gpiochip_get_data(chip);
165164633Ssam	return test_bit(offset, &egpio->is_out) ? -EINVAL : 0;
166252727Sadrian}
167206358Srpaulo
168206358Srpaulo
169206358Srpaulo/*
170252727Sadrian * Output pins
171178354Ssam */
172343035Savos
173343035Savosstatic void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
174343035Savos{
175343035Savos	unsigned long     flag;
176343035Savos	struct egpio_chip *egpio;
177343035Savos	struct egpio_info *ei;
178207323Srpaulo	int               pos;
179283538Sadrian	int               reg;
180283538Sadrian	int               shift;
181207323Srpaulo
182207323Srpaulo	pr_debug("egpio_set(%s, %d(%d), %d)\n",
183207323Srpaulo			chip->label, offset, offset+chip->base, value);
184207323Srpaulo
185207323Srpaulo	egpio = gpiochip_get_data(chip);
186207323Srpaulo	ei    = dev_get_drvdata(egpio->dev);
187207323Srpaulo	pos   = egpio_pos(ei, offset);
188178354Ssam	reg   = egpio->reg_start + pos;
189164633Ssam	shift = pos << ei->reg_shift;
190164633Ssam
191164633Ssam	pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear",
192164633Ssam			reg, (egpio->cached_values >> shift) & ei->reg_mask);
193178354Ssam
194252727Sadrian	spin_lock_irqsave(&ei->lock, flag);
195252727Sadrian	if (value)
196252727Sadrian		egpio->cached_values |= (1 << offset);
197252727Sadrian	else
198252727Sadrian		egpio->cached_values &= ~(1 << offset);
199252727Sadrian	egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg);
200252727Sadrian	spin_unlock_irqrestore(&ei->lock, flag);
201252727Sadrian}
202252727Sadrian
203252727Sadrianstatic int egpio_direction_output(struct gpio_chip *chip,
204252727Sadrian					unsigned offset, int value)
205252727Sadrian{
206252727Sadrian	struct egpio_chip *egpio;
207252727Sadrian
208252727Sadrian	egpio = gpiochip_get_data(chip);
209252727Sadrian	if (test_bit(offset, &egpio->is_out)) {
210252727Sadrian		egpio_set(chip, offset, value);
211252727Sadrian		return 0;
212252727Sadrian	} else {
213252727Sadrian		return -EINVAL;
214270206Sadrian	}
215252727Sadrian}
216252727Sadrian
217252727Sadrianstatic int egpio_get_direction(struct gpio_chip *chip, unsigned offset)
218270206Sadrian{
219257881Sadrian	struct egpio_chip *egpio;
220270206Sadrian
221257881Sadrian	egpio = gpiochip_get_data(chip);
222257881Sadrian
223252727Sadrian	if (test_bit(offset, &egpio->is_out))
224252727Sadrian		return GPIO_LINE_DIRECTION_OUT;
225257881Sadrian
226252727Sadrian	return GPIO_LINE_DIRECTION_IN;
227252727Sadrian}
228252727Sadrian
229252727Sadrianstatic void egpio_write_cache(struct egpio_info *ei)
230252727Sadrian{
231252727Sadrian	int               i;
232252727Sadrian	struct egpio_chip *egpio;
233178354Ssam	int               shift;
234178354Ssam
235302307Sadrian	for (i = 0; i < ei->nchips; i++) {
236302307Sadrian		egpio = &(ei->chip[i]);
237178354Ssam		if (!egpio->is_out)
238302307Sadrian			continue;
239252727Sadrian
240302307Sadrian		for (shift = 0; shift < egpio->chip.ngpio;
241302307Sadrian				shift += (1<<ei->reg_shift)) {
242164633Ssam
243164633Ssam			int reg = egpio->reg_start + egpio_pos(ei, shift);
244206358Srpaulo
245206358Srpaulo			if (!((egpio->is_out >> shift) & ei->reg_mask))
246206358Srpaulo				continue;
247283538Sadrian
248206358Srpaulo			pr_debug("EGPIO: setting %x to %x, was %x\n", reg,
249206358Srpaulo				(egpio->cached_values >> shift) & ei->reg_mask,
250178354Ssam				egpio_readw(ei, reg));
251178354Ssam
252178354Ssam			egpio_writew((egpio->cached_values >> shift)
253164633Ssam					& ei->reg_mask, ei, reg);
254178354Ssam		}
255252727Sadrian	}
256164633Ssam}
257178354Ssam
258178354Ssam
259252727Sadrian/*
260252727Sadrian * Setup
261252727Sadrian */
262252727Sadrian
263252727Sadrianstatic int __init egpio_probe(struct platform_device *pdev)
264252727Sadrian{
265252727Sadrian	struct htc_egpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
266252727Sadrian	struct resource   *res;
267302307Sadrian	struct egpio_info *ei;
268302307Sadrian	struct gpio_chip  *chip;
269252727Sadrian	unsigned int      irq, irq_end;
270252727Sadrian	int               i;
271252727Sadrian
272252727Sadrian	/* Initialize ei data structure. */
273252727Sadrian	ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
274252727Sadrian	if (!ei)
275252736Sadrian		return -ENOMEM;
276252736Sadrian
277252736Sadrian	spin_lock_init(&ei->lock);
278252736Sadrian
279252736Sadrian	/* Find chained irq */
280252736Sadrian	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
281252736Sadrian	if (res)
282252736Sadrian		ei->chained_irq = res->start;
283178354Ssam
284164633Ssam	/* Map egpio chip into virtual address space. */
285164633Ssam	ei->base_addr = devm_platform_ioremap_resource(pdev, 0);
286252727Sadrian	if (IS_ERR(ei->base_addr))
287164633Ssam		return PTR_ERR(ei->base_addr);
288164633Ssam
289178354Ssam	if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
290302307Sadrian		return -EINVAL;
291302307Sadrian
292178354Ssam	ei->bus_shift = fls(pdata->bus_width - 1) - 3;
293178354Ssam	pr_debug("bus_shift = %d\n", ei->bus_shift);
294252727Sadrian
295164633Ssam	if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
296164633Ssam		return -EINVAL;
297164633Ssam
298164633Ssam	ei->reg_shift = fls(pdata->reg_width - 1);
299164633Ssam	pr_debug("reg_shift = %d\n", ei->reg_shift);
300164633Ssam
301178354Ssam	ei->reg_mask = (1 << pdata->reg_width) - 1;
302164633Ssam
303164633Ssam	platform_set_drvdata(pdev, ei);
304164633Ssam
305164633Ssam	ei->nchips = pdata->num_chips;
306164633Ssam	ei->chip = devm_kcalloc(&pdev->dev,
307164633Ssam				ei->nchips, sizeof(struct egpio_chip),
308164633Ssam				GFP_KERNEL);
309164633Ssam	if (!ei->chip)
310164633Ssam		return -ENOMEM;
311164633Ssam
312178354Ssam	for (i = 0; i < ei->nchips; i++) {
313302307Sadrian		ei->chip[i].reg_start = pdata->chip[i].reg_start;
314302307Sadrian		ei->chip[i].cached_values = pdata->chip[i].initial_values;
315178354Ssam		ei->chip[i].is_out = pdata->chip[i].direction;
316178354Ssam		ei->chip[i].dev = &(pdev->dev);
317252727Sadrian		chip = &(ei->chip[i].chip);
318164633Ssam		chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL,
319164633Ssam					     "htc-egpio-%d",
320164633Ssam					     i);
321164633Ssam		if (!chip->label)
322164633Ssam			return -ENOMEM;
323178354Ssam
324178354Ssam		chip->parent          = &pdev->dev;
325178354Ssam		chip->owner           = THIS_MODULE;
326178354Ssam		chip->get             = egpio_get;
327178354Ssam		chip->set             = egpio_set;
328164633Ssam		chip->direction_input = egpio_direction_input;
329164633Ssam		chip->direction_output = egpio_direction_output;
330164633Ssam		chip->get_direction   = egpio_get_direction;
331178354Ssam		chip->base            = pdata->chip[i].gpio_base;
332178354Ssam		chip->ngpio           = pdata->chip[i].num_gpios;
333178354Ssam
334164633Ssam		gpiochip_add_data(chip, &ei->chip[i]);
335206358Srpaulo	}
336206358Srpaulo
337178354Ssam	/* Set initial pin values */
338206358Srpaulo	egpio_write_cache(ei);
339343035Savos
340252727Sadrian	ei->irq_start = pdata->irq_base;
341178354Ssam	ei->nirqs = pdata->num_irqs;
342178354Ssam	ei->ack_register = pdata->ack_register;
343343035Savos
344343035Savos	if (ei->chained_irq) {
345343035Savos		/* Setup irq handlers */
346343035Savos		ei->ack_write = 0xFFFF;
347343035Savos		if (pdata->invert_acks)
348343035Savos			ei->ack_write = 0;
349343035Savos		irq_end = ei->irq_start + ei->nirqs;
350343035Savos		for (irq = ei->irq_start; irq < irq_end; irq++) {
351343035Savos			irq_set_chip_and_handler(irq, &egpio_muxed_chip,
352252727Sadrian						 handle_simple_irq);
353252727Sadrian			irq_set_chip_data(irq, ei);
354252727Sadrian			irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
355252727Sadrian		}
356252727Sadrian		irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING);
357252727Sadrian		irq_set_chained_handler_and_data(ei->chained_irq,
358252727Sadrian						 egpio_handler, ei);
359252727Sadrian		ack_irqs(ei);
360178354Ssam
361178354Ssam		device_init_wakeup(&pdev->dev, 1);
362178354Ssam	}
363178354Ssam
364252727Sadrian	return 0;
365252727Sadrian}
366252727Sadrian
367252727Sadrian#ifdef CONFIG_PM
368252727Sadrianstatic int egpio_suspend(struct platform_device *pdev, pm_message_t state)
369252727Sadrian{
370178354Ssam	struct egpio_info *ei = platform_get_drvdata(pdev);
371178354Ssam
372178354Ssam	if (ei->chained_irq && device_may_wakeup(&pdev->dev))
373178354Ssam		enable_irq_wake(ei->chained_irq);
374178354Ssam	return 0;
375178354Ssam}
376178354Ssam
377178354Ssamstatic int egpio_resume(struct platform_device *pdev)
378206358Srpaulo{
379206358Srpaulo	struct egpio_info *ei = platform_get_drvdata(pdev);
380206358Srpaulo
381206358Srpaulo	if (ei->chained_irq && device_may_wakeup(&pdev->dev))
382206358Srpaulo		disable_irq_wake(ei->chained_irq);
383206358Srpaulo
384206358Srpaulo	/* Update registers from the cache, in case
385206358Srpaulo	   the CPLD was powered off during suspend */
386206358Srpaulo	egpio_write_cache(ei);
387206358Srpaulo	return 0;
388206358Srpaulo}
389206358Srpaulo#else
390206358Srpaulo#define egpio_suspend NULL
391343035Savos#define egpio_resume NULL
392343035Savos#endif
393343035Savos
394206358Srpaulo
395206358Srpaulostatic struct platform_driver egpio_driver = {
396206358Srpaulo	.driver = {
397206358Srpaulo		.name = "htc-egpio",
398206358Srpaulo		.suppress_bind_attrs = true,
399206358Srpaulo	},
400206358Srpaulo	.suspend      = egpio_suspend,
401206358Srpaulo	.resume       = egpio_resume,
402206358Srpaulo};
403206358Srpaulo
404206358Srpaulostatic int __init egpio_init(void)
405206358Srpaulo{
406206358Srpaulo	return platform_driver_probe(&egpio_driver, egpio_probe);
407206358Srpaulo}
408206358Srpaulo/* start early for dependencies */
409206358Srpaulosubsys_initcall(egpio_init);
410206358Srpaulo