| // SPDX-License-Identifier: GPL-2.0 | 
 | // | 
 | // IXP4 GPIO driver | 
 | // Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org> | 
 | // | 
 | // based on previous work and know-how from: | 
 | // Deepak Saxena <dsaxena@plexity.net> | 
 |  | 
 | #include <linux/gpio/driver.h> | 
 | #include <linux/io.h> | 
 | #include <linux/irq.h> | 
 | #include <linux/irqdomain.h> | 
 | #include <linux/irqchip.h> | 
 | #include <linux/of_irq.h> | 
 | #include <linux/platform_device.h> | 
 | #include <linux/bitops.h> | 
 |  | 
 | #define IXP4XX_REG_GPOUT	0x00 | 
 | #define IXP4XX_REG_GPOE		0x04 | 
 | #define IXP4XX_REG_GPIN		0x08 | 
 | #define IXP4XX_REG_GPIS		0x0C | 
 | #define IXP4XX_REG_GPIT1	0x10 | 
 | #define IXP4XX_REG_GPIT2	0x14 | 
 | #define IXP4XX_REG_GPCLK	0x18 | 
 | #define IXP4XX_REG_GPDBSEL	0x1C | 
 |  | 
 | /* | 
 |  * The hardware uses 3 bits to indicate interrupt "style". | 
 |  * we clear and set these three bits accordingly. The lower 24 | 
 |  * bits in two registers (GPIT1 and GPIT2) are used to set up | 
 |  * the style for 8 lines each for a total of 16 GPIO lines. | 
 |  */ | 
 | #define IXP4XX_GPIO_STYLE_ACTIVE_HIGH	0x0 | 
 | #define IXP4XX_GPIO_STYLE_ACTIVE_LOW	0x1 | 
 | #define IXP4XX_GPIO_STYLE_RISING_EDGE	0x2 | 
 | #define IXP4XX_GPIO_STYLE_FALLING_EDGE	0x3 | 
 | #define IXP4XX_GPIO_STYLE_TRANSITIONAL	0x4 | 
 | #define IXP4XX_GPIO_STYLE_MASK		GENMASK(2, 0) | 
 | #define IXP4XX_GPIO_STYLE_SIZE		3 | 
 |  | 
 | /** | 
 |  * struct ixp4xx_gpio - IXP4 GPIO state container | 
 |  * @dev: containing device for this instance | 
 |  * @fwnode: the fwnode for this GPIO chip | 
 |  * @gc: gpiochip for this instance | 
 |  * @base: remapped I/O-memory base | 
 |  * @irq_edge: Each bit represents an IRQ: 1: edge-triggered, | 
 |  * 0: level triggered | 
 |  */ | 
 | struct ixp4xx_gpio { | 
 | 	struct device *dev; | 
 | 	struct fwnode_handle *fwnode; | 
 | 	struct gpio_chip gc; | 
 | 	void __iomem *base; | 
 | 	unsigned long long irq_edge; | 
 | }; | 
 |  | 
 | static void ixp4xx_gpio_irq_ack(struct irq_data *d) | 
 | { | 
 | 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | 
 | 	struct ixp4xx_gpio *g = gpiochip_get_data(gc); | 
 |  | 
 | 	__raw_writel(BIT(d->hwirq), g->base + IXP4XX_REG_GPIS); | 
 | } | 
 |  | 
 | static void ixp4xx_gpio_mask_irq(struct irq_data *d) | 
 | { | 
 | 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | 
 |  | 
 | 	irq_chip_mask_parent(d); | 
 | 	gpiochip_disable_irq(gc, d->hwirq); | 
 | } | 
 |  | 
 | static void ixp4xx_gpio_irq_unmask(struct irq_data *d) | 
 | { | 
 | 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | 
 | 	struct ixp4xx_gpio *g = gpiochip_get_data(gc); | 
 |  | 
 | 	/* ACK when unmasking if not edge-triggered */ | 
 | 	if (!(g->irq_edge & BIT(d->hwirq))) | 
 | 		ixp4xx_gpio_irq_ack(d); | 
 |  | 
 | 	gpiochip_enable_irq(gc, d->hwirq); | 
 | 	irq_chip_unmask_parent(d); | 
 | } | 
 |  | 
 | static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type) | 
 | { | 
 | 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | 
 | 	struct ixp4xx_gpio *g = gpiochip_get_data(gc); | 
 | 	int line = d->hwirq; | 
 | 	unsigned long flags; | 
 | 	u32 int_style; | 
 | 	u32 int_reg; | 
 | 	u32 val; | 
 |  | 
 | 	switch (type) { | 
 | 	case IRQ_TYPE_EDGE_BOTH: | 
 | 		irq_set_handler_locked(d, handle_edge_irq); | 
 | 		int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL; | 
 | 		g->irq_edge |= BIT(d->hwirq); | 
 | 		break; | 
 | 	case IRQ_TYPE_EDGE_RISING: | 
 | 		irq_set_handler_locked(d, handle_edge_irq); | 
 | 		int_style = IXP4XX_GPIO_STYLE_RISING_EDGE; | 
 | 		g->irq_edge |= BIT(d->hwirq); | 
 | 		break; | 
 | 	case IRQ_TYPE_EDGE_FALLING: | 
 | 		irq_set_handler_locked(d, handle_edge_irq); | 
 | 		int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE; | 
 | 		g->irq_edge |= BIT(d->hwirq); | 
 | 		break; | 
 | 	case IRQ_TYPE_LEVEL_HIGH: | 
 | 		irq_set_handler_locked(d, handle_level_irq); | 
 | 		int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH; | 
 | 		g->irq_edge &= ~BIT(d->hwirq); | 
 | 		break; | 
 | 	case IRQ_TYPE_LEVEL_LOW: | 
 | 		irq_set_handler_locked(d, handle_level_irq); | 
 | 		int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW; | 
 | 		g->irq_edge &= ~BIT(d->hwirq); | 
 | 		break; | 
 | 	default: | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	if (line >= 8) { | 
 | 		/* pins 8-15 */ | 
 | 		line -= 8; | 
 | 		int_reg = IXP4XX_REG_GPIT2; | 
 | 	} else { | 
 | 		/* pins 0-7 */ | 
 | 		int_reg = IXP4XX_REG_GPIT1; | 
 | 	} | 
 |  | 
 | 	raw_spin_lock_irqsave(&g->gc.bgpio_lock, flags); | 
 |  | 
 | 	/* Clear the style for the appropriate pin */ | 
 | 	val = __raw_readl(g->base + int_reg); | 
 | 	val &= ~(IXP4XX_GPIO_STYLE_MASK << (line * IXP4XX_GPIO_STYLE_SIZE)); | 
 | 	__raw_writel(val, g->base + int_reg); | 
 |  | 
 | 	__raw_writel(BIT(line), g->base + IXP4XX_REG_GPIS); | 
 |  | 
 | 	/* Set the new style */ | 
 | 	val = __raw_readl(g->base + int_reg); | 
 | 	val |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE)); | 
 | 	__raw_writel(val, g->base + int_reg); | 
 |  | 
 | 	/* Force-configure this line as an input */ | 
 | 	val = __raw_readl(g->base + IXP4XX_REG_GPOE); | 
 | 	val |= BIT(d->hwirq); | 
 | 	__raw_writel(val, g->base + IXP4XX_REG_GPOE); | 
 |  | 
 | 	raw_spin_unlock_irqrestore(&g->gc.bgpio_lock, flags); | 
 |  | 
 | 	/* This parent only accept level high (asserted) */ | 
 | 	return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH); | 
 | } | 
 |  | 
 | static const struct irq_chip ixp4xx_gpio_irqchip = { | 
 | 	.name = "IXP4GPIO", | 
 | 	.irq_ack = ixp4xx_gpio_irq_ack, | 
 | 	.irq_mask = ixp4xx_gpio_mask_irq, | 
 | 	.irq_unmask = ixp4xx_gpio_irq_unmask, | 
 | 	.irq_set_type = ixp4xx_gpio_irq_set_type, | 
 | 	.flags = IRQCHIP_IMMUTABLE, | 
 | 	GPIOCHIP_IRQ_RESOURCE_HELPERS, | 
 | }; | 
 |  | 
 | static int ixp4xx_gpio_child_to_parent_hwirq(struct gpio_chip *gc, | 
 | 					     unsigned int child, | 
 | 					     unsigned int child_type, | 
 | 					     unsigned int *parent, | 
 | 					     unsigned int *parent_type) | 
 | { | 
 | 	/* All these interrupts are level high in the CPU */ | 
 | 	*parent_type = IRQ_TYPE_LEVEL_HIGH; | 
 |  | 
 | 	/* GPIO lines 0..12 have dedicated IRQs */ | 
 | 	if (child == 0) { | 
 | 		*parent = 6; | 
 | 		return 0; | 
 | 	} | 
 | 	if (child == 1) { | 
 | 		*parent = 7; | 
 | 		return 0; | 
 | 	} | 
 | 	if (child >= 2 && child <= 12) { | 
 | 		*parent = child + 17; | 
 | 		return 0; | 
 | 	} | 
 | 	return -EINVAL; | 
 | } | 
 |  | 
 | static int ixp4xx_gpio_probe(struct platform_device *pdev) | 
 | { | 
 | 	unsigned long flags; | 
 | 	struct device *dev = &pdev->dev; | 
 | 	struct device_node *np = dev->of_node; | 
 | 	struct irq_domain *parent; | 
 | 	struct ixp4xx_gpio *g; | 
 | 	struct gpio_irq_chip *girq; | 
 | 	struct device_node *irq_parent; | 
 | 	int ret; | 
 |  | 
 | 	g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL); | 
 | 	if (!g) | 
 | 		return -ENOMEM; | 
 | 	g->dev = dev; | 
 |  | 
 | 	g->base = devm_platform_ioremap_resource(pdev, 0); | 
 | 	if (IS_ERR(g->base)) | 
 | 		return PTR_ERR(g->base); | 
 |  | 
 | 	irq_parent = of_irq_find_parent(np); | 
 | 	if (!irq_parent) { | 
 | 		dev_err(dev, "no IRQ parent node\n"); | 
 | 		return -ENODEV; | 
 | 	} | 
 | 	parent = irq_find_host(irq_parent); | 
 | 	if (!parent) { | 
 | 		dev_err(dev, "no IRQ parent domain\n"); | 
 | 		return -ENODEV; | 
 | 	} | 
 | 	g->fwnode = of_node_to_fwnode(np); | 
 |  | 
 | 	/* | 
 | 	 * Make sure GPIO 14 and 15 are NOT used as clocks but GPIO on | 
 | 	 * specific machines. | 
 | 	 */ | 
 | 	if (of_machine_is_compatible("dlink,dsm-g600-a") || | 
 | 	    of_machine_is_compatible("iom,nas-100d")) | 
 | 		__raw_writel(0x0, g->base + IXP4XX_REG_GPCLK); | 
 |  | 
 | 	/* | 
 | 	 * This is a very special big-endian ARM issue: when the IXP4xx is | 
 | 	 * run in big endian mode, all registers in the machine are switched | 
 | 	 * around to the CPU-native endianness. As you see mostly in the | 
 | 	 * driver we use __raw_readl()/__raw_writel() to access the registers | 
 | 	 * in the appropriate order. With the GPIO library we need to specify | 
 | 	 * byte order explicitly, so this flag needs to be set when compiling | 
 | 	 * for big endian. | 
 | 	 */ | 
 | #if defined(CONFIG_CPU_BIG_ENDIAN) | 
 | 	flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER; | 
 | #else | 
 | 	flags = 0; | 
 | #endif | 
 |  | 
 | 	/* Populate and register gpio chip */ | 
 | 	ret = bgpio_init(&g->gc, dev, 4, | 
 | 			 g->base + IXP4XX_REG_GPIN, | 
 | 			 g->base + IXP4XX_REG_GPOUT, | 
 | 			 NULL, | 
 | 			 NULL, | 
 | 			 g->base + IXP4XX_REG_GPOE, | 
 | 			 flags); | 
 | 	if (ret) { | 
 | 		dev_err(dev, "unable to init generic GPIO\n"); | 
 | 		return ret; | 
 | 	} | 
 | 	g->gc.ngpio = 16; | 
 | 	g->gc.label = "IXP4XX_GPIO_CHIP"; | 
 | 	/* | 
 | 	 * TODO: when we have migrated to device tree and all GPIOs | 
 | 	 * are fetched using phandles, set this to -1 to get rid of | 
 | 	 * the fixed gpiochip base. | 
 | 	 */ | 
 | 	g->gc.base = 0; | 
 | 	g->gc.parent = &pdev->dev; | 
 | 	g->gc.owner = THIS_MODULE; | 
 |  | 
 | 	girq = &g->gc.irq; | 
 | 	gpio_irq_chip_set_chip(girq, &ixp4xx_gpio_irqchip); | 
 | 	girq->fwnode = g->fwnode; | 
 | 	girq->parent_domain = parent; | 
 | 	girq->child_to_parent_hwirq = ixp4xx_gpio_child_to_parent_hwirq; | 
 | 	girq->handler = handle_bad_irq; | 
 | 	girq->default_type = IRQ_TYPE_NONE; | 
 |  | 
 | 	ret = devm_gpiochip_add_data(dev, &g->gc, g); | 
 | 	if (ret) { | 
 | 		dev_err(dev, "failed to add SoC gpiochip\n"); | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	platform_set_drvdata(pdev, g); | 
 | 	dev_info(dev, "IXP4 GPIO registered\n"); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static const struct of_device_id ixp4xx_gpio_of_match[] = { | 
 | 	{ | 
 | 		.compatible = "intel,ixp4xx-gpio", | 
 | 	}, | 
 | 	{}, | 
 | }; | 
 |  | 
 |  | 
 | static struct platform_driver ixp4xx_gpio_driver = { | 
 | 	.driver = { | 
 | 		.name		= "ixp4xx-gpio", | 
 | 		.of_match_table = ixp4xx_gpio_of_match, | 
 | 	}, | 
 | 	.probe = ixp4xx_gpio_probe, | 
 | }; | 
 | builtin_platform_driver(ixp4xx_gpio_driver); |