diff options
author | Stefan Bosch <stefan_b@posteo.net> | 2020-07-10 20:07:30 +0300 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-07-29 15:43:40 +0300 |
commit | 8d393b2c2278c846d26d59b37a2b46d3bcdb1663 (patch) | |
tree | f77274622d36aab84d67a7a589a3f0da9ec98233 /drivers/pinctrl/nexell | |
parent | 8408318943ebff4ec0533bf3318dd591a06926f5 (diff) | |
download | u-boot-8d393b2c2278c846d26d59b37a2b46d3bcdb1663.tar.xz |
pinctrl: 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...).
- doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt added.
Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
Diffstat (limited to 'drivers/pinctrl/nexell')
-rw-r--r-- | drivers/pinctrl/nexell/Kconfig | 18 | ||||
-rw-r--r-- | drivers/pinctrl/nexell/Makefile | 7 | ||||
-rw-r--r-- | drivers/pinctrl/nexell/pinctrl-nexell.c | 66 | ||||
-rw-r--r-- | drivers/pinctrl/nexell/pinctrl-nexell.h | 68 | ||||
-rw-r--r-- | drivers/pinctrl/nexell/pinctrl-s5pxx18.c | 220 | ||||
-rw-r--r-- | drivers/pinctrl/nexell/pinctrl-s5pxx18.h | 53 |
6 files changed, 432 insertions, 0 deletions
diff --git a/drivers/pinctrl/nexell/Kconfig b/drivers/pinctrl/nexell/Kconfig new file mode 100644 index 0000000000..8f1e472239 --- /dev/null +++ b/drivers/pinctrl/nexell/Kconfig @@ -0,0 +1,18 @@ +if ARCH_NEXELL + +config PINCTRL_NEXELL + bool "Nexell pinctrl driver" + help + Support of pin multiplexing and pin configuration for Nexell + SoCs. + +config PINCTRL_NEXELL_S5PXX18 + bool "Nexell s5pxx18 SoC pinctrl driver" + default y if ARCH_S5P4418 || ARCH_S5P6818 + depends on ARCH_NEXELL && PINCTRL_FULL + select PINCTRL_NEXELL + help + Support of pin multiplexing and pin configuration for S5P4418 + and S5P6818 SoC. + +endif diff --git a/drivers/pinctrl/nexell/Makefile b/drivers/pinctrl/nexell/Makefile new file mode 100644 index 0000000000..74df414d55 --- /dev/null +++ b/drivers/pinctrl/nexell/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 Nexell +# Bongyu, KOO <freestyle@nexell.co.kr> + +obj-$(CONFIG_PINCTRL_NEXELL) += pinctrl-nexell.o +obj-$(CONFIG_PINCTRL_NEXELL_S5PXX18) += pinctrl-s5pxx18.o diff --git a/drivers/pinctrl/nexell/pinctrl-nexell.c b/drivers/pinctrl/nexell/pinctrl-nexell.c new file mode 100644 index 0000000000..4518c05d46 --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-nexell.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO <freestyle@nexell.co.kr> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <asm/io.h> +#include "pinctrl-nexell.h" +#include "pinctrl-s5pxx18.h" + +DECLARE_GLOBAL_DATA_PTR; + +/* given a pin-name, return the address of pin config registers */ +unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, + u32 *pin) +{ + struct nexell_pinctrl_priv *priv = dev_get_priv(dev); + const struct nexell_pin_ctrl *pin_ctrl = priv->pin_ctrl; + const struct nexell_pin_bank_data *bank_data = pin_ctrl->pin_banks; + u32 nr_banks = pin_ctrl->nr_banks, idx = 0; + char bank[10]; + + /* + * The format of the pin name is <bank name>-<pin_number>. + * Example: gpioa-4 (gpioa is the bank name and 4 is the pin number) + */ + while (pin_name[idx] != '-') { + bank[idx] = pin_name[idx]; + idx++; + } + bank[idx] = '\0'; + *pin = (u32)simple_strtoul(&pin_name[++idx], NULL, 10); + + /* lookup the pin bank data using the pin bank name */ + for (idx = 0; idx < nr_banks; idx++) + if (!strcmp(bank, bank_data[idx].name)) + break; + + return priv->base + bank_data[idx].offset; +} + +int nexell_pinctrl_probe(struct udevice *dev) +{ + struct nexell_pinctrl_priv *priv; + fdt_addr_t base; + + priv = dev_get_priv(dev); + if (!priv) + return -EINVAL; + + base = devfdt_get_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = base; + + priv->pin_ctrl = (struct nexell_pin_ctrl *)dev_get_driver_data(dev); + + s5pxx18_pinctrl_init(dev); + + return 0; +} diff --git a/drivers/pinctrl/nexell/pinctrl-nexell.h b/drivers/pinctrl/nexell/pinctrl-nexell.h new file mode 100644 index 0000000000..b21eefcabe --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-nexell.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO <freestyle@nexell.co.kr> + * + */ + +#ifndef __PINCTRL_NEXELL_H_ +#define __PINCTRL_NEXELL_H_ + +/** + * struct nexell_pin_bank_data: represent a controller pin-bank data. + * @offset: starting offset of the pin-bank registers. + * @nr_pins: number of pins included in this bank. + * @name: name to be prefixed for each pin in this pin bank. + */ +struct nexell_pin_bank_data { + u32 offset; + u8 nr_pins; + const char *name; + u8 type; +}; + +#define NEXELL_PIN_BANK(pins, reg, id) \ + { \ + .offset = reg, \ + .nr_pins = pins, \ + .name = id \ + } + +/** + * struct nexell_pin_ctrl: represent a pin controller. + * @pin_banks: list of pin banks included in this controller. + * @nr_banks: number of pin banks. + */ +struct nexell_pin_ctrl { + const struct nexell_pin_bank_data *pin_banks; + u32 nr_banks; +}; + +/** + * struct nexell_pinctrl_priv: nexell pin controller driver private data + * @pin_ctrl: pin controller bank information. + * @base: base address of the pin controller instance. + */ +struct nexell_pinctrl_priv { + const struct nexell_pin_ctrl *pin_ctrl; + unsigned long base; +}; + +/** + * struct nexell_pinctrl_config_data: configuration for a peripheral. + * @offset: offset of the config registers in the controller. + * @mask: value of the register to be masked with. + * @value: new value to be programmed. + */ +struct nexell_pinctrl_config_data { + const unsigned int offset; + const unsigned int mask; + const unsigned int value; +}; + +unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, + u32 *pin); +int nexell_pinctrl_probe(struct udevice *dev); + +#endif /* __PINCTRL_NEXELL_H_ */ diff --git a/drivers/pinctrl/nexell/pinctrl-s5pxx18.c b/drivers/pinctrl/nexell/pinctrl-s5pxx18.c new file mode 100644 index 0000000000..96a2ed38a0 --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-s5pxx18.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO <freestyle@nexell.co.kr> + * + * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <asm/io.h> +#include <dm/pinctrl.h> +#include <dm/root.h> +#include "pinctrl-nexell.h" +#include "pinctrl-s5pxx18.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void nx_gpio_set_bit(u32 *value, u32 bit, int enable) +{ + register u32 newvalue; + + newvalue = *value; + newvalue &= ~(1ul << bit); + newvalue |= (u32)enable << bit; + writel(newvalue, value); +} + +static void nx_gpio_set_bit2(u32 *value, u32 bit, u32 bit_value) +{ + register u32 newvalue = *value; + + newvalue = (u32)(newvalue & ~(3ul << (bit * 2))); + newvalue = (u32)(newvalue | (bit_value << (bit * 2))); + + writel(newvalue, value); +} + +static int nx_gpio_open_module(void *base) +{ + writel(0xFFFFFFFF, base + GPIOX_SLEW_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_DRV1_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_DRV0_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_PULLSEL_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_PULLENB_DISABLE_DEFAULT); + return true; +} + +static void nx_gpio_set_pad_function(void *base, u32 pin, u32 padfunc) +{ + u32 reg = (pin / 16) ? GPIOX_ALTFN1 : GPIOX_ALTFN0; + + nx_gpio_set_bit2(base + reg, pin % 16, padfunc); +} + +static void nx_gpio_set_drive_strength(void *base, u32 pin, u32 drv) +{ + nx_gpio_set_bit(base + GPIOX_DRV1, pin, (int)(((u32)drv >> 0) & 0x1)); + nx_gpio_set_bit(base + GPIOX_DRV0, pin, (int)(((u32)drv >> 1) & 0x1)); +} + +static void nx_gpio_set_pull_mode(void *base, u32 pin, u32 mode) +{ + if (mode == nx_gpio_pull_off) { + nx_gpio_set_bit(base + GPIOX_PULLENB, pin, false); + nx_gpio_set_bit(base + GPIOX_PULLSEL, pin, false); + } else { + nx_gpio_set_bit(base + GPIOX_PULLSEL, + pin, (mode & 1 ? true : false)); + nx_gpio_set_bit(base + GPIOX_PULLENB, pin, true); + } +} + +static void nx_alive_set_pullup(void *base, u32 pin, bool enable) +{ + u32 PULLUP_MASK; + + PULLUP_MASK = (1UL << pin); + if (enable) + writel(PULLUP_MASK, base + ALIVE_PADPULLUPSET); + else + writel(PULLUP_MASK, base + ALIVE_PADPULLUPRST); +} + +static int s5pxx18_pinctrl_gpio_init(struct udevice *dev) +{ + struct nexell_pinctrl_priv *priv = dev_get_priv(dev); + const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl; + unsigned long reg = priv->base; + int i; + + for (i = 0; i < ctrl->nr_banks - 1; i++) /* except alive bank */ + nx_gpio_open_module((void *)(reg + ctrl->pin_banks[i].offset)); + + return 0; +} + +static int s5pxx18_pinctrl_alive_init(struct udevice *dev) +{ + struct nexell_pinctrl_priv *priv = dev_get_priv(dev); + const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl; + unsigned long reg = priv->base; + + reg += ctrl->pin_banks[ctrl->nr_banks - 1].offset; + + writel(1, reg + ALIVE_PWRGATE); + return 0; +} + +int s5pxx18_pinctrl_init(struct udevice *dev) +{ + s5pxx18_pinctrl_gpio_init(dev); + s5pxx18_pinctrl_alive_init(dev); + + return 0; +} + +static int is_pin_alive(const char *name) +{ + return !strncmp(name, "alive", 5); +} + +/** + * s5pxx18_pinctrl_set_state: configure a pin state. + * dev: the pinctrl device to be configured. + * config: the state to be configured. + */ +static int s5pxx18_pinctrl_set_state(struct udevice *dev, + struct udevice *config) +{ + unsigned int count, idx, pin; + unsigned int pinfunc, pinpud, pindrv; + unsigned long reg; + const char *name; + int ret; + + /* + * refer to the following document for the pinctrl bindings + * doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt + */ + count = dev_read_string_count(config, "pins"); + + if (count <= 0) + return -EINVAL; + + pinfunc = dev_read_s32_default(config, "pin-function", -1); + pinpud = dev_read_s32_default(config, "pin-pull", -1); + pindrv = dev_read_s32_default(config, "pin-strength", -1); + + for (idx = 0; idx < count; idx++) { + ret = dev_read_string_index(config, "pins", idx, &name); + if (ret) + return ret; + if (!name) + continue; + reg = pin_to_bank_base(dev, name, &pin); + + if (is_pin_alive(name)) { + /* pin pull up/down */ + if (pinpud != -1) + nx_alive_set_pullup((void *)reg, pin, + pinpud & 1); + continue; + } + + /* pin function */ + if (pinfunc != -1) + nx_gpio_set_pad_function((void *)reg, pin, pinfunc); + + /* pin pull up/down/off */ + if (pinpud != -1) + nx_gpio_set_pull_mode((void *)reg, pin, pinpud); + + /* pin drive strength */ + if (pindrv != -1) + nx_gpio_set_drive_strength((void *)reg, pin, pindrv); + } + + return 0; +} + +static struct pinctrl_ops s5pxx18_pinctrl_ops = { + .set_state = s5pxx18_pinctrl_set_state, +}; + +/* pin banks of s5pxx18 pin-controller */ +static const struct nexell_pin_bank_data s5pxx18_pin_banks[] = { + NEXELL_PIN_BANK(32, 0xA000, "gpioa"), + NEXELL_PIN_BANK(32, 0xB000, "gpiob"), + NEXELL_PIN_BANK(32, 0xC000, "gpioc"), + NEXELL_PIN_BANK(32, 0xD000, "gpiod"), + NEXELL_PIN_BANK(32, 0xE000, "gpioe"), + NEXELL_PIN_BANK(6, 0x0800, "alive"), +}; + +const struct nexell_pin_ctrl s5pxx18_pin_ctrl[] = { + { + /* pin-controller data */ + .pin_banks = s5pxx18_pin_banks, + .nr_banks = ARRAY_SIZE(s5pxx18_pin_banks), + }, +}; + +static const struct udevice_id s5pxx18_pinctrl_ids[] = { + { .compatible = "nexell,s5pxx18-pinctrl", + .data = (ulong)s5pxx18_pin_ctrl }, + { } +}; + +U_BOOT_DRIVER(pinctrl_s5pxx18) = { + .name = "pinctrl_s5pxx18", + .id = UCLASS_PINCTRL, + .of_match = s5pxx18_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct nexell_pinctrl_priv), + .ops = &s5pxx18_pinctrl_ops, + .probe = nexell_pinctrl_probe, + .flags = DM_FLAG_PRE_RELOC +}; diff --git a/drivers/pinctrl/nexell/pinctrl-s5pxx18.h b/drivers/pinctrl/nexell/pinctrl-s5pxx18.h new file mode 100644 index 0000000000..843a00b955 --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-s5pxx18.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO <freestyle@nexell.co.kr> + */ + +#ifndef __PINCTRL_S5PXX18_H_ +#define __PINCTRL_S5PXX18_H_ + +#include <linux/types.h> +#include <asm/io.h> + +#define GPIOX_ALTFN0 0x20 +#define GPIOX_ALTFN1 0x24 +#define GPIOX_DRV1 0x48 +#define GPIOX_DRV0 0x50 +#define GPIOX_PULLSEL 0x58 +#define GPIOX_PULLENB 0x60 + +#define GPIOX_SLEW_DISABLE_DEFAULT 0x44 +#define GPIOX_DRV1_DISABLE_DEFAULT 0x4C +#define GPIOX_DRV0_DISABLE_DEFAULT 0x54 +#define GPIOX_PULLSEL_DISABLE_DEFAULT 0x5C +#define GPIOX_PULLENB_DISABLE_DEFAULT 0x64 + +#define ALIVE_PWRGATE 0x0 +#define ALIVE_PADPULLUPRST 0x80 +#define ALIVE_PADPULLUPSET 0x84 +#define ALIVE_PADPULLUPREAD 0x88 + +enum { + nx_gpio_padfunc_0 = 0ul, + nx_gpio_padfunc_1 = 1ul, + nx_gpio_padfunc_2 = 2ul, + nx_gpio_padfunc_3 = 3ul +}; + +enum { + nx_gpio_drvstrength_0 = 0ul, + nx_gpio_drvstrength_1 = 1ul, + nx_gpio_drvstrength_2 = 2ul, + nx_gpio_drvstrength_3 = 3ul +}; + +enum { + nx_gpio_pull_down = 0ul, + nx_gpio_pull_up = 1ul, + nx_gpio_pull_off = 2ul +}; + +int s5pxx18_pinctrl_init(struct udevice *dev); +#endif /* __PINCTRL_S5PXX18_H_ */ |