From: Stefan Bosch Date: Fri, 10 Jul 2020 17:07:27 +0000 (+0200) Subject: gpio: add nexell driver X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=b8f748d6f233955cc116ee9ef7cc43dbc5326d81;p=u-boot.git gpio: add nexell driver Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01: - livetree API (dev_read_...) is used instead of fdt one (fdt...). Signed-off-by: Stefan Bosch --- diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 0e8ad9530d..c1928442be 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -457,4 +457,13 @@ config MT7621_GPIO help Say yes here to support MediaTek MT7621 compatible GPIOs. +config NX_GPIO + bool "Nexell GPIO driver" + depends on DM_GPIO + help + Support GPIO access on Nexell SoCs. The GPIOs are arranged into + a number of banks (different for each SoC type) each with 32 GPIOs. + The GPIOs for a device are defined in the device tree with one node + for each bank. + endmenu diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 7638259007..334c5f27fe 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -64,4 +64,5 @@ obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o +obj-$(CONFIG_NX_GPIO) += nx_gpio.o obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o diff --git a/drivers/gpio/nx_gpio.c b/drivers/gpio/nx_gpio.c new file mode 100644 index 0000000000..5ec73c4359 --- /dev/null +++ b/drivers/gpio/nx_gpio.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Nexell + * DeokJin, Lee + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct nx_gpio_regs { + u32 data; /* Data register */ + u32 outputenb; /* Output Enable register */ + u32 detmode[2]; /* Detect Mode Register */ + u32 intenb; /* Interrupt Enable Register */ + u32 det; /* Event Detect Register */ + u32 pad; /* Pad Status Register */ +}; + +struct nx_alive_gpio_regs { + u32 pwrgate; /* Power Gating Register */ + u32 reserved0[28]; /* Reserved0 */ + u32 outputenb_reset;/* Alive GPIO Output Enable Reset Register */ + u32 outputenb; /* Alive GPIO Output Enable Register */ + u32 outputenb_read; /* Alive GPIO Output Read Register */ + u32 reserved1[3]; /* Reserved1 */ + u32 pad_reset; /* Alive GPIO Output Reset Register */ + u32 data; /* Alive GPIO Output Register */ + u32 pad_read; /* Alive GPIO Pad Read Register */ + u32 reserved2[33]; /* Reserved2 */ + u32 pad; /* Alive GPIO Input Value Register */ +}; + +struct nx_gpio_platdata { + void *regs; + int gpio_count; + const char *bank_name; +}; + +static int nx_alive_gpio_is_check(struct udevice *dev) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + const char *bank_name = plat->bank_name; + + if (!strcmp(bank_name, "gpio_alv")) + return 1; + + return 0; +} + +static int nx_alive_gpio_direction_input(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + + setbits_le32(®s->outputenb_reset, 1 << pin); + + return 0; +} + +static int nx_alive_gpio_direction_output(struct udevice *dev, unsigned int pin, + int val) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + + if (val) + setbits_le32(®s->data, 1 << pin); + else + setbits_le32(®s->pad_reset, 1 << pin); + + setbits_le32(®s->outputenb, 1 << pin); + + return 0; +} + +static int nx_alive_gpio_get_value(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + unsigned int mask = 1UL << pin; + unsigned int value; + + value = (readl(®s->pad_read) & mask) >> pin; + + return value; +} + +static int nx_alive_gpio_set_value(struct udevice *dev, unsigned int pin, + int val) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + + if (val) + setbits_le32(®s->data, 1 << pin); + else + clrbits_le32(®s->pad_reset, 1 << pin); + + return 0; +} + +static int nx_alive_gpio_get_function(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + unsigned int mask = (1UL << pin); + unsigned int output; + + output = readl(®s->outputenb_read) & mask; + + if (output) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int nx_gpio_direction_input(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_direction_input(dev, pin); + + clrbits_le32(®s->outputenb, 1 << pin); + + return 0; +} + +static int nx_gpio_direction_output(struct udevice *dev, unsigned int pin, + int val) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_direction_output(dev, pin, val); + + if (val) + setbits_le32(®s->data, 1 << pin); + else + clrbits_le32(®s->data, 1 << pin); + + setbits_le32(®s->outputenb, 1 << pin); + + return 0; +} + +static int nx_gpio_get_value(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + unsigned int mask = 1UL << pin; + unsigned int value; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_get_value(dev, pin); + + value = (readl(®s->pad) & mask) >> pin; + + return value; +} + +static int nx_gpio_set_value(struct udevice *dev, unsigned int pin, int val) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_set_value(dev, pin, val); + + if (val) + setbits_le32(®s->data, 1 << pin); + else + clrbits_le32(®s->data, 1 << pin); + + return 0; +} + +static int nx_gpio_get_function(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + unsigned int mask = (1UL << pin); + unsigned int output; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_get_function(dev, pin); + + output = readl(®s->outputenb) & mask; + + if (output) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int nx_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + + uc_priv->gpio_count = plat->gpio_count; + uc_priv->bank_name = plat->bank_name; + + return 0; +} + +static int nx_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + + plat->regs = map_physmem(devfdt_get_addr(dev), + sizeof(struct nx_gpio_regs), + MAP_NOCACHE); + plat->gpio_count = dev_read_s32_default(dev, "nexell,gpio-bank-width", + 32); + plat->bank_name = dev_read_string(dev, "gpio-bank-name"); + + return 0; +} + +static const struct dm_gpio_ops nx_gpio_ops = { + .direction_input = nx_gpio_direction_input, + .direction_output = nx_gpio_direction_output, + .get_value = nx_gpio_get_value, + .set_value = nx_gpio_set_value, + .get_function = nx_gpio_get_function, +}; + +static const struct udevice_id nx_gpio_ids[] = { + { .compatible = "nexell,nexell-gpio" }, + { } +}; + +U_BOOT_DRIVER(nx_gpio) = { + .name = "nx_gpio", + .id = UCLASS_GPIO, + .of_match = nx_gpio_ids, + .ops = &nx_gpio_ops, + .ofdata_to_platdata = nx_gpio_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct nx_gpio_platdata), + .probe = nx_gpio_probe, +};