1 // SPDX-License-Identifier: GPL-2.0
3 * TQ-Systems TQMx86 PLD GPIO driver
5 * Based on vendor driver by:
6 * Vadim V.Vlasov <vvlasov@dev.rtsoft.ru>
9 #include <linux/bitops.h>
10 #include <linux/errno.h>
11 #include <linux/gpio/driver.h>
12 #include <linux/init.h>
13 #include <linux/interrupt.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/slab.h>
20 #define TQMX86_NGPIO 8
21 #define TQMX86_NGPO 4 /* 0-3 - output */
22 #define TQMX86_NGPI 4 /* 4-7 - input */
23 #define TQMX86_DIR_INPUT_MASK 0xf0 /* 0-3 - output, 4-7 - input */
25 #define TQMX86_GPIODD 0 /* GPIO Data Direction Register */
26 #define TQMX86_GPIOD 1 /* GPIO Data Register */
27 #define TQMX86_GPIIC 3 /* GPI Interrupt Configuration Register */
28 #define TQMX86_GPIIS 4 /* GPI Interrupt Status Register */
30 #define TQMX86_GPII_FALLING BIT(0)
31 #define TQMX86_GPII_RISING BIT(1)
32 #define TQMX86_GPII_MASK (BIT(0) | BIT(1))
33 #define TQMX86_GPII_BITS 2
35 struct tqmx86_gpio_data
{
36 struct gpio_chip chip
;
37 struct irq_chip irq_chip
;
38 void __iomem
*io_base
;
40 raw_spinlock_t spinlock
;
41 u8 irq_type
[TQMX86_NGPI
];
44 static u8
tqmx86_gpio_read(struct tqmx86_gpio_data
*gd
, unsigned int reg
)
46 return ioread8(gd
->io_base
+ reg
);
49 static void tqmx86_gpio_write(struct tqmx86_gpio_data
*gd
, u8 val
,
52 iowrite8(val
, gd
->io_base
+ reg
);
55 static int tqmx86_gpio_get(struct gpio_chip
*chip
, unsigned int offset
)
57 struct tqmx86_gpio_data
*gpio
= gpiochip_get_data(chip
);
59 return !!(tqmx86_gpio_read(gpio
, TQMX86_GPIOD
) & BIT(offset
));
62 static void tqmx86_gpio_set(struct gpio_chip
*chip
, unsigned int offset
,
65 struct tqmx86_gpio_data
*gpio
= gpiochip_get_data(chip
);
69 raw_spin_lock_irqsave(&gpio
->spinlock
, flags
);
70 val
= tqmx86_gpio_read(gpio
, TQMX86_GPIOD
);
75 tqmx86_gpio_write(gpio
, val
, TQMX86_GPIOD
);
76 raw_spin_unlock_irqrestore(&gpio
->spinlock
, flags
);
79 static int tqmx86_gpio_direction_input(struct gpio_chip
*chip
,
82 /* Direction cannot be changed. Validate is an input. */
83 if (BIT(offset
) & TQMX86_DIR_INPUT_MASK
)
89 static int tqmx86_gpio_direction_output(struct gpio_chip
*chip
,
93 /* Direction cannot be changed, validate is an output */
94 if (BIT(offset
) & TQMX86_DIR_INPUT_MASK
)
97 tqmx86_gpio_set(chip
, offset
, value
);
101 static int tqmx86_gpio_get_direction(struct gpio_chip
*chip
,
104 return !!(TQMX86_DIR_INPUT_MASK
& BIT(offset
));
107 static void tqmx86_gpio_irq_mask(struct irq_data
*data
)
109 unsigned int offset
= (data
->hwirq
- TQMX86_NGPO
);
110 struct tqmx86_gpio_data
*gpio
= gpiochip_get_data(
111 irq_data_get_irq_chip_data(data
));
115 mask
= TQMX86_GPII_MASK
<< (offset
* TQMX86_GPII_BITS
);
117 raw_spin_lock_irqsave(&gpio
->spinlock
, flags
);
118 gpiic
= tqmx86_gpio_read(gpio
, TQMX86_GPIIC
);
120 tqmx86_gpio_write(gpio
, gpiic
, TQMX86_GPIIC
);
121 raw_spin_unlock_irqrestore(&gpio
->spinlock
, flags
);
124 static void tqmx86_gpio_irq_unmask(struct irq_data
*data
)
126 unsigned int offset
= (data
->hwirq
- TQMX86_NGPO
);
127 struct tqmx86_gpio_data
*gpio
= gpiochip_get_data(
128 irq_data_get_irq_chip_data(data
));
132 mask
= TQMX86_GPII_MASK
<< (offset
* TQMX86_GPII_BITS
);
134 raw_spin_lock_irqsave(&gpio
->spinlock
, flags
);
135 gpiic
= tqmx86_gpio_read(gpio
, TQMX86_GPIIC
);
137 gpiic
|= gpio
->irq_type
[offset
] << (offset
* TQMX86_GPII_BITS
);
138 tqmx86_gpio_write(gpio
, gpiic
, TQMX86_GPIIC
);
139 raw_spin_unlock_irqrestore(&gpio
->spinlock
, flags
);
142 static int tqmx86_gpio_irq_set_type(struct irq_data
*data
, unsigned int type
)
144 struct tqmx86_gpio_data
*gpio
= gpiochip_get_data(
145 irq_data_get_irq_chip_data(data
));
146 unsigned int offset
= (data
->hwirq
- TQMX86_NGPO
);
147 unsigned int edge_type
= type
& IRQF_TRIGGER_MASK
;
152 case IRQ_TYPE_EDGE_RISING
:
153 new_type
= TQMX86_GPII_RISING
;
155 case IRQ_TYPE_EDGE_FALLING
:
156 new_type
= TQMX86_GPII_FALLING
;
158 case IRQ_TYPE_EDGE_BOTH
:
159 new_type
= TQMX86_GPII_FALLING
| TQMX86_GPII_RISING
;
162 return -EINVAL
; /* not supported */
165 gpio
->irq_type
[offset
] = new_type
;
167 raw_spin_lock_irqsave(&gpio
->spinlock
, flags
);
168 gpiic
= tqmx86_gpio_read(gpio
, TQMX86_GPIIC
);
169 gpiic
&= ~((TQMX86_GPII_MASK
) << (offset
* TQMX86_GPII_BITS
));
170 gpiic
|= new_type
<< (offset
* TQMX86_GPII_BITS
);
171 tqmx86_gpio_write(gpio
, gpiic
, TQMX86_GPIIC
);
172 raw_spin_unlock_irqrestore(&gpio
->spinlock
, flags
);
177 static void tqmx86_gpio_irq_handler(struct irq_desc
*desc
)
179 struct gpio_chip
*chip
= irq_desc_get_handler_data(desc
);
180 struct tqmx86_gpio_data
*gpio
= gpiochip_get_data(chip
);
181 struct irq_chip
*irq_chip
= irq_desc_get_chip(desc
);
182 unsigned long irq_bits
;
183 int i
= 0, child_irq
;
186 chained_irq_enter(irq_chip
, desc
);
188 irq_status
= tqmx86_gpio_read(gpio
, TQMX86_GPIIS
);
189 tqmx86_gpio_write(gpio
, irq_status
, TQMX86_GPIIS
);
191 irq_bits
= irq_status
;
192 for_each_set_bit(i
, &irq_bits
, TQMX86_NGPI
) {
193 child_irq
= irq_find_mapping(gpio
->chip
.irq
.domain
,
195 generic_handle_irq(child_irq
);
198 chained_irq_exit(irq_chip
, desc
);
201 /* Minimal runtime PM is needed by the IRQ subsystem */
202 static int __maybe_unused
tqmx86_gpio_runtime_suspend(struct device
*dev
)
207 static int __maybe_unused
tqmx86_gpio_runtime_resume(struct device
*dev
)
212 static const struct dev_pm_ops tqmx86_gpio_dev_pm_ops
= {
213 SET_RUNTIME_PM_OPS(tqmx86_gpio_runtime_suspend
,
214 tqmx86_gpio_runtime_resume
, NULL
)
217 static int tqmx86_gpio_probe(struct platform_device
*pdev
)
219 struct device
*dev
= &pdev
->dev
;
220 struct tqmx86_gpio_data
*gpio
;
221 struct gpio_chip
*chip
;
222 void __iomem
*io_base
;
223 struct resource
*res
;
226 irq
= platform_get_irq(pdev
, 0);
230 res
= platform_get_resource(pdev
, IORESOURCE_IO
, 0);
232 dev_err(&pdev
->dev
, "Cannot get I/O\n");
236 io_base
= devm_ioport_map(&pdev
->dev
, res
->start
, resource_size(res
));
240 gpio
= devm_kzalloc(dev
, sizeof(*gpio
), GFP_KERNEL
);
244 raw_spin_lock_init(&gpio
->spinlock
);
245 gpio
->io_base
= io_base
;
247 tqmx86_gpio_write(gpio
, (u8
)~TQMX86_DIR_INPUT_MASK
, TQMX86_GPIODD
);
249 platform_set_drvdata(pdev
, gpio
);
252 chip
->label
= "gpio-tqmx86";
253 chip
->owner
= THIS_MODULE
;
254 chip
->can_sleep
= false;
256 chip
->direction_input
= tqmx86_gpio_direction_input
;
257 chip
->direction_output
= tqmx86_gpio_direction_output
;
258 chip
->get_direction
= tqmx86_gpio_get_direction
;
259 chip
->get
= tqmx86_gpio_get
;
260 chip
->set
= tqmx86_gpio_set
;
261 chip
->ngpio
= TQMX86_NGPIO
;
262 chip
->irq
.need_valid_mask
= true;
263 chip
->parent
= pdev
->dev
.parent
;
265 pm_runtime_enable(&pdev
->dev
);
267 ret
= devm_gpiochip_add_data(dev
, chip
, gpio
);
269 dev_err(dev
, "Could not register GPIO chip\n");
274 struct irq_chip
*irq_chip
= &gpio
->irq_chip
;
277 irq_chip
->name
= chip
->label
;
278 irq_chip
->parent_device
= &pdev
->dev
;
279 irq_chip
->irq_mask
= tqmx86_gpio_irq_mask
;
280 irq_chip
->irq_unmask
= tqmx86_gpio_irq_unmask
;
281 irq_chip
->irq_set_type
= tqmx86_gpio_irq_set_type
;
283 /* Mask all interrupts */
284 tqmx86_gpio_write(gpio
, 0, TQMX86_GPIIC
);
286 /* Clear all pending interrupts */
287 irq_status
= tqmx86_gpio_read(gpio
, TQMX86_GPIIS
);
288 tqmx86_gpio_write(gpio
, irq_status
, TQMX86_GPIIS
);
290 ret
= gpiochip_irqchip_add(chip
, irq_chip
,
291 0, handle_simple_irq
,
294 dev_err(dev
, "Could not add irq chip\n");
298 gpiochip_set_chained_irqchip(chip
, irq_chip
,
299 irq
, tqmx86_gpio_irq_handler
);
302 /* Only GPIOs 4-7 are valid for interrupts. Clear the others */
303 clear_bit(0, chip
->irq
.valid_mask
);
304 clear_bit(1, chip
->irq
.valid_mask
);
305 clear_bit(2, chip
->irq
.valid_mask
);
306 clear_bit(3, chip
->irq
.valid_mask
);
308 dev_info(dev
, "GPIO functionality initialized with %d pins\n",
314 pm_runtime_disable(&pdev
->dev
);
319 static struct platform_driver tqmx86_gpio_driver
= {
321 .name
= "tqmx86-gpio",
322 .pm
= &tqmx86_gpio_dev_pm_ops
,
324 .probe
= tqmx86_gpio_probe
,
327 module_platform_driver(tqmx86_gpio_driver
);
329 MODULE_DESCRIPTION("TQMx86 PLD GPIO Driver");
330 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
331 MODULE_LICENSE("GPL");
332 MODULE_ALIAS("platform:tqmx86-gpio");