Like done in Linux, for easier code sharing. Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- arch/arm/Kconfig | 1 + drivers/gpio/Kconfig | 7 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-rockchip.c | 196 +++++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-rockchip.c | 178 -------------------------- 5 files changed, 205 insertions(+), 178 deletions(-) create mode 100644 drivers/gpio/gpio-rockchip.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5aef8fcd3b..37fe591000 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -260,6 +260,7 @@ config ARCH_ROCKCHIP select OFTREE select HAVE_PBL_MULTI_IMAGES select HAS_DEBUG_LL + imply GPIO_ROCKCHIP config ARCH_STM32MP bool "STMicroelectronics STM32MP" diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index dd2b56d256..e19f5a5aba 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -155,6 +155,13 @@ config GPIO_RASPBERRYPI_EXP Turn on GPIO support for the expander on Raspberry Pi 3 boards, using the firmware mailbox to communicate with VideoCore on BCM283x chips. +config GPIO_ROCKCHIP + bool "Rockchip GPIO support" + depends on ARCH_ROCKCHIP + help + Say yes here to include the driver for the GPIO controller found on + Rockchip SoCs. + config GPIO_STMPE depends on MFD_STMPE bool "STMPE GPIO Expander" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 90ab0a8b28..628e975285 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o +obj-$(CONFIG_GPIO_ROCKCHIP) += gpio-rockchip.o obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_DESIGNWARE) += gpio-dw.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c new file mode 100644 index 0000000000..b01a30c18a --- /dev/null +++ b/drivers/gpio/gpio-rockchip.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <common.h> +#include <errno.h> +#include <io.h> +#include <of.h> +#include <gpio.h> +#include <init.h> +#include <linux/clk.h> +#include <linux/basic_mmio_gpio.h> +#include <mach/rockchip/rockchip.h> + +struct rockchip_gpiochip { + struct device *dev; + void __iomem *reg_base; + struct clk *clk; + struct bgpio_chip bgpio_chip; +}; + +/* GPIO registers */ +enum { + RK_GPIO_SWPORT_DR = 0x00, + RK_GPIO_SWPORT_DDR = 0x04, + RK_GPIO_EXT_PORT = 0x50, +}; + +/* GPIO registers */ +enum { + RK_GPIOV2_DR_L = 0x00, + RK_GPIOV2_DR_H = 0x04, + RK_GPIOV2_DDR_L = 0x08, + RK_GPIOV2_DDR_H = 0x0c, + RK_GPIOV2_EXT_PORT = 0x70, +}; + +static struct rockchip_gpiochip *gc_to_rockchip_pinctrl(struct gpio_chip *gc) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return container_of(bgc, struct rockchip_gpiochip, bgpio_chip); +} + +static int rockchip_gpiov2_direction_input(struct gpio_chip *gc, unsigned int gpio) +{ + struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc); + u32 mask; + + mask = 1 << (16 + (gpio % 16)); + + if (gpio < 16) + writel(mask, rgc->reg_base + RK_GPIOV2_DDR_L); + else + writel(mask, rgc->reg_base + RK_GPIOV2_DDR_H); + + return 0; +} + +static int rockchip_gpiov2_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc); + u32 r; + + if (gpio < 16) + r = readl(rgc->reg_base + RK_GPIOV2_DDR_L); + else + r = readl(rgc->reg_base + RK_GPIOV2_DDR_H); + + return r & BIT(gpio % 16) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; +} + +static void rockchip_gpiov2_set_value(struct gpio_chip *gc, unsigned int gpio, + int val) +{ + struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc); + u32 mask, vval = 0; + + mask = 1 << (16 + (gpio % 16)); + if (val) + vval = 1 << (gpio % 16); + + if (gpio < 16) + writel(mask | vval, rgc->reg_base + RK_GPIOV2_DR_L); + else + writel(mask | vval, rgc->reg_base + RK_GPIOV2_DR_H); +} + +static int rockchip_gpiov2_direction_output(struct gpio_chip *gc, + unsigned int gpio, int val) +{ + struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc); + u32 mask, out, vval = 0; + + mask = 1 << (16 + (gpio % 16)); + out = 1 << (gpio % 16); + if (val) + vval = 1 << (gpio % 16); + + if (gpio < 16) { + writel(mask | vval, rgc->reg_base + RK_GPIOV2_DR_L); + writel(mask | out, rgc->reg_base + RK_GPIOV2_DDR_L); + } else { + writel(mask | vval, rgc->reg_base + RK_GPIOV2_DR_H); + writel(mask | out, rgc->reg_base + RK_GPIOV2_DDR_H); + } + + return 0; +} + +static int rockchip_gpiov2_get_value(struct gpio_chip *gc, unsigned int gpio) +{ + struct rockchip_gpiochip *rgc = gc_to_rockchip_pinctrl(gc); + u32 mask, r; + + mask = 1 << (gpio % 32); + r = readl(rgc->reg_base + RK_GPIOV2_EXT_PORT); + + return r & mask ? 1 : 0; +} + +static struct gpio_ops rockchip_gpio_ops = { + .direction_input = rockchip_gpiov2_direction_input, + .direction_output = rockchip_gpiov2_direction_output, + .get = rockchip_gpiov2_get_value, + .set = rockchip_gpiov2_set_value, + .get_direction = rockchip_gpiov2_get_direction, +}; + +static int rockchip_gpio_probe(struct device *dev) +{ + struct rockchip_gpiochip *rgc; + struct gpio_chip *gpio; + struct resource *res; + void __iomem *reg_base; + int ret; + + rgc = xzalloc(sizeof(*rgc)); + gpio = &rgc->bgpio_chip.gc; + + res = dev_request_mem_resource(dev, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + + rgc->reg_base = IOMEM(res->start); + + rgc->clk = clk_get(dev, NULL); + + if (IS_ERR(rgc->clk)) + return PTR_ERR(rgc->clk); + + ret = clk_enable(rgc->clk); + if (ret) + return ret; + + reg_base = rgc->reg_base; + + if (rockchip_soc() == 3568) { + gpio->ngpio = 32; + gpio->dev = dev; + gpio->ops = &rockchip_gpio_ops; + gpio->base = of_alias_get_id(dev->of_node, "gpio"); + if (gpio->base < 0) + return -EINVAL; + gpio->base *= 32; + } else { + ret = bgpio_init(&rgc->bgpio_chip, dev, 4, + reg_base + RK_GPIO_EXT_PORT, + reg_base + RK_GPIO_SWPORT_DR, NULL, + reg_base + RK_GPIO_SWPORT_DDR, NULL, 0); + if (ret) + return ret; + } + + ret = gpiochip_add(&rgc->bgpio_chip.gc); + if (ret) { + dev_err(dev, "failed to register gpio_chip:: %d\n", ret); + return ret; + } + + return 0; +} + +static struct of_device_id rockchip_gpio_dt_match[] = { + { + .compatible = "rockchip,gpio-bank", + }, { + /* sentinel */ + } +}; + +static struct driver rockchip_gpio_driver = { + .name = "rockchip-gpio", + .probe = rockchip_gpio_probe, + .of_compatible = DRV_OF_COMPAT(rockchip_gpio_dt_match), +}; + +core_platform_driver(rockchip_gpio_driver); diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 4021f7ff23..6547423261 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -90,167 +90,6 @@ enum { RK_BIAS_BUS_HOLD, }; -/* GPIO registers */ -enum { - RK_GPIO_SWPORT_DR = 0x00, - RK_GPIO_SWPORT_DDR = 0x04, - RK_GPIO_EXT_PORT = 0x50, -}; - -/* GPIO registers */ -enum { - RK_GPIOV2_DR_L = 0x00, - RK_GPIOV2_DR_H = 0x04, - RK_GPIOV2_DDR_L = 0x08, - RK_GPIOV2_DDR_H = 0x0c, - RK_GPIOV2_EXT_PORT = 0x70, -}; - -static struct rockchip_pin_bank *gc_to_rockchip_pinctrl(struct gpio_chip *gc) -{ - struct bgpio_chip *bgc = to_bgpio_chip(gc); - - return container_of(bgc, struct rockchip_pin_bank, bgpio_chip); -} - -static int rockchip_gpiov2_direction_input(struct gpio_chip *gc, unsigned int gpio) -{ - struct rockchip_pin_bank *bank = gc_to_rockchip_pinctrl(gc); - u32 mask; - - mask = 1 << (16 + (gpio % 16)); - - if (gpio < 16) - writel(mask, bank->reg_base + RK_GPIOV2_DDR_L); - else - writel(mask, bank->reg_base + RK_GPIOV2_DDR_H); - - return 0; -} - -static int rockchip_gpiov2_get_direction(struct gpio_chip *gc, unsigned int gpio) -{ - struct rockchip_pin_bank *bank = gc_to_rockchip_pinctrl(gc); - u32 r; - - if (gpio < 16) - r = readl(bank->reg_base + RK_GPIOV2_DDR_L); - else - r = readl(bank->reg_base + RK_GPIOV2_DDR_H); - - return r & BIT(gpio % 16) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; -} - -static void rockchip_gpiov2_set_value(struct gpio_chip *gc, unsigned int gpio, - int val) -{ - struct rockchip_pin_bank *bank = gc_to_rockchip_pinctrl(gc); - u32 mask, vval = 0; - - mask = 1 << (16 + (gpio % 16)); - if (val) - vval = 1 << (gpio % 16); - - if (gpio < 16) - writel(mask | vval, bank->reg_base + RK_GPIOV2_DR_L); - else - writel(mask | vval, bank->reg_base + RK_GPIOV2_DR_H); -} - -static int rockchip_gpiov2_direction_output(struct gpio_chip *gc, - unsigned int gpio, int val) -{ - struct rockchip_pin_bank *bank = gc_to_rockchip_pinctrl(gc); - u32 mask, out, vval = 0; - - mask = 1 << (16 + (gpio % 16)); - out = 1 << (gpio % 16); - if (val) - vval = 1 << (gpio % 16); - - if (gpio < 16) { - writel(mask | vval, bank->reg_base + RK_GPIOV2_DR_L); - writel(mask | out, bank->reg_base + RK_GPIOV2_DDR_L); - } else { - writel(mask | vval, bank->reg_base + RK_GPIOV2_DR_H); - writel(mask | out, bank->reg_base + RK_GPIOV2_DDR_H); - } - - return 0; -} - -static int rockchip_gpiov2_get_value(struct gpio_chip *gc, unsigned int gpio) -{ - struct rockchip_pin_bank *bank = gc_to_rockchip_pinctrl(gc); - u32 mask, r; - - mask = 1 << (gpio % 32); - r = readl(bank->reg_base + RK_GPIOV2_EXT_PORT); - - return r & mask ? 1 : 0; -} - -static struct gpio_ops rockchip_gpio_ops = { - .direction_input = rockchip_gpiov2_direction_input, - .direction_output = rockchip_gpiov2_direction_output, - .get = rockchip_gpiov2_get_value, - .set = rockchip_gpiov2_set_value, - .get_direction = rockchip_gpiov2_get_direction, -}; - -static int rockchip_gpio_probe(struct device *dev) -{ - struct rockchip_pinctrl *info = dev->parent->priv; - struct rockchip_pin_ctrl *ctrl = info->ctrl; - struct rockchip_pin_bank *bank; - struct gpio_chip *gpio; - void __iomem *reg_base; - int ret, bankno; - - bankno = of_alias_get_id(dev->of_node, "gpio"); - if (bankno >= ctrl->nr_banks) - bankno = -EINVAL; - if (bankno < 0) - return bankno; - - bank = &ctrl->pin_banks[bankno]; - gpio = &bank->bgpio_chip.gc; - - if (!bank->valid) - dev_warn(dev, "bank %s is not valid\n", bank->name); - - reg_base = bank->reg_base; - - if (ctrl->type == RK3568) { - gpio->ngpio = 32; - gpio->dev = dev; - gpio->ops = &rockchip_gpio_ops; - gpio->base = bankno; - if (gpio->base < 0) - return -EINVAL; - gpio->base *= 32; - } else { - ret = bgpio_init(&bank->bgpio_chip, dev, 4, - reg_base + RK_GPIO_EXT_PORT, - reg_base + RK_GPIO_SWPORT_DR, NULL, - reg_base + RK_GPIO_SWPORT_DDR, NULL, 0); - if (ret) - return ret; - } - - bank->bgpio_chip.gc.dev = dev; - - bank->bgpio_chip.gc.ngpio = bank->nr_pins; - ret = gpiochip_add(&bank->bgpio_chip.gc); - if (ret) { - dev_err(dev, "failed to register gpio_chip %s, error code: %d\n", - bank->name, ret); - return ret; - } - - return 0; -} - static struct rockchip_pinctrl *to_rockchip_pinctrl(struct pinctrl_device *pdev) { return container_of(pdev, struct rockchip_pinctrl, pctl_dev); @@ -1145,20 +984,3 @@ static struct driver rockchip_pinctrl_driver = { }; core_platform_driver(rockchip_pinctrl_driver); - -static struct of_device_id rockchip_gpio_dt_match[] = { - { - .compatible = "rockchip,gpio-bank", - .data = &rk2928_pin_ctrl, - }, { - /* sentinel */ - } -}; - -static struct driver rockchip_gpio_driver = { - .name = "rockchip-gpio", - .probe = rockchip_gpio_probe, - .of_compatible = DRV_OF_COMPAT(rockchip_gpio_dt_match), -}; - -core_platform_driver(rockchip_gpio_driver); -- 2.39.2