1b868db94SAndrew Lunn // SPDX-License-Identifier: GPL-2.0
2b868db94SAndrew Lunn /*
3b868db94SAndrew Lunn * TQ-Systems TQMx86 PLD GPIO driver
4b868db94SAndrew Lunn *
5b868db94SAndrew Lunn * Based on vendor driver by:
6b868db94SAndrew Lunn * Vadim V.Vlasov <vvlasov@dev.rtsoft.ru>
7b868db94SAndrew Lunn */
8b868db94SAndrew Lunn
901aa7b7aSMatthias Schiffer #include <linux/bitmap.h>
10b868db94SAndrew Lunn #include <linux/bitops.h>
11b868db94SAndrew Lunn #include <linux/errno.h>
12b868db94SAndrew Lunn #include <linux/gpio/driver.h>
13b868db94SAndrew Lunn #include <linux/init.h>
14b868db94SAndrew Lunn #include <linux/interrupt.h>
15b868db94SAndrew Lunn #include <linux/kernel.h>
16b868db94SAndrew Lunn #include <linux/module.h>
17b868db94SAndrew Lunn #include <linux/platform_device.h>
18b868db94SAndrew Lunn #include <linux/pm_runtime.h>
198e43827bSLinus Walleij #include <linux/seq_file.h>
20b868db94SAndrew Lunn #include <linux/slab.h>
21b868db94SAndrew Lunn
22b868db94SAndrew Lunn #define TQMX86_NGPIO 8
23b868db94SAndrew Lunn #define TQMX86_NGPO 4 /* 0-3 - output */
24b868db94SAndrew Lunn #define TQMX86_NGPI 4 /* 4-7 - input */
25b868db94SAndrew Lunn #define TQMX86_DIR_INPUT_MASK 0xf0 /* 0-3 - output, 4-7 - input */
26b868db94SAndrew Lunn
27b868db94SAndrew Lunn #define TQMX86_GPIODD 0 /* GPIO Data Direction Register */
28b868db94SAndrew Lunn #define TQMX86_GPIOD 1 /* GPIO Data Register */
29b868db94SAndrew Lunn #define TQMX86_GPIIC 3 /* GPI Interrupt Configuration Register */
30b868db94SAndrew Lunn #define TQMX86_GPIIS 4 /* GPI Interrupt Status Register */
31b868db94SAndrew Lunn
3212043e85SMatthias Schiffer #define TQMX86_GPII_NONE 0
33b868db94SAndrew Lunn #define TQMX86_GPII_FALLING BIT(0)
34b868db94SAndrew Lunn #define TQMX86_GPII_RISING BIT(1)
35*17a6806fSMatthias Schiffer /* Stored in irq_type as a trigger type, but not actually valid as a register
36*17a6806fSMatthias Schiffer * value, so the name doesn't use "GPII"
37*17a6806fSMatthias Schiffer */
38*17a6806fSMatthias Schiffer #define TQMX86_INT_BOTH (BIT(0) | BIT(1))
39b868db94SAndrew Lunn #define TQMX86_GPII_MASK (BIT(0) | BIT(1))
40b868db94SAndrew Lunn #define TQMX86_GPII_BITS 2
4112043e85SMatthias Schiffer /* Stored in irq_type with GPII bits */
4212043e85SMatthias Schiffer #define TQMX86_INT_UNMASKED BIT(2)
43b868db94SAndrew Lunn
44b868db94SAndrew Lunn struct tqmx86_gpio_data {
45b868db94SAndrew Lunn struct gpio_chip chip;
46b868db94SAndrew Lunn void __iomem *io_base;
47b868db94SAndrew Lunn int irq;
4812043e85SMatthias Schiffer /* Lock must be held for accessing output and irq_type fields */
49b868db94SAndrew Lunn raw_spinlock_t spinlock;
5001aa7b7aSMatthias Schiffer DECLARE_BITMAP(output, TQMX86_NGPIO);
51b868db94SAndrew Lunn u8 irq_type[TQMX86_NGPI];
52b868db94SAndrew Lunn };
53b868db94SAndrew Lunn
tqmx86_gpio_read(struct tqmx86_gpio_data * gd,unsigned int reg)54b868db94SAndrew Lunn static u8 tqmx86_gpio_read(struct tqmx86_gpio_data *gd, unsigned int reg)
55b868db94SAndrew Lunn {
56b868db94SAndrew Lunn return ioread8(gd->io_base + reg);
57b868db94SAndrew Lunn }
58b868db94SAndrew Lunn
tqmx86_gpio_write(struct tqmx86_gpio_data * gd,u8 val,unsigned int reg)59b868db94SAndrew Lunn static void tqmx86_gpio_write(struct tqmx86_gpio_data *gd, u8 val,
60b868db94SAndrew Lunn unsigned int reg)
61b868db94SAndrew Lunn {
62b868db94SAndrew Lunn iowrite8(val, gd->io_base + reg);
63b868db94SAndrew Lunn }
64b868db94SAndrew Lunn
tqmx86_gpio_get(struct gpio_chip * chip,unsigned int offset)65b868db94SAndrew Lunn static int tqmx86_gpio_get(struct gpio_chip *chip, unsigned int offset)
66b868db94SAndrew Lunn {
67b868db94SAndrew Lunn struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
68b868db94SAndrew Lunn
69b868db94SAndrew Lunn return !!(tqmx86_gpio_read(gpio, TQMX86_GPIOD) & BIT(offset));
70b868db94SAndrew Lunn }
71b868db94SAndrew Lunn
tqmx86_gpio_set(struct gpio_chip * chip,unsigned int offset,int value)72b868db94SAndrew Lunn static void tqmx86_gpio_set(struct gpio_chip *chip, unsigned int offset,
73b868db94SAndrew Lunn int value)
74b868db94SAndrew Lunn {
75b868db94SAndrew Lunn struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
76b868db94SAndrew Lunn unsigned long flags;
77b868db94SAndrew Lunn
78b868db94SAndrew Lunn raw_spin_lock_irqsave(&gpio->spinlock, flags);
7901aa7b7aSMatthias Schiffer __assign_bit(offset, gpio->output, value);
8001aa7b7aSMatthias Schiffer tqmx86_gpio_write(gpio, bitmap_get_value8(gpio->output, 0), TQMX86_GPIOD);
81b868db94SAndrew Lunn raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
82b868db94SAndrew Lunn }
83b868db94SAndrew Lunn
tqmx86_gpio_direction_input(struct gpio_chip * chip,unsigned int offset)84b868db94SAndrew Lunn static int tqmx86_gpio_direction_input(struct gpio_chip *chip,
85b868db94SAndrew Lunn unsigned int offset)
86b868db94SAndrew Lunn {
87b868db94SAndrew Lunn /* Direction cannot be changed. Validate is an input. */
88b868db94SAndrew Lunn if (BIT(offset) & TQMX86_DIR_INPUT_MASK)
89b868db94SAndrew Lunn return 0;
90b868db94SAndrew Lunn else
91b868db94SAndrew Lunn return -EINVAL;
92b868db94SAndrew Lunn }
93b868db94SAndrew Lunn
tqmx86_gpio_direction_output(struct gpio_chip * chip,unsigned int offset,int value)94b868db94SAndrew Lunn static int tqmx86_gpio_direction_output(struct gpio_chip *chip,
95b868db94SAndrew Lunn unsigned int offset,
96b868db94SAndrew Lunn int value)
97b868db94SAndrew Lunn {
98b868db94SAndrew Lunn /* Direction cannot be changed, validate is an output */
99b868db94SAndrew Lunn if (BIT(offset) & TQMX86_DIR_INPUT_MASK)
100b868db94SAndrew Lunn return -EINVAL;
10118fadd6aSAxel Lin
10218fadd6aSAxel Lin tqmx86_gpio_set(chip, offset, value);
103b868db94SAndrew Lunn return 0;
104b868db94SAndrew Lunn }
105b868db94SAndrew Lunn
tqmx86_gpio_get_direction(struct gpio_chip * chip,unsigned int offset)106b868db94SAndrew Lunn static int tqmx86_gpio_get_direction(struct gpio_chip *chip,
107b868db94SAndrew Lunn unsigned int offset)
108b868db94SAndrew Lunn {
109e42615ecSMatti Vaittinen if (TQMX86_DIR_INPUT_MASK & BIT(offset))
110e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN;
111e42615ecSMatti Vaittinen
112e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT;
113b868db94SAndrew Lunn }
114b868db94SAndrew Lunn
tqmx86_gpio_irq_config(struct tqmx86_gpio_data * gpio,int offset)11512043e85SMatthias Schiffer static void tqmx86_gpio_irq_config(struct tqmx86_gpio_data *gpio, int offset)
11612043e85SMatthias Schiffer __must_hold(&gpio->spinlock)
11712043e85SMatthias Schiffer {
11812043e85SMatthias Schiffer u8 type = TQMX86_GPII_NONE, gpiic;
11912043e85SMatthias Schiffer
120*17a6806fSMatthias Schiffer if (gpio->irq_type[offset] & TQMX86_INT_UNMASKED) {
12112043e85SMatthias Schiffer type = gpio->irq_type[offset] & TQMX86_GPII_MASK;
12212043e85SMatthias Schiffer
123*17a6806fSMatthias Schiffer if (type == TQMX86_INT_BOTH)
124*17a6806fSMatthias Schiffer type = tqmx86_gpio_get(&gpio->chip, offset + TQMX86_NGPO)
125*17a6806fSMatthias Schiffer ? TQMX86_GPII_FALLING
126*17a6806fSMatthias Schiffer : TQMX86_GPII_RISING;
127*17a6806fSMatthias Schiffer }
128*17a6806fSMatthias Schiffer
12912043e85SMatthias Schiffer gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);
13012043e85SMatthias Schiffer gpiic &= ~(TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS));
13112043e85SMatthias Schiffer gpiic |= type << (offset * TQMX86_GPII_BITS);
13212043e85SMatthias Schiffer tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC);
13312043e85SMatthias Schiffer }
13412043e85SMatthias Schiffer
tqmx86_gpio_irq_mask(struct irq_data * data)135b868db94SAndrew Lunn static void tqmx86_gpio_irq_mask(struct irq_data *data)
136b868db94SAndrew Lunn {
137b868db94SAndrew Lunn unsigned int offset = (data->hwirq - TQMX86_NGPO);
138b868db94SAndrew Lunn struct tqmx86_gpio_data *gpio = gpiochip_get_data(
139b868db94SAndrew Lunn irq_data_get_irq_chip_data(data));
140b868db94SAndrew Lunn unsigned long flags;
141b868db94SAndrew Lunn
142b868db94SAndrew Lunn raw_spin_lock_irqsave(&gpio->spinlock, flags);
14312043e85SMatthias Schiffer gpio->irq_type[offset] &= ~TQMX86_INT_UNMASKED;
14412043e85SMatthias Schiffer tqmx86_gpio_irq_config(gpio, offset);
145b868db94SAndrew Lunn raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
14612043e85SMatthias Schiffer
1478e43827bSLinus Walleij gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(data));
148b868db94SAndrew Lunn }
149b868db94SAndrew Lunn
tqmx86_gpio_irq_unmask(struct irq_data * data)150b868db94SAndrew Lunn static void tqmx86_gpio_irq_unmask(struct irq_data *data)
151b868db94SAndrew Lunn {
152b868db94SAndrew Lunn unsigned int offset = (data->hwirq - TQMX86_NGPO);
153b868db94SAndrew Lunn struct tqmx86_gpio_data *gpio = gpiochip_get_data(
154b868db94SAndrew Lunn irq_data_get_irq_chip_data(data));
155b868db94SAndrew Lunn unsigned long flags;
156b868db94SAndrew Lunn
1578e43827bSLinus Walleij gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(data));
15812043e85SMatthias Schiffer
159b868db94SAndrew Lunn raw_spin_lock_irqsave(&gpio->spinlock, flags);
16012043e85SMatthias Schiffer gpio->irq_type[offset] |= TQMX86_INT_UNMASKED;
16112043e85SMatthias Schiffer tqmx86_gpio_irq_config(gpio, offset);
162b868db94SAndrew Lunn raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
163b868db94SAndrew Lunn }
164b868db94SAndrew Lunn
tqmx86_gpio_irq_set_type(struct irq_data * data,unsigned int type)165b868db94SAndrew Lunn static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type)
166b868db94SAndrew Lunn {
167b868db94SAndrew Lunn struct tqmx86_gpio_data *gpio = gpiochip_get_data(
168b868db94SAndrew Lunn irq_data_get_irq_chip_data(data));
169b868db94SAndrew Lunn unsigned int offset = (data->hwirq - TQMX86_NGPO);
170b868db94SAndrew Lunn unsigned int edge_type = type & IRQF_TRIGGER_MASK;
171b868db94SAndrew Lunn unsigned long flags;
17212043e85SMatthias Schiffer u8 new_type;
173b868db94SAndrew Lunn
174b868db94SAndrew Lunn switch (edge_type) {
175b868db94SAndrew Lunn case IRQ_TYPE_EDGE_RISING:
176b868db94SAndrew Lunn new_type = TQMX86_GPII_RISING;
177b868db94SAndrew Lunn break;
178b868db94SAndrew Lunn case IRQ_TYPE_EDGE_FALLING:
179b868db94SAndrew Lunn new_type = TQMX86_GPII_FALLING;
180b868db94SAndrew Lunn break;
181b868db94SAndrew Lunn case IRQ_TYPE_EDGE_BOTH:
182*17a6806fSMatthias Schiffer new_type = TQMX86_INT_BOTH;
183b868db94SAndrew Lunn break;
184b868db94SAndrew Lunn default:
185b868db94SAndrew Lunn return -EINVAL; /* not supported */
186b868db94SAndrew Lunn }
187b868db94SAndrew Lunn
188b868db94SAndrew Lunn raw_spin_lock_irqsave(&gpio->spinlock, flags);
18912043e85SMatthias Schiffer gpio->irq_type[offset] &= ~TQMX86_GPII_MASK;
19012043e85SMatthias Schiffer gpio->irq_type[offset] |= new_type;
19112043e85SMatthias Schiffer tqmx86_gpio_irq_config(gpio, offset);
192b868db94SAndrew Lunn raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
193b868db94SAndrew Lunn
194b868db94SAndrew Lunn return 0;
195b868db94SAndrew Lunn }
196b868db94SAndrew Lunn
tqmx86_gpio_irq_handler(struct irq_desc * desc)197b868db94SAndrew Lunn static void tqmx86_gpio_irq_handler(struct irq_desc *desc)
198b868db94SAndrew Lunn {
199b868db94SAndrew Lunn struct gpio_chip *chip = irq_desc_get_handler_data(desc);
200b868db94SAndrew Lunn struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
201b868db94SAndrew Lunn struct irq_chip *irq_chip = irq_desc_get_chip(desc);
202*17a6806fSMatthias Schiffer unsigned long irq_bits, flags;
203*17a6806fSMatthias Schiffer int i;
204b868db94SAndrew Lunn u8 irq_status;
205b868db94SAndrew Lunn
206b868db94SAndrew Lunn chained_irq_enter(irq_chip, desc);
207b868db94SAndrew Lunn
208b868db94SAndrew Lunn irq_status = tqmx86_gpio_read(gpio, TQMX86_GPIIS);
209b868db94SAndrew Lunn tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);
210b868db94SAndrew Lunn
211b868db94SAndrew Lunn irq_bits = irq_status;
212*17a6806fSMatthias Schiffer
213*17a6806fSMatthias Schiffer raw_spin_lock_irqsave(&gpio->spinlock, flags);
214*17a6806fSMatthias Schiffer for_each_set_bit(i, &irq_bits, TQMX86_NGPI) {
215*17a6806fSMatthias Schiffer /*
216*17a6806fSMatthias Schiffer * Edge-both triggers are implemented by flipping the edge
217*17a6806fSMatthias Schiffer * trigger after each interrupt, as the controller only supports
218*17a6806fSMatthias Schiffer * either rising or falling edge triggers, but not both.
219*17a6806fSMatthias Schiffer *
220*17a6806fSMatthias Schiffer * Internally, the TQMx86 GPIO controller has separate status
221*17a6806fSMatthias Schiffer * registers for rising and falling edge interrupts. GPIIC
222*17a6806fSMatthias Schiffer * configures which bits from which register are visible in the
223*17a6806fSMatthias Schiffer * interrupt status register GPIIS and defines what triggers the
224*17a6806fSMatthias Schiffer * parent IRQ line. Writing to GPIIS always clears both rising
225*17a6806fSMatthias Schiffer * and falling interrupt flags internally, regardless of the
226*17a6806fSMatthias Schiffer * currently configured trigger.
227*17a6806fSMatthias Schiffer *
228*17a6806fSMatthias Schiffer * In consequence, we can cleanly implement the edge-both
229*17a6806fSMatthias Schiffer * trigger in software by first clearing the interrupt and then
230*17a6806fSMatthias Schiffer * setting the new trigger based on the current GPIO input in
231*17a6806fSMatthias Schiffer * tqmx86_gpio_irq_config() - even if an edge arrives between
232*17a6806fSMatthias Schiffer * reading the input and setting the trigger, we will have a new
233*17a6806fSMatthias Schiffer * interrupt pending.
234*17a6806fSMatthias Schiffer */
235*17a6806fSMatthias Schiffer if ((gpio->irq_type[i] & TQMX86_GPII_MASK) == TQMX86_INT_BOTH)
236*17a6806fSMatthias Schiffer tqmx86_gpio_irq_config(gpio, i);
237*17a6806fSMatthias Schiffer }
238*17a6806fSMatthias Schiffer raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
239*17a6806fSMatthias Schiffer
240dbd1c54fSMarc Zyngier for_each_set_bit(i, &irq_bits, TQMX86_NGPI)
241dbd1c54fSMarc Zyngier generic_handle_domain_irq(gpio->chip.irq.domain,
242b868db94SAndrew Lunn i + TQMX86_NGPO);
243b868db94SAndrew Lunn
244b868db94SAndrew Lunn chained_irq_exit(irq_chip, desc);
245b868db94SAndrew Lunn }
246b868db94SAndrew Lunn
247b868db94SAndrew Lunn /* Minimal runtime PM is needed by the IRQ subsystem */
tqmx86_gpio_runtime_suspend(struct device * dev)248b868db94SAndrew Lunn static int __maybe_unused tqmx86_gpio_runtime_suspend(struct device *dev)
249b868db94SAndrew Lunn {
250b868db94SAndrew Lunn return 0;
251b868db94SAndrew Lunn }
252b868db94SAndrew Lunn
tqmx86_gpio_runtime_resume(struct device * dev)253b868db94SAndrew Lunn static int __maybe_unused tqmx86_gpio_runtime_resume(struct device *dev)
254b868db94SAndrew Lunn {
255b868db94SAndrew Lunn return 0;
256b868db94SAndrew Lunn }
257b868db94SAndrew Lunn
258b868db94SAndrew Lunn static const struct dev_pm_ops tqmx86_gpio_dev_pm_ops = {
259b868db94SAndrew Lunn SET_RUNTIME_PM_OPS(tqmx86_gpio_runtime_suspend,
260b868db94SAndrew Lunn tqmx86_gpio_runtime_resume, NULL)
261b868db94SAndrew Lunn };
262b868db94SAndrew Lunn
tqmx86_init_irq_valid_mask(struct gpio_chip * chip,unsigned long * valid_mask,unsigned int ngpios)2635fbe5b58SLinus Walleij static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip,
2645fbe5b58SLinus Walleij unsigned long *valid_mask,
2655fbe5b58SLinus Walleij unsigned int ngpios)
2665fbe5b58SLinus Walleij {
2675fbe5b58SLinus Walleij /* Only GPIOs 4-7 are valid for interrupts. Clear the others */
2685fbe5b58SLinus Walleij clear_bit(0, valid_mask);
2695fbe5b58SLinus Walleij clear_bit(1, valid_mask);
2705fbe5b58SLinus Walleij clear_bit(2, valid_mask);
2715fbe5b58SLinus Walleij clear_bit(3, valid_mask);
2725fbe5b58SLinus Walleij }
2735fbe5b58SLinus Walleij
tqmx86_gpio_irq_print_chip(struct irq_data * d,struct seq_file * p)2748e43827bSLinus Walleij static void tqmx86_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
2758e43827bSLinus Walleij {
2768e43827bSLinus Walleij struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
2778e43827bSLinus Walleij
2788e43827bSLinus Walleij seq_printf(p, gc->label);
2798e43827bSLinus Walleij }
2808e43827bSLinus Walleij
2818e43827bSLinus Walleij static const struct irq_chip tqmx86_gpio_irq_chip = {
2828e43827bSLinus Walleij .irq_mask = tqmx86_gpio_irq_mask,
2838e43827bSLinus Walleij .irq_unmask = tqmx86_gpio_irq_unmask,
2848e43827bSLinus Walleij .irq_set_type = tqmx86_gpio_irq_set_type,
2858e43827bSLinus Walleij .irq_print_chip = tqmx86_gpio_irq_print_chip,
2868e43827bSLinus Walleij .flags = IRQCHIP_IMMUTABLE,
2878e43827bSLinus Walleij GPIOCHIP_IRQ_RESOURCE_HELPERS,
2888e43827bSLinus Walleij };
2898e43827bSLinus Walleij
tqmx86_gpio_probe(struct platform_device * pdev)290b868db94SAndrew Lunn static int tqmx86_gpio_probe(struct platform_device *pdev)
291b868db94SAndrew Lunn {
292b868db94SAndrew Lunn struct device *dev = &pdev->dev;
293b868db94SAndrew Lunn struct tqmx86_gpio_data *gpio;
294b868db94SAndrew Lunn struct gpio_chip *chip;
29574639d66SLinus Walleij struct gpio_irq_chip *girq;
296b868db94SAndrew Lunn void __iomem *io_base;
297b868db94SAndrew Lunn struct resource *res;
298b868db94SAndrew Lunn int ret, irq;
299b868db94SAndrew Lunn
3009b87f435SMatthias Schiffer irq = platform_get_irq_optional(pdev, 0);
3019b87f435SMatthias Schiffer if (irq < 0 && irq != -ENXIO)
302b868db94SAndrew Lunn return irq;
303b868db94SAndrew Lunn
304b868db94SAndrew Lunn res = platform_get_resource(pdev, IORESOURCE_IO, 0);
305b868db94SAndrew Lunn if (!res) {
306b868db94SAndrew Lunn dev_err(&pdev->dev, "Cannot get I/O\n");
307b868db94SAndrew Lunn return -ENODEV;
308b868db94SAndrew Lunn }
309b868db94SAndrew Lunn
310b868db94SAndrew Lunn io_base = devm_ioport_map(&pdev->dev, res->start, resource_size(res));
311b868db94SAndrew Lunn if (!io_base)
312b868db94SAndrew Lunn return -ENOMEM;
313b868db94SAndrew Lunn
314b868db94SAndrew Lunn gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
315b868db94SAndrew Lunn if (!gpio)
316b868db94SAndrew Lunn return -ENOMEM;
317b868db94SAndrew Lunn
318b868db94SAndrew Lunn raw_spin_lock_init(&gpio->spinlock);
319b868db94SAndrew Lunn gpio->io_base = io_base;
320b868db94SAndrew Lunn
321b868db94SAndrew Lunn tqmx86_gpio_write(gpio, (u8)~TQMX86_DIR_INPUT_MASK, TQMX86_GPIODD);
322b868db94SAndrew Lunn
32301aa7b7aSMatthias Schiffer /*
32401aa7b7aSMatthias Schiffer * Reading the previous output state is not possible with TQMx86 hardware.
32501aa7b7aSMatthias Schiffer * Initialize all outputs to 0 to have a defined state that matches the
32601aa7b7aSMatthias Schiffer * shadow register.
32701aa7b7aSMatthias Schiffer */
32801aa7b7aSMatthias Schiffer tqmx86_gpio_write(gpio, 0, TQMX86_GPIOD);
32901aa7b7aSMatthias Schiffer
330b868db94SAndrew Lunn chip = &gpio->chip;
331b868db94SAndrew Lunn chip->label = "gpio-tqmx86";
332b868db94SAndrew Lunn chip->owner = THIS_MODULE;
333b868db94SAndrew Lunn chip->can_sleep = false;
334b868db94SAndrew Lunn chip->base = -1;
335b868db94SAndrew Lunn chip->direction_input = tqmx86_gpio_direction_input;
336b868db94SAndrew Lunn chip->direction_output = tqmx86_gpio_direction_output;
337b868db94SAndrew Lunn chip->get_direction = tqmx86_gpio_get_direction;
338b868db94SAndrew Lunn chip->get = tqmx86_gpio_get;
339b868db94SAndrew Lunn chip->set = tqmx86_gpio_set;
340b868db94SAndrew Lunn chip->ngpio = TQMX86_NGPIO;
341b868db94SAndrew Lunn chip->parent = pdev->dev.parent;
342b868db94SAndrew Lunn
343b868db94SAndrew Lunn pm_runtime_enable(&pdev->dev);
344b868db94SAndrew Lunn
3459b87f435SMatthias Schiffer if (irq > 0) {
346b868db94SAndrew Lunn u8 irq_status;
347b868db94SAndrew Lunn
348b868db94SAndrew Lunn /* Mask all interrupts */
349b868db94SAndrew Lunn tqmx86_gpio_write(gpio, 0, TQMX86_GPIIC);
350b868db94SAndrew Lunn
351b868db94SAndrew Lunn /* Clear all pending interrupts */
352b868db94SAndrew Lunn irq_status = tqmx86_gpio_read(gpio, TQMX86_GPIIS);
353b868db94SAndrew Lunn tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);
354b868db94SAndrew Lunn
35574639d66SLinus Walleij girq = &chip->irq;
3568e43827bSLinus Walleij gpio_irq_chip_set_chip(girq, &tqmx86_gpio_irq_chip);
35774639d66SLinus Walleij girq->parent_handler = tqmx86_gpio_irq_handler;
35874639d66SLinus Walleij girq->num_parents = 1;
35974639d66SLinus Walleij girq->parents = devm_kcalloc(&pdev->dev, 1,
36074639d66SLinus Walleij sizeof(*girq->parents),
36174639d66SLinus Walleij GFP_KERNEL);
36274639d66SLinus Walleij if (!girq->parents) {
36374639d66SLinus Walleij ret = -ENOMEM;
36474639d66SLinus Walleij goto out_pm_dis;
36574639d66SLinus Walleij }
36674639d66SLinus Walleij girq->parents[0] = irq;
36774639d66SLinus Walleij girq->default_type = IRQ_TYPE_NONE;
36874639d66SLinus Walleij girq->handler = handle_simple_irq;
3695fbe5b58SLinus Walleij girq->init_valid_mask = tqmx86_init_irq_valid_mask;
37021a9acc1SDongliang Mu
37121a9acc1SDongliang Mu irq_domain_set_pm_device(girq->domain, dev);
37274639d66SLinus Walleij }
37374639d66SLinus Walleij
37474639d66SLinus Walleij ret = devm_gpiochip_add_data(dev, chip, gpio);
375b868db94SAndrew Lunn if (ret) {
37674639d66SLinus Walleij dev_err(dev, "Could not register GPIO chip\n");
37796be65d1SWei Yongjun goto out_pm_dis;
378b868db94SAndrew Lunn }
379b868db94SAndrew Lunn
380b868db94SAndrew Lunn dev_info(dev, "GPIO functionality initialized with %d pins\n",
381b868db94SAndrew Lunn chip->ngpio);
382b868db94SAndrew Lunn
383b868db94SAndrew Lunn return 0;
384b868db94SAndrew Lunn
385b868db94SAndrew Lunn out_pm_dis:
386b868db94SAndrew Lunn pm_runtime_disable(&pdev->dev);
387b868db94SAndrew Lunn
388b868db94SAndrew Lunn return ret;
389b868db94SAndrew Lunn }
390b868db94SAndrew Lunn
391b868db94SAndrew Lunn static struct platform_driver tqmx86_gpio_driver = {
392b868db94SAndrew Lunn .driver = {
393b868db94SAndrew Lunn .name = "tqmx86-gpio",
394b868db94SAndrew Lunn .pm = &tqmx86_gpio_dev_pm_ops,
395b868db94SAndrew Lunn },
396b868db94SAndrew Lunn .probe = tqmx86_gpio_probe,
397b868db94SAndrew Lunn };
398b868db94SAndrew Lunn
399b868db94SAndrew Lunn module_platform_driver(tqmx86_gpio_driver);
400b868db94SAndrew Lunn
401b868db94SAndrew Lunn MODULE_DESCRIPTION("TQMx86 PLD GPIO Driver");
402b868db94SAndrew Lunn MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
403b868db94SAndrew Lunn MODULE_LICENSE("GPL");
404b868db94SAndrew Lunn MODULE_ALIAS("platform:tqmx86-gpio");
405