Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: visconti: Add Toshiba Visconti GPIO support

Add the GPIO driver for Toshiba Visconti ARM SoCs.

Signed-off-by: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
Reviewed-by: Punit Agrawal <punit1.agrawal@toshiba.co.jp>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

authored by

Nobuhiro Iwamatsu and committed by
Bartosz Golaszewski
2ad74f40 858093f7

+252
+10
drivers/gpio/Kconfig
··· 648 648 help 649 649 Say yes here to support Vybrid vf610 GPIOs. 650 650 651 + config GPIO_VISCONTI 652 + tristate "Toshiba Visconti GPIO support" 653 + depends on ARCH_VISCONTI || COMPILE_TEST 654 + depends on OF_GPIO 655 + select GPIOLIB_IRQCHIP 656 + select GPIO_GENERIC 657 + select IRQ_DOMAIN_HIERARCHY 658 + help 659 + Say yes here to support GPIO on Tohisba Visconti. 660 + 651 661 config GPIO_VR41XX 652 662 tristate "NEC VR4100 series General-purpose I/O Uint support" 653 663 depends on CPU_VR41XX
+1
drivers/gpio/Makefile
··· 164 164 obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o 165 165 obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o 166 166 obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o 167 + obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o 167 168 obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o 168 169 obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o 169 170 obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o
+218
drivers/gpio/gpio-visconti.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Toshiba Visconti GPIO Support 4 + * 5 + * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation 6 + * (C) Copyright 2020 TOSHIBA CORPORATION 7 + * 8 + * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp> 9 + */ 10 + 11 + #include <linux/gpio/driver.h> 12 + #include <linux/init.h> 13 + #include <linux/interrupt.h> 14 + #include <linux/module.h> 15 + #include <linux/io.h> 16 + #include <linux/of_irq.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/bitops.h> 19 + 20 + /* register offset */ 21 + #define GPIO_DIR 0x00 22 + #define GPIO_IDATA 0x08 23 + #define GPIO_ODATA 0x10 24 + #define GPIO_OSET 0x18 25 + #define GPIO_OCLR 0x20 26 + #define GPIO_INTMODE 0x30 27 + 28 + #define BASE_HW_IRQ 24 29 + 30 + struct visconti_gpio { 31 + void __iomem *base; 32 + spinlock_t lock; /* protect gpio register */ 33 + struct gpio_chip gpio_chip; 34 + struct irq_chip irq_chip; 35 + }; 36 + 37 + static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type) 38 + { 39 + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 40 + struct visconti_gpio *priv = gpiochip_get_data(gc); 41 + u32 offset = irqd_to_hwirq(d); 42 + u32 bit = BIT(offset); 43 + u32 intc_type = IRQ_TYPE_EDGE_RISING; 44 + u32 intmode, odata; 45 + int ret = 0; 46 + unsigned long flags; 47 + 48 + spin_lock_irqsave(&priv->lock, flags); 49 + 50 + odata = readl(priv->base + GPIO_ODATA); 51 + intmode = readl(priv->base + GPIO_INTMODE); 52 + 53 + switch (type) { 54 + case IRQ_TYPE_EDGE_RISING: 55 + odata &= ~bit; 56 + intmode &= ~bit; 57 + break; 58 + case IRQ_TYPE_EDGE_FALLING: 59 + odata |= bit; 60 + intmode &= ~bit; 61 + break; 62 + case IRQ_TYPE_EDGE_BOTH: 63 + intmode |= bit; 64 + break; 65 + case IRQ_TYPE_LEVEL_HIGH: 66 + intc_type = IRQ_TYPE_LEVEL_HIGH; 67 + odata &= ~bit; 68 + intmode &= ~bit; 69 + break; 70 + case IRQ_TYPE_LEVEL_LOW: 71 + intc_type = IRQ_TYPE_LEVEL_HIGH; 72 + odata |= bit; 73 + intmode &= ~bit; 74 + break; 75 + default: 76 + ret = -EINVAL; 77 + goto err; 78 + } 79 + 80 + writel(odata, priv->base + GPIO_ODATA); 81 + writel(intmode, priv->base + GPIO_INTMODE); 82 + irq_set_irq_type(offset, intc_type); 83 + 84 + ret = irq_chip_set_type_parent(d, type); 85 + err: 86 + spin_unlock_irqrestore(&priv->lock, flags); 87 + return ret; 88 + } 89 + 90 + static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc, 91 + unsigned int child, 92 + unsigned int child_type, 93 + unsigned int *parent, 94 + unsigned int *parent_type) 95 + { 96 + /* Interrupts 0..15 mapped to interrupts 24..39 on the GIC */ 97 + if (child < 16) { 98 + /* All these interrupts are level high in the CPU */ 99 + *parent_type = IRQ_TYPE_LEVEL_HIGH; 100 + *parent = child + BASE_HW_IRQ; 101 + return 0; 102 + } 103 + return -EINVAL; 104 + } 105 + 106 + static void *visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip, 107 + unsigned int parent_hwirq, 108 + unsigned int parent_type) 109 + { 110 + struct irq_fwspec *fwspec; 111 + 112 + fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL); 113 + if (!fwspec) 114 + return NULL; 115 + 116 + fwspec->fwnode = chip->irq.parent_domain->fwnode; 117 + fwspec->param_count = 3; 118 + fwspec->param[0] = 0; 119 + fwspec->param[1] = parent_hwirq; 120 + fwspec->param[2] = parent_type; 121 + 122 + return fwspec; 123 + } 124 + 125 + static int visconti_gpio_probe(struct platform_device *pdev) 126 + { 127 + struct device *dev = &pdev->dev; 128 + struct visconti_gpio *priv; 129 + struct irq_chip *irq_chip; 130 + struct gpio_irq_chip *girq; 131 + struct irq_domain *parent; 132 + struct device_node *irq_parent; 133 + struct fwnode_handle *fwnode; 134 + int ret; 135 + 136 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 137 + if (!priv) 138 + return -ENOMEM; 139 + 140 + spin_lock_init(&priv->lock); 141 + 142 + priv->base = devm_platform_ioremap_resource(pdev, 0); 143 + if (IS_ERR(priv->base)) 144 + return PTR_ERR(priv->base); 145 + 146 + irq_parent = of_irq_find_parent(dev->of_node); 147 + if (!irq_parent) { 148 + dev_err(dev, "No IRQ parent node\n"); 149 + return -ENODEV; 150 + } 151 + 152 + parent = irq_find_host(irq_parent); 153 + if (!parent) { 154 + dev_err(dev, "No IRQ parent domain\n"); 155 + return -ENODEV; 156 + } 157 + 158 + fwnode = of_node_to_fwnode(irq_parent); 159 + of_node_put(irq_parent); 160 + 161 + ret = bgpio_init(&priv->gpio_chip, dev, 4, 162 + priv->base + GPIO_IDATA, 163 + priv->base + GPIO_OSET, 164 + priv->base + GPIO_OCLR, 165 + priv->base + GPIO_DIR, 166 + NULL, 167 + 0); 168 + if (ret) { 169 + dev_err(dev, "unable to init generic GPIO\n"); 170 + return ret; 171 + } 172 + 173 + irq_chip = &priv->irq_chip; 174 + irq_chip->name = dev_name(dev); 175 + irq_chip->irq_mask = irq_chip_mask_parent; 176 + irq_chip->irq_unmask = irq_chip_unmask_parent; 177 + irq_chip->irq_eoi = irq_chip_eoi_parent; 178 + irq_chip->irq_set_type = visconti_gpio_irq_set_type; 179 + irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; 180 + 181 + girq = &priv->gpio_chip.irq; 182 + girq->chip = irq_chip; 183 + girq->fwnode = fwnode; 184 + girq->parent_domain = parent; 185 + girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq; 186 + girq->populate_parent_alloc_arg = visconti_gpio_populate_parent_fwspec; 187 + girq->default_type = IRQ_TYPE_NONE; 188 + girq->handler = handle_level_irq; 189 + 190 + ret = devm_gpiochip_add_data(dev, &priv->gpio_chip, priv); 191 + if (ret) { 192 + dev_err(dev, "failed to add GPIO chip\n"); 193 + return ret; 194 + } 195 + 196 + platform_set_drvdata(pdev, priv); 197 + 198 + return ret; 199 + } 200 + 201 + static const struct of_device_id visconti_gpio_of_match[] = { 202 + { .compatible = "toshiba,gpio-tmpv7708", }, 203 + { /* end of table */ } 204 + }; 205 + MODULE_DEVICE_TABLE(of, visconti_gpio_of_match); 206 + 207 + static struct platform_driver visconti_gpio_driver = { 208 + .probe = visconti_gpio_probe, 209 + .driver = { 210 + .name = "visconti_gpio", 211 + .of_match_table = of_match_ptr(visconti_gpio_of_match), 212 + } 213 + }; 214 + module_platform_driver(visconti_gpio_driver); 215 + 216 + MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>"); 217 + MODULE_DESCRIPTION("Toshiba Visconti GPIO Driver"); 218 + MODULE_LICENSE("GPL v2");
+23
drivers/pinctrl/visconti/pinctrl-common.c
··· 245 245 return 0; 246 246 } 247 247 248 + static int visconti_gpio_request_enable(struct pinctrl_dev *pctldev, 249 + struct pinctrl_gpio_range *range, 250 + unsigned int pin) 251 + { 252 + struct visconti_pinctrl *priv = pinctrl_dev_get_drvdata(pctldev); 253 + const struct visconti_mux *gpio_mux = &priv->devdata->gpio_mux[pin]; 254 + unsigned long flags; 255 + unsigned int val; 256 + 257 + dev_dbg(priv->dev, "%s: pin = %d\n", __func__, pin); 258 + 259 + /* update mux */ 260 + spin_lock_irqsave(&priv->lock, flags); 261 + val = readl(priv->base + gpio_mux->offset); 262 + val &= ~gpio_mux->mask; 263 + val |= gpio_mux->val; 264 + writel(val, priv->base + gpio_mux->offset); 265 + spin_unlock_irqrestore(&priv->lock, flags); 266 + 267 + return 0; 268 + } 269 + 248 270 static const struct pinmux_ops visconti_pinmux_ops = { 249 271 .get_functions_count = visconti_get_functions_count, 250 272 .get_function_name = visconti_get_function_name, 251 273 .get_function_groups = visconti_get_function_groups, 252 274 .set_mux = visconti_set_mux, 275 + .gpio_request_enable = visconti_gpio_request_enable, 253 276 .strict = true, 254 277 }; 255 278