1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | /* |
4 | * Copyright 2017-2018 Cadence |
5 | * |
6 | * Authors: |
7 | * Jan Kotas <jank@cadence.com> |
8 | * Boris Brezillon <boris.brezillon@free-electrons.com> |
9 | */ |
10 | |
11 | #include <linux/gpio/driver.h> |
12 | #include <linux/clk.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/spinlock.h> |
18 | |
19 | #define CDNS_GPIO_BYPASS_MODE 0x00 |
20 | #define CDNS_GPIO_DIRECTION_MODE 0x04 |
21 | #define CDNS_GPIO_OUTPUT_EN 0x08 |
22 | #define CDNS_GPIO_OUTPUT_VALUE 0x0c |
23 | #define CDNS_GPIO_INPUT_VALUE 0x10 |
24 | #define CDNS_GPIO_IRQ_MASK 0x14 |
25 | #define CDNS_GPIO_IRQ_EN 0x18 |
26 | #define CDNS_GPIO_IRQ_DIS 0x1c |
27 | #define CDNS_GPIO_IRQ_STATUS 0x20 |
28 | #define CDNS_GPIO_IRQ_TYPE 0x24 |
29 | #define CDNS_GPIO_IRQ_VALUE 0x28 |
30 | #define CDNS_GPIO_IRQ_ANY_EDGE 0x2c |
31 | |
32 | struct cdns_gpio_chip { |
33 | struct gpio_chip gc; |
34 | struct clk *pclk; |
35 | void __iomem *regs; |
36 | u32 bypass_orig; |
37 | }; |
38 | |
39 | static int cdns_gpio_request(struct gpio_chip *chip, unsigned int offset) |
40 | { |
41 | struct cdns_gpio_chip *cgpio = gpiochip_get_data(gc: chip); |
42 | unsigned long flags; |
43 | |
44 | raw_spin_lock_irqsave(&chip->bgpio_lock, flags); |
45 | |
46 | iowrite32(ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE) & ~BIT(offset), |
47 | cgpio->regs + CDNS_GPIO_BYPASS_MODE); |
48 | |
49 | raw_spin_unlock_irqrestore(&chip->bgpio_lock, flags); |
50 | return 0; |
51 | } |
52 | |
53 | static void cdns_gpio_free(struct gpio_chip *chip, unsigned int offset) |
54 | { |
55 | struct cdns_gpio_chip *cgpio = gpiochip_get_data(gc: chip); |
56 | unsigned long flags; |
57 | |
58 | raw_spin_lock_irqsave(&chip->bgpio_lock, flags); |
59 | |
60 | iowrite32(ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE) | |
61 | (BIT(offset) & cgpio->bypass_orig), |
62 | cgpio->regs + CDNS_GPIO_BYPASS_MODE); |
63 | |
64 | raw_spin_unlock_irqrestore(&chip->bgpio_lock, flags); |
65 | } |
66 | |
67 | static void cdns_gpio_irq_mask(struct irq_data *d) |
68 | { |
69 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); |
70 | struct cdns_gpio_chip *cgpio = gpiochip_get_data(gc: chip); |
71 | |
72 | iowrite32(BIT(d->hwirq), cgpio->regs + CDNS_GPIO_IRQ_DIS); |
73 | gpiochip_disable_irq(gc: chip, offset: irqd_to_hwirq(d)); |
74 | } |
75 | |
76 | static void cdns_gpio_irq_unmask(struct irq_data *d) |
77 | { |
78 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); |
79 | struct cdns_gpio_chip *cgpio = gpiochip_get_data(gc: chip); |
80 | |
81 | gpiochip_enable_irq(gc: chip, offset: irqd_to_hwirq(d)); |
82 | iowrite32(BIT(d->hwirq), cgpio->regs + CDNS_GPIO_IRQ_EN); |
83 | } |
84 | |
85 | static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type) |
86 | { |
87 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d); |
88 | struct cdns_gpio_chip *cgpio = gpiochip_get_data(gc: chip); |
89 | unsigned long flags; |
90 | u32 int_value; |
91 | u32 int_type; |
92 | u32 mask = BIT(d->hwirq); |
93 | int ret = 0; |
94 | |
95 | raw_spin_lock_irqsave(&chip->bgpio_lock, flags); |
96 | |
97 | int_value = ioread32(cgpio->regs + CDNS_GPIO_IRQ_VALUE) & ~mask; |
98 | int_type = ioread32(cgpio->regs + CDNS_GPIO_IRQ_TYPE) & ~mask; |
99 | |
100 | /* |
101 | * The GPIO controller doesn't have an ACK register. |
102 | * All interrupt statuses are cleared on a status register read. |
103 | * Don't support edge interrupts for now. |
104 | */ |
105 | |
106 | if (type == IRQ_TYPE_LEVEL_HIGH) { |
107 | int_type |= mask; |
108 | int_value |= mask; |
109 | } else if (type == IRQ_TYPE_LEVEL_LOW) { |
110 | int_type |= mask; |
111 | } else { |
112 | ret = -EINVAL; |
113 | goto err_irq_type; |
114 | } |
115 | |
116 | iowrite32(int_value, cgpio->regs + CDNS_GPIO_IRQ_VALUE); |
117 | iowrite32(int_type, cgpio->regs + CDNS_GPIO_IRQ_TYPE); |
118 | |
119 | err_irq_type: |
120 | raw_spin_unlock_irqrestore(&chip->bgpio_lock, flags); |
121 | return ret; |
122 | } |
123 | |
124 | static void cdns_gpio_irq_handler(struct irq_desc *desc) |
125 | { |
126 | struct gpio_chip *chip = irq_desc_get_handler_data(desc); |
127 | struct cdns_gpio_chip *cgpio = gpiochip_get_data(gc: chip); |
128 | struct irq_chip *irqchip = irq_desc_get_chip(desc); |
129 | unsigned long status; |
130 | int hwirq; |
131 | |
132 | chained_irq_enter(chip: irqchip, desc); |
133 | |
134 | status = ioread32(cgpio->regs + CDNS_GPIO_IRQ_STATUS) & |
135 | ~ioread32(cgpio->regs + CDNS_GPIO_IRQ_MASK); |
136 | |
137 | for_each_set_bit(hwirq, &status, chip->ngpio) |
138 | generic_handle_domain_irq(domain: chip->irq.domain, hwirq); |
139 | |
140 | chained_irq_exit(chip: irqchip, desc); |
141 | } |
142 | |
143 | static const struct irq_chip cdns_gpio_irqchip = { |
144 | .name = "cdns-gpio" , |
145 | .irq_mask = cdns_gpio_irq_mask, |
146 | .irq_unmask = cdns_gpio_irq_unmask, |
147 | .irq_set_type = cdns_gpio_irq_set_type, |
148 | .flags = IRQCHIP_IMMUTABLE, |
149 | GPIOCHIP_IRQ_RESOURCE_HELPERS, |
150 | }; |
151 | |
152 | static int cdns_gpio_probe(struct platform_device *pdev) |
153 | { |
154 | struct cdns_gpio_chip *cgpio; |
155 | int ret, irq; |
156 | u32 dir_prev; |
157 | u32 num_gpios = 32; |
158 | |
159 | cgpio = devm_kzalloc(dev: &pdev->dev, size: sizeof(*cgpio), GFP_KERNEL); |
160 | if (!cgpio) |
161 | return -ENOMEM; |
162 | |
163 | cgpio->regs = devm_platform_ioremap_resource(pdev, index: 0); |
164 | if (IS_ERR(ptr: cgpio->regs)) |
165 | return PTR_ERR(ptr: cgpio->regs); |
166 | |
167 | of_property_read_u32(np: pdev->dev.of_node, propname: "ngpios" , out_value: &num_gpios); |
168 | |
169 | if (num_gpios > 32) { |
170 | dev_err(&pdev->dev, "ngpios must be less or equal 32\n" ); |
171 | return -EINVAL; |
172 | } |
173 | |
174 | /* |
175 | * Set all pins as inputs by default, otherwise: |
176 | * gpiochip_lock_as_irq: |
177 | * tried to flag a GPIO set as output for IRQ |
178 | * Generic GPIO driver stores the direction value internally, |
179 | * so it needs to be changed before bgpio_init() is called. |
180 | */ |
181 | dir_prev = ioread32(cgpio->regs + CDNS_GPIO_DIRECTION_MODE); |
182 | iowrite32(GENMASK(num_gpios - 1, 0), |
183 | cgpio->regs + CDNS_GPIO_DIRECTION_MODE); |
184 | |
185 | ret = bgpio_init(gc: &cgpio->gc, dev: &pdev->dev, sz: 4, |
186 | dat: cgpio->regs + CDNS_GPIO_INPUT_VALUE, |
187 | set: cgpio->regs + CDNS_GPIO_OUTPUT_VALUE, |
188 | NULL, |
189 | NULL, |
190 | dirin: cgpio->regs + CDNS_GPIO_DIRECTION_MODE, |
191 | BGPIOF_READ_OUTPUT_REG_SET); |
192 | if (ret) { |
193 | dev_err(&pdev->dev, "Failed to register generic gpio, %d\n" , |
194 | ret); |
195 | goto err_revert_dir; |
196 | } |
197 | |
198 | cgpio->gc.label = dev_name(dev: &pdev->dev); |
199 | cgpio->gc.ngpio = num_gpios; |
200 | cgpio->gc.parent = &pdev->dev; |
201 | cgpio->gc.base = -1; |
202 | cgpio->gc.owner = THIS_MODULE; |
203 | cgpio->gc.request = cdns_gpio_request; |
204 | cgpio->gc.free = cdns_gpio_free; |
205 | |
206 | cgpio->pclk = devm_clk_get(dev: &pdev->dev, NULL); |
207 | if (IS_ERR(ptr: cgpio->pclk)) { |
208 | ret = PTR_ERR(ptr: cgpio->pclk); |
209 | dev_err(&pdev->dev, |
210 | "Failed to retrieve peripheral clock, %d\n" , ret); |
211 | goto err_revert_dir; |
212 | } |
213 | |
214 | ret = clk_prepare_enable(clk: cgpio->pclk); |
215 | if (ret) { |
216 | dev_err(&pdev->dev, |
217 | "Failed to enable the peripheral clock, %d\n" , ret); |
218 | goto err_revert_dir; |
219 | } |
220 | |
221 | /* |
222 | * Optional irq_chip support |
223 | */ |
224 | irq = platform_get_irq(pdev, 0); |
225 | if (irq >= 0) { |
226 | struct gpio_irq_chip *girq; |
227 | |
228 | girq = &cgpio->gc.irq; |
229 | gpio_irq_chip_set_chip(girq, chip: &cdns_gpio_irqchip); |
230 | girq->parent_handler = cdns_gpio_irq_handler; |
231 | girq->num_parents = 1; |
232 | girq->parents = devm_kcalloc(dev: &pdev->dev, n: 1, |
233 | size: sizeof(*girq->parents), |
234 | GFP_KERNEL); |
235 | if (!girq->parents) { |
236 | ret = -ENOMEM; |
237 | goto err_disable_clk; |
238 | } |
239 | girq->parents[0] = irq; |
240 | girq->default_type = IRQ_TYPE_NONE; |
241 | girq->handler = handle_level_irq; |
242 | } |
243 | |
244 | ret = devm_gpiochip_add_data(&pdev->dev, &cgpio->gc, cgpio); |
245 | if (ret < 0) { |
246 | dev_err(&pdev->dev, "Could not register gpiochip, %d\n" , ret); |
247 | goto err_disable_clk; |
248 | } |
249 | |
250 | cgpio->bypass_orig = ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE); |
251 | |
252 | /* |
253 | * Enable gpio outputs, ignored for input direction |
254 | */ |
255 | iowrite32(GENMASK(num_gpios - 1, 0), |
256 | cgpio->regs + CDNS_GPIO_OUTPUT_EN); |
257 | iowrite32(0, cgpio->regs + CDNS_GPIO_BYPASS_MODE); |
258 | |
259 | platform_set_drvdata(pdev, data: cgpio); |
260 | return 0; |
261 | |
262 | err_disable_clk: |
263 | clk_disable_unprepare(clk: cgpio->pclk); |
264 | |
265 | err_revert_dir: |
266 | iowrite32(dir_prev, cgpio->regs + CDNS_GPIO_DIRECTION_MODE); |
267 | |
268 | return ret; |
269 | } |
270 | |
271 | static void cdns_gpio_remove(struct platform_device *pdev) |
272 | { |
273 | struct cdns_gpio_chip *cgpio = platform_get_drvdata(pdev); |
274 | |
275 | iowrite32(cgpio->bypass_orig, cgpio->regs + CDNS_GPIO_BYPASS_MODE); |
276 | clk_disable_unprepare(clk: cgpio->pclk); |
277 | } |
278 | |
279 | static const struct of_device_id cdns_of_ids[] = { |
280 | { .compatible = "cdns,gpio-r1p02" }, |
281 | { /* sentinel */ }, |
282 | }; |
283 | MODULE_DEVICE_TABLE(of, cdns_of_ids); |
284 | |
285 | static struct platform_driver cdns_gpio_driver = { |
286 | .driver = { |
287 | .name = "cdns-gpio" , |
288 | .of_match_table = cdns_of_ids, |
289 | }, |
290 | .probe = cdns_gpio_probe, |
291 | .remove_new = cdns_gpio_remove, |
292 | }; |
293 | module_platform_driver(cdns_gpio_driver); |
294 | |
295 | MODULE_AUTHOR("Jan Kotas <jank@cadence.com>" ); |
296 | MODULE_DESCRIPTION("Cadence GPIO driver" ); |
297 | MODULE_LICENSE("GPL v2" ); |
298 | MODULE_ALIAS("platform:cdns-gpio" ); |
299 | |