1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (C) 2022 Microchip Technology Inc. |
3 | // pci1xxxx gpio driver |
4 | |
5 | #include <linux/module.h> |
6 | #include <linux/spinlock.h> |
7 | #include <linux/gpio/driver.h> |
8 | #include <linux/bio.h> |
9 | #include <linux/mutex.h> |
10 | #include <linux/kthread.h> |
11 | #include <linux/interrupt.h> |
12 | |
13 | #include "mchp_pci1xxxx_gp.h" |
14 | |
15 | #define PCI1XXXX_NR_PINS 93 |
16 | #define PERI_GEN_RESET 0 |
17 | #define OUT_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400) |
18 | #define INP_EN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x10) |
19 | #define OUT_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x20) |
20 | #define INP_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x30) |
21 | #define PULLUP_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x40) |
22 | #define PULLDOWN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x50) |
23 | #define OPENDRAIN_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x60) |
24 | #define WAKEMASK_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x70) |
25 | #define MODE_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x80) |
26 | #define INTR_LO_TO_HI_EDGE_CONFIG(x) ((((x) / 32) * 4) + 0x400 + 0x90) |
27 | #define INTR_HI_TO_LO_EDGE_CONFIG(x) ((((x) / 32) * 4) + 0x400 + 0xA0) |
28 | #define INTR_LEVEL_CONFIG_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0xB0) |
29 | #define INTR_LEVEL_MASK_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0xC0) |
30 | #define INTR_STAT_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0xD0) |
31 | #define DEBOUNCE_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0xE0) |
32 | #define PIO_GLOBAL_CONFIG_OFFSET (0x400 + 0xF0) |
33 | #define PIO_PCI_CTRL_REG_OFFSET (0x400 + 0xF4) |
34 | #define INTR_MASK_OFFSET(x) ((((x) / 32) * 4) + 0x400 + 0x100) |
35 | #define INTR_STATUS_OFFSET(x) (((x) * 4) + 0x400 + 0xD0) |
36 | |
37 | struct pci1xxxx_gpio { |
38 | struct auxiliary_device *aux_dev; |
39 | void __iomem *reg_base; |
40 | struct gpio_chip gpio; |
41 | spinlock_t lock; |
42 | int irq_base; |
43 | }; |
44 | |
45 | static int pci1xxxx_gpio_get_direction(struct gpio_chip *gpio, unsigned int nr) |
46 | { |
47 | struct pci1xxxx_gpio *priv = gpiochip_get_data(gc: gpio); |
48 | u32 data; |
49 | int ret = -EINVAL; |
50 | |
51 | data = readl(addr: priv->reg_base + INP_EN_OFFSET(nr)); |
52 | if (data & BIT(nr % 32)) { |
53 | ret = 1; |
54 | } else { |
55 | data = readl(addr: priv->reg_base + OUT_EN_OFFSET(nr)); |
56 | if (data & BIT(nr % 32)) |
57 | ret = 0; |
58 | } |
59 | |
60 | return ret; |
61 | } |
62 | |
63 | static inline void pci1xxx_assign_bit(void __iomem *base_addr, unsigned int reg_offset, |
64 | unsigned int bitpos, bool set) |
65 | { |
66 | u32 data; |
67 | |
68 | data = readl(addr: base_addr + reg_offset); |
69 | if (set) |
70 | data |= BIT(bitpos); |
71 | else |
72 | data &= ~BIT(bitpos); |
73 | writel(val: data, addr: base_addr + reg_offset); |
74 | } |
75 | |
76 | static int pci1xxxx_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr) |
77 | { |
78 | struct pci1xxxx_gpio *priv = gpiochip_get_data(gc: gpio); |
79 | unsigned long flags; |
80 | |
81 | spin_lock_irqsave(&priv->lock, flags); |
82 | pci1xxx_assign_bit(base_addr: priv->reg_base, INP_EN_OFFSET(nr), bitpos: (nr % 32), set: true); |
83 | pci1xxx_assign_bit(base_addr: priv->reg_base, OUT_EN_OFFSET(nr), bitpos: (nr % 32), set: false); |
84 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
85 | |
86 | return 0; |
87 | } |
88 | |
89 | static int pci1xxxx_gpio_get(struct gpio_chip *gpio, unsigned int nr) |
90 | { |
91 | struct pci1xxxx_gpio *priv = gpiochip_get_data(gc: gpio); |
92 | |
93 | return (readl(addr: priv->reg_base + INP_OFFSET(nr)) >> (nr % 32)) & 1; |
94 | } |
95 | |
96 | static int pci1xxxx_gpio_direction_output(struct gpio_chip *gpio, |
97 | unsigned int nr, int val) |
98 | { |
99 | struct pci1xxxx_gpio *priv = gpiochip_get_data(gc: gpio); |
100 | unsigned long flags; |
101 | u32 data; |
102 | |
103 | spin_lock_irqsave(&priv->lock, flags); |
104 | pci1xxx_assign_bit(base_addr: priv->reg_base, INP_EN_OFFSET(nr), bitpos: (nr % 32), set: false); |
105 | pci1xxx_assign_bit(base_addr: priv->reg_base, OUT_EN_OFFSET(nr), bitpos: (nr % 32), set: true); |
106 | data = readl(addr: priv->reg_base + OUT_OFFSET(nr)); |
107 | if (val) |
108 | data |= (1 << (nr % 32)); |
109 | else |
110 | data &= ~(1 << (nr % 32)); |
111 | writel(val: data, addr: priv->reg_base + OUT_OFFSET(nr)); |
112 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
113 | |
114 | return 0; |
115 | } |
116 | |
117 | static void pci1xxxx_gpio_set(struct gpio_chip *gpio, |
118 | unsigned int nr, int val) |
119 | { |
120 | struct pci1xxxx_gpio *priv = gpiochip_get_data(gc: gpio); |
121 | unsigned long flags; |
122 | |
123 | spin_lock_irqsave(&priv->lock, flags); |
124 | pci1xxx_assign_bit(base_addr: priv->reg_base, OUT_OFFSET(nr), bitpos: (nr % 32), set: val); |
125 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
126 | } |
127 | |
128 | static int pci1xxxx_gpio_set_config(struct gpio_chip *gpio, unsigned int offset, |
129 | unsigned long config) |
130 | { |
131 | struct pci1xxxx_gpio *priv = gpiochip_get_data(gc: gpio); |
132 | unsigned long flags; |
133 | int ret = 0; |
134 | |
135 | spin_lock_irqsave(&priv->lock, flags); |
136 | switch (pinconf_to_config_param(config)) { |
137 | case PIN_CONFIG_BIAS_PULL_UP: |
138 | pci1xxx_assign_bit(base_addr: priv->reg_base, PULLUP_OFFSET(offset), bitpos: (offset % 32), set: true); |
139 | break; |
140 | case PIN_CONFIG_BIAS_PULL_DOWN: |
141 | pci1xxx_assign_bit(base_addr: priv->reg_base, PULLDOWN_OFFSET(offset), bitpos: (offset % 32), set: true); |
142 | break; |
143 | case PIN_CONFIG_BIAS_DISABLE: |
144 | pci1xxx_assign_bit(base_addr: priv->reg_base, PULLUP_OFFSET(offset), bitpos: (offset % 32), set: false); |
145 | pci1xxx_assign_bit(base_addr: priv->reg_base, PULLDOWN_OFFSET(offset), bitpos: (offset % 32), set: false); |
146 | break; |
147 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: |
148 | pci1xxx_assign_bit(base_addr: priv->reg_base, OPENDRAIN_OFFSET(offset), bitpos: (offset % 32), set: true); |
149 | break; |
150 | default: |
151 | ret = -EOPNOTSUPP; |
152 | break; |
153 | } |
154 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
155 | |
156 | return ret; |
157 | } |
158 | |
159 | static void pci1xxxx_gpio_irq_ack(struct irq_data *data) |
160 | { |
161 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d: data); |
162 | struct pci1xxxx_gpio *priv = gpiochip_get_data(gc: chip); |
163 | unsigned int gpio = irqd_to_hwirq(d: data); |
164 | unsigned long flags; |
165 | |
166 | spin_lock_irqsave(&priv->lock, flags); |
167 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_STAT_OFFSET(gpio), bitpos: (gpio % 32), set: true); |
168 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
169 | } |
170 | |
171 | static void pci1xxxx_gpio_irq_set_mask(struct irq_data *data, bool set) |
172 | { |
173 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d: data); |
174 | struct pci1xxxx_gpio *priv = gpiochip_get_data(gc: chip); |
175 | unsigned int gpio = irqd_to_hwirq(d: data); |
176 | unsigned long flags; |
177 | |
178 | if (!set) |
179 | gpiochip_enable_irq(gc: chip, offset: gpio); |
180 | spin_lock_irqsave(&priv->lock, flags); |
181 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_MASK_OFFSET(gpio), bitpos: (gpio % 32), set); |
182 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
183 | if (set) |
184 | gpiochip_disable_irq(gc: chip, offset: gpio); |
185 | } |
186 | |
187 | static void pci1xxxx_gpio_irq_mask(struct irq_data *data) |
188 | { |
189 | pci1xxxx_gpio_irq_set_mask(data, set: true); |
190 | } |
191 | |
192 | static void pci1xxxx_gpio_irq_unmask(struct irq_data *data) |
193 | { |
194 | pci1xxxx_gpio_irq_set_mask(data, set: false); |
195 | } |
196 | |
197 | static int pci1xxxx_gpio_set_type(struct irq_data *data, unsigned int trigger_type) |
198 | { |
199 | struct gpio_chip *chip = irq_data_get_irq_chip_data(d: data); |
200 | struct pci1xxxx_gpio *priv = gpiochip_get_data(gc: chip); |
201 | unsigned int gpio = irqd_to_hwirq(d: data); |
202 | unsigned int bitpos = gpio % 32; |
203 | |
204 | if (trigger_type & IRQ_TYPE_EDGE_FALLING) { |
205 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_HI_TO_LO_EDGE_CONFIG(gpio), |
206 | bitpos, set: false); |
207 | pci1xxx_assign_bit(base_addr: priv->reg_base, MODE_OFFSET(gpio), |
208 | bitpos, set: false); |
209 | irq_set_handler_locked(data, handler: handle_edge_irq); |
210 | } else { |
211 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_HI_TO_LO_EDGE_CONFIG(gpio), |
212 | bitpos, set: true); |
213 | } |
214 | |
215 | if (trigger_type & IRQ_TYPE_EDGE_RISING) { |
216 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_LO_TO_HI_EDGE_CONFIG(gpio), |
217 | bitpos, set: false); |
218 | pci1xxx_assign_bit(base_addr: priv->reg_base, MODE_OFFSET(gpio), bitpos, |
219 | set: false); |
220 | irq_set_handler_locked(data, handler: handle_edge_irq); |
221 | } else { |
222 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_LO_TO_HI_EDGE_CONFIG(gpio), |
223 | bitpos, set: true); |
224 | } |
225 | |
226 | if (trigger_type & IRQ_TYPE_LEVEL_LOW) { |
227 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_LEVEL_CONFIG_OFFSET(gpio), |
228 | bitpos, set: true); |
229 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_LEVEL_MASK_OFFSET(gpio), |
230 | bitpos, set: false); |
231 | pci1xxx_assign_bit(base_addr: priv->reg_base, MODE_OFFSET(gpio), bitpos, |
232 | set: true); |
233 | irq_set_handler_locked(data, handler: handle_edge_irq); |
234 | } |
235 | |
236 | if (trigger_type & IRQ_TYPE_LEVEL_HIGH) { |
237 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_LEVEL_CONFIG_OFFSET(gpio), |
238 | bitpos, set: false); |
239 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_LEVEL_MASK_OFFSET(gpio), |
240 | bitpos, set: false); |
241 | pci1xxx_assign_bit(base_addr: priv->reg_base, MODE_OFFSET(gpio), bitpos, |
242 | set: true); |
243 | irq_set_handler_locked(data, handler: handle_edge_irq); |
244 | } |
245 | |
246 | if ((!(trigger_type & IRQ_TYPE_LEVEL_LOW)) && (!(trigger_type & IRQ_TYPE_LEVEL_HIGH))) |
247 | pci1xxx_assign_bit(base_addr: priv->reg_base, INTR_LEVEL_MASK_OFFSET(gpio), bitpos, set: true); |
248 | |
249 | return true; |
250 | } |
251 | |
252 | static irqreturn_t pci1xxxx_gpio_irq_handler(int irq, void *dev_id) |
253 | { |
254 | struct pci1xxxx_gpio *priv = dev_id; |
255 | struct gpio_chip *gc = &priv->gpio; |
256 | unsigned long int_status = 0; |
257 | unsigned long flags; |
258 | u8 pincount; |
259 | int bit; |
260 | u8 gpiobank; |
261 | |
262 | spin_lock_irqsave(&priv->lock, flags); |
263 | pci1xxx_assign_bit(base_addr: priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, bitpos: 16, set: true); |
264 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
265 | for (gpiobank = 0; gpiobank < 3; gpiobank++) { |
266 | spin_lock_irqsave(&priv->lock, flags); |
267 | int_status = readl(addr: priv->reg_base + INTR_STATUS_OFFSET(gpiobank)); |
268 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
269 | if (gpiobank == 2) |
270 | pincount = 29; |
271 | else |
272 | pincount = 32; |
273 | for_each_set_bit(bit, &int_status, pincount) { |
274 | unsigned int irq; |
275 | |
276 | spin_lock_irqsave(&priv->lock, flags); |
277 | writel(BIT(bit), addr: priv->reg_base + INTR_STATUS_OFFSET(gpiobank)); |
278 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
279 | irq = irq_find_mapping(domain: gc->irq.domain, hwirq: (bit + (gpiobank * 32))); |
280 | generic_handle_irq(irq); |
281 | } |
282 | } |
283 | spin_lock_irqsave(&priv->lock, flags); |
284 | pci1xxx_assign_bit(base_addr: priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, bitpos: 16, set: false); |
285 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
286 | |
287 | return IRQ_HANDLED; |
288 | } |
289 | |
290 | static const struct irq_chip pci1xxxx_gpio_irqchip = { |
291 | .name = "pci1xxxx_gpio" , |
292 | .irq_ack = pci1xxxx_gpio_irq_ack, |
293 | .irq_mask = pci1xxxx_gpio_irq_mask, |
294 | .irq_unmask = pci1xxxx_gpio_irq_unmask, |
295 | .irq_set_type = pci1xxxx_gpio_set_type, |
296 | .flags = IRQCHIP_IMMUTABLE, |
297 | GPIOCHIP_IRQ_RESOURCE_HELPERS, |
298 | }; |
299 | |
300 | static int pci1xxxx_gpio_suspend(struct device *dev) |
301 | { |
302 | struct pci1xxxx_gpio *priv = dev_get_drvdata(dev); |
303 | unsigned long flags; |
304 | |
305 | spin_lock_irqsave(&priv->lock, flags); |
306 | pci1xxx_assign_bit(base_addr: priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, |
307 | bitpos: 16, set: true); |
308 | pci1xxx_assign_bit(base_addr: priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, |
309 | bitpos: 17, set: false); |
310 | pci1xxx_assign_bit(base_addr: priv->reg_base, PERI_GEN_RESET, bitpos: 16, set: true); |
311 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
312 | |
313 | return 0; |
314 | } |
315 | |
316 | static int pci1xxxx_gpio_resume(struct device *dev) |
317 | { |
318 | struct pci1xxxx_gpio *priv = dev_get_drvdata(dev); |
319 | unsigned long flags; |
320 | |
321 | spin_lock_irqsave(&priv->lock, flags); |
322 | pci1xxx_assign_bit(base_addr: priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, |
323 | bitpos: 17, set: true); |
324 | pci1xxx_assign_bit(base_addr: priv->reg_base, PIO_GLOBAL_CONFIG_OFFSET, |
325 | bitpos: 16, set: false); |
326 | pci1xxx_assign_bit(base_addr: priv->reg_base, PERI_GEN_RESET, bitpos: 16, set: false); |
327 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
328 | |
329 | return 0; |
330 | } |
331 | |
332 | static int pci1xxxx_gpio_setup(struct pci1xxxx_gpio *priv, int irq) |
333 | { |
334 | struct gpio_chip *gchip = &priv->gpio; |
335 | struct gpio_irq_chip *girq; |
336 | int retval; |
337 | |
338 | gchip->label = dev_name(dev: &priv->aux_dev->dev); |
339 | gchip->parent = &priv->aux_dev->dev; |
340 | gchip->owner = THIS_MODULE; |
341 | gchip->direction_input = pci1xxxx_gpio_direction_input; |
342 | gchip->direction_output = pci1xxxx_gpio_direction_output; |
343 | gchip->get_direction = pci1xxxx_gpio_get_direction; |
344 | gchip->get = pci1xxxx_gpio_get; |
345 | gchip->set = pci1xxxx_gpio_set; |
346 | gchip->set_config = pci1xxxx_gpio_set_config; |
347 | gchip->dbg_show = NULL; |
348 | gchip->base = -1; |
349 | gchip->ngpio = PCI1XXXX_NR_PINS; |
350 | gchip->can_sleep = false; |
351 | |
352 | retval = devm_request_threaded_irq(dev: &priv->aux_dev->dev, irq, |
353 | NULL, thread_fn: pci1xxxx_gpio_irq_handler, |
354 | IRQF_ONESHOT, devname: "PCI1xxxxGPIO" , dev_id: priv); |
355 | |
356 | if (retval) |
357 | return retval; |
358 | |
359 | girq = &priv->gpio.irq; |
360 | gpio_irq_chip_set_chip(girq, chip: &pci1xxxx_gpio_irqchip); |
361 | girq->parent_handler = NULL; |
362 | girq->num_parents = 0; |
363 | girq->parents = NULL; |
364 | girq->default_type = IRQ_TYPE_NONE; |
365 | girq->handler = handle_bad_irq; |
366 | |
367 | return 0; |
368 | } |
369 | |
370 | static int pci1xxxx_gpio_probe(struct auxiliary_device *aux_dev, |
371 | const struct auxiliary_device_id *id) |
372 | |
373 | { |
374 | struct auxiliary_device_wrapper *aux_dev_wrapper; |
375 | struct gp_aux_data_type *pdata; |
376 | struct pci1xxxx_gpio *priv; |
377 | int retval; |
378 | |
379 | aux_dev_wrapper = (struct auxiliary_device_wrapper *) |
380 | container_of(aux_dev, struct auxiliary_device_wrapper, aux_dev); |
381 | |
382 | pdata = &aux_dev_wrapper->gp_aux_data; |
383 | |
384 | if (!pdata) |
385 | return -EINVAL; |
386 | |
387 | priv = devm_kzalloc(dev: &aux_dev->dev, size: sizeof(struct pci1xxxx_gpio), GFP_KERNEL); |
388 | if (!priv) |
389 | return -ENOMEM; |
390 | |
391 | spin_lock_init(&priv->lock); |
392 | priv->aux_dev = aux_dev; |
393 | |
394 | if (!devm_request_mem_region(&aux_dev->dev, pdata->region_start, 0x800, aux_dev->name)) |
395 | return -EBUSY; |
396 | |
397 | priv->reg_base = devm_ioremap(dev: &aux_dev->dev, offset: pdata->region_start, size: 0x800); |
398 | if (!priv->reg_base) |
399 | return -ENOMEM; |
400 | |
401 | writel(val: 0x0264, addr: (priv->reg_base + 0x400 + 0xF0)); |
402 | |
403 | retval = pci1xxxx_gpio_setup(priv, irq: pdata->irq_num); |
404 | |
405 | if (retval < 0) |
406 | return retval; |
407 | |
408 | dev_set_drvdata(dev: &aux_dev->dev, data: priv); |
409 | |
410 | return devm_gpiochip_add_data(&aux_dev->dev, &priv->gpio, priv); |
411 | } |
412 | |
413 | static DEFINE_SIMPLE_DEV_PM_OPS(pci1xxxx_gpio_pm_ops, pci1xxxx_gpio_suspend, pci1xxxx_gpio_resume); |
414 | |
415 | static const struct auxiliary_device_id pci1xxxx_gpio_auxiliary_id_table[] = { |
416 | {.name = "mchp_pci1xxxx_gp.gp_gpio" }, |
417 | {} |
418 | }; |
419 | MODULE_DEVICE_TABLE(auxiliary, pci1xxxx_gpio_auxiliary_id_table); |
420 | |
421 | static struct auxiliary_driver pci1xxxx_gpio_driver = { |
422 | .driver = { |
423 | .name = "PCI1xxxxGPIO" , |
424 | .pm = &pci1xxxx_gpio_pm_ops, |
425 | }, |
426 | .probe = pci1xxxx_gpio_probe, |
427 | .id_table = pci1xxxx_gpio_auxiliary_id_table |
428 | }; |
429 | module_auxiliary_driver(pci1xxxx_gpio_driver); |
430 | |
431 | MODULE_DESCRIPTION("Microchip Technology Inc. PCI1xxxx GPIO controller" ); |
432 | MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>" ); |
433 | MODULE_LICENSE("GPL" ); |
434 | |