brintos

brintos / linux-shallow public Read only

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