123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // 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
- };
|