File Index
Files and directories
Sign in
FILE

gpio-lpc18xx.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpio/gpio-lpc18xx.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * GPIO driver for NXP LPC18xx/43xx.
  4 *
  5 * Copyright (C) 2018 Vladimir Zapolskiy <vz@mleia.com>
  6 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
  7 *
  8 */
  9
 10#include <linux/clk.h>
 11#include <linux/gpio/driver.h>
 12#include <linux/io.h>
 13#include <linux/irqdomain.h>
 14#include <linux/module.h>
 15#include <linux/of.h>
 16#include <linux/of_address.h>
 17#include <linux/of_irq.h>
 18#include <linux/pinctrl/consumer.h>
 19#include <linux/platform_device.h>
 20
 21/* LPC18xx GPIO register offsets */
 22#define LPC18XX_REG_DIR(n)	(0x2000 + n * sizeof(u32))
 23
 24#define LPC18XX_MAX_PORTS	8
 25#define LPC18XX_PINS_PER_PORT	32
 26
 27/* LPC18xx GPIO pin interrupt controller register offsets */
 28#define LPC18XX_GPIO_PIN_IC_ISEL	0x00
 29#define LPC18XX_GPIO_PIN_IC_IENR	0x04
 30#define LPC18XX_GPIO_PIN_IC_SIENR	0x08
 31#define LPC18XX_GPIO_PIN_IC_CIENR	0x0c
 32#define LPC18XX_GPIO_PIN_IC_IENF	0x10
 33#define LPC18XX_GPIO_PIN_IC_SIENF	0x14
 34#define LPC18XX_GPIO_PIN_IC_CIENF	0x18
 35#define LPC18XX_GPIO_PIN_IC_RISE	0x1c
 36#define LPC18XX_GPIO_PIN_IC_FALL	0x20
 37#define LPC18XX_GPIO_PIN_IC_IST		0x24
 38
 39#define NR_LPC18XX_GPIO_PIN_IC_IRQS	8
 40
 41struct lpc18xx_gpio_pin_ic {
 42	void __iomem *base;
 43	struct irq_domain *domain;
 44	struct raw_spinlock lock;
 45	struct gpio_chip *gpio;
 46};
 47
 48struct lpc18xx_gpio_chip {
 49	struct gpio_chip gpio;
 50	void __iomem *base;
 51	struct lpc18xx_gpio_pin_ic *pin_ic;
 52	spinlock_t lock;
 53};
 54
 55static inline void lpc18xx_gpio_pin_ic_isel(struct lpc18xx_gpio_pin_ic *ic,
 56					    u32 pin, bool set)
 57{
 58	u32 val = readl_relaxed(ic->base + LPC18XX_GPIO_PIN_IC_ISEL);
 59
 60	if (set)
 61		val &= ~BIT(pin);
 62	else
 63		val |= BIT(pin);
 64
 65	writel_relaxed(val, ic->base + LPC18XX_GPIO_PIN_IC_ISEL);
 66}
 67
 68static inline void lpc18xx_gpio_pin_ic_set(struct lpc18xx_gpio_pin_ic *ic,
 69					   u32 pin, u32 reg)
 70{
 71	writel_relaxed(BIT(pin), ic->base + reg);
 72}
 73
 74static void lpc18xx_gpio_pin_ic_mask(struct irq_data *d)
 75{
 76	struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
 77	u32 type = irqd_get_trigger_type(d);
 78	irq_hw_number_t hwirq = irqd_to_hwirq(d);
 79
 80	raw_spin_lock(&ic->lock);
 81
 82	if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING)
 83		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
 84					LPC18XX_GPIO_PIN_IC_CIENR);
 85
 86	if (type & IRQ_TYPE_EDGE_FALLING)
 87		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
 88					LPC18XX_GPIO_PIN_IC_CIENF);
 89
 90	raw_spin_unlock(&ic->lock);
 91
 92	irq_chip_mask_parent(d);
 93
 94	gpiochip_disable_irq(ic->gpio, hwirq);
 95}
 96
 97static void lpc18xx_gpio_pin_ic_unmask(struct irq_data *d)
 98{
 99	struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
100	u32 type = irqd_get_trigger_type(d);
101	irq_hw_number_t hwirq = irqd_to_hwirq(d);
102
103	gpiochip_enable_irq(ic->gpio, hwirq);
104
105	raw_spin_lock(&ic->lock);
106
107	if (type & IRQ_TYPE_LEVEL_MASK || type & IRQ_TYPE_EDGE_RISING)
108		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
109					LPC18XX_GPIO_PIN_IC_SIENR);
110
111	if (type & IRQ_TYPE_EDGE_FALLING)
112		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
113					LPC18XX_GPIO_PIN_IC_SIENF);
114
115	raw_spin_unlock(&ic->lock);
116
117	irq_chip_unmask_parent(d);
118}
119
120static void lpc18xx_gpio_pin_ic_eoi(struct irq_data *d)
121{
122	struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
123	u32 type = irqd_get_trigger_type(d);
124
125	raw_spin_lock(&ic->lock);
126
127	if (type & IRQ_TYPE_EDGE_BOTH)
128		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
129					LPC18XX_GPIO_PIN_IC_IST);
130
131	raw_spin_unlock(&ic->lock);
132
133	irq_chip_eoi_parent(d);
134}
135
136static int lpc18xx_gpio_pin_ic_set_type(struct irq_data *d, unsigned int type)
137{
138	struct lpc18xx_gpio_pin_ic *ic = d->chip_data;
139
140	raw_spin_lock(&ic->lock);
141
142	if (type & IRQ_TYPE_LEVEL_HIGH) {
143		lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true);
144		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
145					LPC18XX_GPIO_PIN_IC_SIENF);
146	} else if (type & IRQ_TYPE_LEVEL_LOW) {
147		lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, true);
148		lpc18xx_gpio_pin_ic_set(ic, d->hwirq,
149					LPC18XX_GPIO_PIN_IC_CIENF);
150	} else {
151		lpc18xx_gpio_pin_ic_isel(ic, d->hwirq, false);
152	}
153
154	raw_spin_unlock(&ic->lock);
155
156	return 0;
157}
158
159static const struct irq_chip lpc18xx_gpio_pin_ic = {
160	.name		= "LPC18xx GPIO pin",
161	.irq_mask	= lpc18xx_gpio_pin_ic_mask,
162	.irq_unmask	= lpc18xx_gpio_pin_ic_unmask,
163	.irq_eoi	= lpc18xx_gpio_pin_ic_eoi,
164	.irq_set_type	= lpc18xx_gpio_pin_ic_set_type,
165	.flags		= IRQCHIP_IMMUTABLE | IRQCHIP_SET_TYPE_MASKED,
166	GPIOCHIP_IRQ_RESOURCE_HELPERS,
167};
168
169static int lpc18xx_gpio_pin_ic_domain_alloc(struct irq_domain *domain,
170					    unsigned int virq,
171					    unsigned int nr_irqs, void *data)
172{
173	struct irq_fwspec parent_fwspec, *fwspec = data;
174	struct lpc18xx_gpio_pin_ic *ic = domain->host_data;
175	irq_hw_number_t hwirq;
176	int ret;
177
178	if (nr_irqs != 1)
179		return -EINVAL;
180
181	hwirq = fwspec->param[0];
182	if (hwirq >= NR_LPC18XX_GPIO_PIN_IC_IRQS)
183		return -EINVAL;
184
185	/*
186	 * All LPC18xx/LPC43xx GPIO pin hardware interrupts are translated
187	 * into edge interrupts 32...39 on parent Cortex-M3/M4 NVIC
188	 */
189	parent_fwspec.fwnode = domain->parent->fwnode;
190	parent_fwspec.param_count = 1;
191	parent_fwspec.param[0] = hwirq + 32;
192
193	ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
194	if (ret < 0) {
195		pr_err("failed to allocate parent irq %u: %d\n",
196		       parent_fwspec.param[0], ret);
197		return ret;
198	}
199
200	return irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
201					     &lpc18xx_gpio_pin_ic, ic);
202}
203
204static const struct irq_domain_ops lpc18xx_gpio_pin_ic_domain_ops = {
205	.alloc	= lpc18xx_gpio_pin_ic_domain_alloc,
206	.xlate	= irq_domain_xlate_twocell,
207	.free	= irq_domain_free_irqs_common,
208};
209
210static int lpc18xx_gpio_pin_ic_probe(struct lpc18xx_gpio_chip *gc)
211{
212	struct device *dev = gc->gpio.parent;
213	struct irq_domain *parent_domain;
214	struct device_node *parent_node;
215	struct lpc18xx_gpio_pin_ic *ic;
216	struct resource res;
217	int ret, index;
218
219	parent_node = of_irq_find_parent(dev->of_node);
220	if (!parent_node)
221		return -ENXIO;
222
223	parent_domain = irq_find_host(parent_node);
224	of_node_put(parent_node);
225	if (!parent_domain)
226		return -ENXIO;
227
228	ic = devm_kzalloc(dev, sizeof(*ic), GFP_KERNEL);
229	if (!ic)
230		return -ENOMEM;
231
232	index = of_property_match_string(dev->of_node, "reg-names",
233					 "gpio-pin-ic");
234	if (index < 0) {
235		ret = -ENODEV;
236		goto free_ic;
237	}
238
239	ret = of_address_to_resource(dev->of_node, index, &res);
240	if (ret < 0)
241		goto free_ic;
242
243	ic->base = devm_ioremap_resource(dev, &res);
244	if (IS_ERR(ic->base)) {
245		ret = PTR_ERR(ic->base);
246		goto free_ic;
247	}
248
249	raw_spin_lock_init(&ic->lock);
250
251	ic->domain = irq_domain_create_hierarchy(parent_domain, 0, NR_LPC18XX_GPIO_PIN_IC_IRQS,
252						 dev_fwnode(dev), &lpc18xx_gpio_pin_ic_domain_ops,
253						 ic);
254	if (!ic->domain) {
255		pr_err("unable to add irq domain\n");
256		ret = -ENODEV;
257		goto free_iomap;
258	}
259
260	ic->gpio = &gc->gpio;
261	gc->pin_ic = ic;
262
263	return 0;
264
265free_iomap:
266	devm_iounmap(dev, ic->base);
267free_ic:
268	devm_kfree(dev, ic);
269
270	return ret;
271}
272
273static int lpc18xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
274			    int value)
275{
276	struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
277
278	writeb(value ? 1 : 0, gc->base + offset);
279
280	return 0;
281}
282
283static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset)
284{
285	struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
286	return !!readb(gc->base + offset);
287}
288
289static int lpc18xx_gpio_direction(struct gpio_chip *chip, unsigned offset,
290				  bool out)
291{
292	struct lpc18xx_gpio_chip *gc = gpiochip_get_data(chip);
293	unsigned long flags;
294	u32 port, pin, dir;
295
296	port = offset / LPC18XX_PINS_PER_PORT;
297	pin  = offset % LPC18XX_PINS_PER_PORT;
298
299	spin_lock_irqsave(&gc->lock, flags);
300	dir = readl(gc->base + LPC18XX_REG_DIR(port));
301	if (out)
302		dir |= BIT(pin);
303	else
304		dir &= ~BIT(pin);
305	writel(dir, gc->base + LPC18XX_REG_DIR(port));
306	spin_unlock_irqrestore(&gc->lock, flags);
307
308	return 0;
309}
310
311static int lpc18xx_gpio_direction_input(struct gpio_chip *chip,
312					unsigned offset)
313{
314	return lpc18xx_gpio_direction(chip, offset, false);
315}
316
317static int lpc18xx_gpio_direction_output(struct gpio_chip *chip,
318					 unsigned offset, int value)
319{
320	lpc18xx_gpio_set(chip, offset, value);
321	return lpc18xx_gpio_direction(chip, offset, true);
322}
323
324static const struct gpio_chip lpc18xx_chip = {
325	.label			= "lpc18xx/43xx-gpio",
326	.request		= gpiochip_generic_request,
327	.free			= gpiochip_generic_free,
328	.direction_input	= lpc18xx_gpio_direction_input,
329	.direction_output	= lpc18xx_gpio_direction_output,
330	.set			= lpc18xx_gpio_set,
331	.get			= lpc18xx_gpio_get,
332	.ngpio			= LPC18XX_MAX_PORTS * LPC18XX_PINS_PER_PORT,
333	.owner			= THIS_MODULE,
334};
335
336static int lpc18xx_gpio_probe(struct platform_device *pdev)
337{
338	struct device *dev = &pdev->dev;
339	struct lpc18xx_gpio_chip *gc;
340	int index, ret;
341	struct clk *clk;
342
343	gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
344	if (!gc)
345		return -ENOMEM;
346
347	gc->gpio = lpc18xx_chip;
348	platform_set_drvdata(pdev, gc);
349
350	index = of_property_match_string(dev->of_node, "reg-names", "gpio");
351	if (index < 0) {
352		/* To support backward compatibility take the first resource */
353		gc->base = devm_platform_ioremap_resource(pdev, 0);
354	} else {
355		struct resource res;
356
357		ret = of_address_to_resource(dev->of_node, index, &res);
358		if (ret < 0)
359			return ret;
360
361		gc->base = devm_ioremap_resource(dev, &res);
362	}
363	if (IS_ERR(gc->base))
364		return PTR_ERR(gc->base);
365
366	clk = devm_clk_get_enabled(dev, NULL);
367	if (IS_ERR(clk)) {
368		dev_err(dev, "input clock not found\n");
369		return PTR_ERR(clk);
370	}
371
372	spin_lock_init(&gc->lock);
373
374	gc->gpio.parent = dev;
375
376	ret = devm_gpiochip_add_data(dev, &gc->gpio, gc);
377	if (ret)
378		return dev_err_probe(dev, ret, "failed to add gpio chip\n");
379
380	/* On error GPIO pin interrupt controller just won't be registered */
381	lpc18xx_gpio_pin_ic_probe(gc);
382
383	return 0;
384}
385
386static void lpc18xx_gpio_remove(struct platform_device *pdev)
387{
388	struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev);
389
390	if (gc->pin_ic)
391		irq_domain_remove(gc->pin_ic->domain);
392}
393
394static const struct of_device_id lpc18xx_gpio_match[] = {
395	{ .compatible = "nxp,lpc1850-gpio" },
396	{ }
397};
398MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match);
399
400static struct platform_driver lpc18xx_gpio_driver = {
401	.probe	= lpc18xx_gpio_probe,
402	.remove	= lpc18xx_gpio_remove,
403	.driver	= {
404		.name		= "lpc18xx-gpio",
405		.of_match_table	= lpc18xx_gpio_match,
406	},
407};
408module_platform_driver(lpc18xx_gpio_driver);
409
410MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
411MODULE_AUTHOR("Vladimir Zapolskiy <vz@mleia.com>");
412MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx");
413MODULE_LICENSE("GPL v2");
~/ Read-only file preview.