From 1b2cc689fc2db0db56c617e789906a684b22097a Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 9 Nov 2016 08:14:16 -0800 Subject: gpio: Add GPIO driver for Vybrid Add GPIO driver for VF610 Family of SoCs (based on analogous driver from Linux kernel) Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- drivers/gpio/Kconfig | 3 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-vf610.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 drivers/gpio/gpio-vf610.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ab919c95f5..fe62778b3c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -49,6 +49,9 @@ config GPIO_GENERIC_PLATFORM config GPIO_IMX def_bool ARCH_IMX +config GPIO_VF610 + def_bool ARCH_VF610 + config GPIO_MXS def_bool ARCH_MXS diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 8767eed1e8..248100f0fe 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_DESIGNWARE) += gpio-dw.o +obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c new file mode 100644 index 0000000000..7c8d1e4c98 --- /dev/null +++ b/drivers/gpio/gpio-vf610.c @@ -0,0 +1,166 @@ +/* + * vf610 GPIO support through PORT and GPIO module + * + * Copyright (c) 2014 Toradex AG. + * + * Author: Stefan Agner . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define VF610_GPIO_PER_PORT 32 +#define PINCTRL_BASE 2 +#define COUNT 3 + +struct vf610_gpio_port { + struct gpio_chip chip; + void __iomem *gpio_base; + unsigned int pinctrl_base; +}; + +#define GPIO_PDOR 0x00 +#define GPIO_PSOR 0x04 +#define GPIO_PCOR 0x08 +#define GPIO_PTOR 0x0c +#define GPIO_PDIR 0x10 + +static const struct of_device_id vf610_gpio_dt_ids[] = { + { .compatible = "fsl,vf610-gpio" }, + { /* sentinel */ } +}; + + +static int vf610_gpio_get_value(struct gpio_chip *chip, unsigned int gpio) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + + return !!(readl(port->gpio_base + GPIO_PDIR) & BIT(gpio)); +} + +static void vf610_gpio_set_value(struct gpio_chip *chip, + unsigned int gpio, int val) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + unsigned long mask = BIT(gpio); + + writel(mask, port->gpio_base + ((val) ? GPIO_PSOR : GPIO_PCOR)); +} + +static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + + return pinctrl_gpio_direction_input(port->pinctrl_base + gpio); +} + +static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, + int value) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + + vf610_gpio_set_value(chip, gpio, value); + + return pinctrl_gpio_direction_output(port->pinctrl_base + gpio); +} + +static int vf610_gpio_get_direction(struct gpio_chip *chip, unsigned gpio) +{ + struct vf610_gpio_port *port = + container_of(chip, struct vf610_gpio_port, chip); + + return pinctrl_gpio_get_direction(port->pinctrl_base + gpio); +} + +static struct gpio_ops vf610_gpio_ops = { + .direction_input = vf610_gpio_direction_input, + .direction_output = vf610_gpio_direction_output, + .get = vf610_gpio_get_value, + .set = vf610_gpio_set_value, + .get_direction = vf610_gpio_get_direction, +}; + +static int vf610_gpio_probe(struct device_d *dev) +{ + int ret, size; + struct resource *iores; + struct vf610_gpio_port *port; + const __be32 *gpio_ranges; + + port = xzalloc(sizeof(*port)); + if (!port) + return -ENOMEM; + + gpio_ranges = of_get_property(dev->device_node, "gpio-ranges", &size); + if (!gpio_ranges) { + dev_err(dev, "Couldn't read 'gpio-ranges' propery of %s\n", + dev->device_node->full_name); + ret = -EINVAL; + goto free_port; + } + + port->pinctrl_base = be32_to_cpu(gpio_ranges[PINCTRL_BASE]); + port->chip.ngpio = be32_to_cpu(gpio_ranges[COUNT]); + + iores = dev_request_mem_resource(dev, 1); + if (IS_ERR(iores)) { + ret = PTR_ERR(iores); + dev_dbg(dev, "Failed to request memory resource\n"); + goto free_port; + } + + port->gpio_base = IOMEM(iores->start); + + port->chip.ops = &vf610_gpio_ops; + if (dev->id < 0) { + port->chip.base = of_alias_get_id(dev->device_node, "gpio"); + if (port->chip.base < 0) { + ret = port->chip.base; + dev_dbg(dev, "Failed to get GPIO alias\n"); + goto free_port; + } + } else { + port->chip.base = dev->id; + } + + + port->chip.base *= VF610_GPIO_PER_PORT; + port->chip.dev = dev; + gpiochip_add(&port->chip); + + return 0; + +free_port: + free(port); + return ret; +} + +static struct driver_d vf610_gpio_driver = { + .name = "gpio-vf610", + .probe = vf610_gpio_probe, + .of_compatible = DRV_OF_COMPAT(vf610_gpio_dt_ids), +}; + +static int __init gpio_vf610_init(void) +{ + return platform_driver_register(&vf610_gpio_driver); +} +core_initcall(gpio_vf610_init); -- cgit v1.2.3