1 // SPDX-License-Identifier: GPL-2.0
3 * Toshiba Visconti GPIO Support
5 * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation
6 * (C) Copyright 2020 TOSHIBA CORPORATION
8 * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
11 #include <linux/bitops.h>
12 #include <linux/gpio/driver.h>
13 #include <linux/init.h>
14 #include <linux/interrupt.h>
15 #include <linux/module.h>
17 #include <linux/of_irq.h>
18 #include <linux/platform_device.h>
19 #include <linux/property.h>
20 #include <linux/seq_file.h>
24 #define GPIO_IDATA 0x08
25 #define GPIO_ODATA 0x10
26 #define GPIO_OSET 0x18
27 #define GPIO_OCLR 0x20
28 #define GPIO_INTMODE 0x30
30 #define BASE_HW_IRQ 24
32 struct visconti_gpio
{
34 spinlock_t lock
; /* protect gpio register */
35 struct gpio_chip gpio_chip
;
39 static int visconti_gpio_irq_set_type(struct irq_data
*d
, unsigned int type
)
41 struct gpio_chip
*gc
= irq_data_get_irq_chip_data(d
);
42 struct visconti_gpio
*priv
= gpiochip_get_data(gc
);
43 u32 offset
= irqd_to_hwirq(d
);
44 u32 bit
= BIT(offset
);
45 u32 intc_type
= IRQ_TYPE_EDGE_RISING
;
50 spin_lock_irqsave(&priv
->lock
, flags
);
52 odata
= readl(priv
->base
+ GPIO_ODATA
);
53 intmode
= readl(priv
->base
+ GPIO_INTMODE
);
56 case IRQ_TYPE_EDGE_RISING
:
60 case IRQ_TYPE_EDGE_FALLING
:
64 case IRQ_TYPE_EDGE_BOTH
:
67 case IRQ_TYPE_LEVEL_HIGH
:
68 intc_type
= IRQ_TYPE_LEVEL_HIGH
;
72 case IRQ_TYPE_LEVEL_LOW
:
73 intc_type
= IRQ_TYPE_LEVEL_HIGH
;
82 writel(odata
, priv
->base
+ GPIO_ODATA
);
83 writel(intmode
, priv
->base
+ GPIO_INTMODE
);
84 irq_set_irq_type(offset
, intc_type
);
86 ret
= irq_chip_set_type_parent(d
, type
);
88 spin_unlock_irqrestore(&priv
->lock
, flags
);
92 static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip
*gc
,
94 unsigned int child_type
,
96 unsigned int *parent_type
)
98 /* Interrupts 0..15 mapped to interrupts 24..39 on the GIC */
100 /* All these interrupts are level high in the CPU */
101 *parent_type
= IRQ_TYPE_LEVEL_HIGH
;
102 *parent
= child
+ BASE_HW_IRQ
;
108 static int visconti_gpio_populate_parent_fwspec(struct gpio_chip
*chip
,
109 union gpio_irq_fwspec
*gfwspec
,
110 unsigned int parent_hwirq
,
111 unsigned int parent_type
)
113 struct irq_fwspec
*fwspec
= &gfwspec
->fwspec
;
115 fwspec
->fwnode
= chip
->irq
.parent_domain
->fwnode
;
116 fwspec
->param_count
= 3;
117 fwspec
->param
[0] = 0;
118 fwspec
->param
[1] = parent_hwirq
;
119 fwspec
->param
[2] = parent_type
;
124 static void visconti_gpio_mask_irq(struct irq_data
*d
)
126 struct gpio_chip
*gc
= irq_data_get_irq_chip_data(d
);
128 irq_chip_mask_parent(d
);
129 gpiochip_disable_irq(gc
, irqd_to_hwirq(d
));
132 static void visconti_gpio_unmask_irq(struct irq_data
*d
)
134 struct gpio_chip
*gc
= irq_data_get_irq_chip_data(d
);
136 gpiochip_enable_irq(gc
, irqd_to_hwirq(d
));
137 irq_chip_unmask_parent(d
);
140 static void visconti_gpio_irq_print_chip(struct irq_data
*d
, struct seq_file
*p
)
142 struct gpio_chip
*gc
= irq_data_get_irq_chip_data(d
);
143 struct visconti_gpio
*priv
= gpiochip_get_data(gc
);
145 seq_puts(p
, dev_name(priv
->dev
));
148 static const struct irq_chip visconti_gpio_irq_chip
= {
149 .irq_mask
= visconti_gpio_mask_irq
,
150 .irq_unmask
= visconti_gpio_unmask_irq
,
151 .irq_eoi
= irq_chip_eoi_parent
,
152 .irq_set_type
= visconti_gpio_irq_set_type
,
153 .irq_print_chip
= visconti_gpio_irq_print_chip
,
154 .flags
= IRQCHIP_SET_TYPE_MASKED
| IRQCHIP_MASK_ON_SUSPEND
|
156 GPIOCHIP_IRQ_RESOURCE_HELPERS
,
159 static int visconti_gpio_probe(struct platform_device
*pdev
)
161 struct device
*dev
= &pdev
->dev
;
162 struct visconti_gpio
*priv
;
163 struct gpio_irq_chip
*girq
;
164 struct irq_domain
*parent
;
165 struct device_node
*irq_parent
;
168 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
172 spin_lock_init(&priv
->lock
);
175 priv
->base
= devm_platform_ioremap_resource(pdev
, 0);
176 if (IS_ERR(priv
->base
))
177 return PTR_ERR(priv
->base
);
179 irq_parent
= of_irq_find_parent(dev
->of_node
);
181 dev_err(dev
, "No IRQ parent node\n");
185 parent
= irq_find_host(irq_parent
);
186 of_node_put(irq_parent
);
188 dev_err(dev
, "No IRQ parent domain\n");
192 ret
= bgpio_init(&priv
->gpio_chip
, dev
, 4,
193 priv
->base
+ GPIO_IDATA
,
194 priv
->base
+ GPIO_OSET
,
195 priv
->base
+ GPIO_OCLR
,
196 priv
->base
+ GPIO_DIR
,
200 dev_err(dev
, "unable to init generic GPIO\n");
204 girq
= &priv
->gpio_chip
.irq
;
205 gpio_irq_chip_set_chip(girq
, &visconti_gpio_irq_chip
);
206 girq
->fwnode
= dev_fwnode(dev
);
207 girq
->parent_domain
= parent
;
208 girq
->child_to_parent_hwirq
= visconti_gpio_child_to_parent_hwirq
;
209 girq
->populate_parent_alloc_arg
= visconti_gpio_populate_parent_fwspec
;
210 girq
->default_type
= IRQ_TYPE_NONE
;
211 girq
->handler
= handle_level_irq
;
213 return devm_gpiochip_add_data(dev
, &priv
->gpio_chip
, priv
);
216 static const struct of_device_id visconti_gpio_of_match
[] = {
217 { .compatible
= "toshiba,gpio-tmpv7708", },
218 { /* end of table */ }
220 MODULE_DEVICE_TABLE(of
, visconti_gpio_of_match
);
222 static struct platform_driver visconti_gpio_driver
= {
223 .probe
= visconti_gpio_probe
,
225 .name
= "visconti_gpio",
226 .of_match_table
= visconti_gpio_of_match
,
229 module_platform_driver(visconti_gpio_driver
);
231 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>");
232 MODULE_DESCRIPTION("Toshiba Visconti GPIO Driver");
233 MODULE_LICENSE("GPL v2");