183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
21f8f7730SSimon Glass /*
31f8f7730SSimon Glass * (C) Copyright 2015 Google, Inc
41f8f7730SSimon Glass *
51f8f7730SSimon Glass * (C) Copyright 2008-2014 Rockchip Electronics
61f8f7730SSimon Glass * Peter, Software Engineering, <superpeter.cai@gmail.com>.
71f8f7730SSimon Glass */
81f8f7730SSimon Glass
91f8f7730SSimon Glass #include <common.h>
101f8f7730SSimon Glass #include <dm.h>
1148647828SSimon Glass #include <syscon.h>
121221ce45SMasahiro Yamada #include <linux/errno.h>
131f8f7730SSimon Glass #include <asm/gpio.h>
141f8f7730SSimon Glass #include <asm/io.h>
1548647828SSimon Glass #include <asm/arch/clock.h>
1648647828SSimon Glass #include <dm/pinctrl.h>
1748647828SSimon Glass #include <dt-bindings/clock/rk3288-cru.h>
181f8f7730SSimon Glass
191f8f7730SSimon Glass enum {
201f8f7730SSimon Glass ROCKCHIP_GPIOS_PER_BANK = 32,
211f8f7730SSimon Glass };
221f8f7730SSimon Glass
231f8f7730SSimon Glass #define OFFSET_TO_BIT(bit) (1UL << (bit))
241f8f7730SSimon Glass
251f8f7730SSimon Glass struct rockchip_gpio_priv {
261f8f7730SSimon Glass struct rockchip_gpio_regs *regs;
2748647828SSimon Glass struct udevice *pinctrl;
2848647828SSimon Glass int bank;
291f8f7730SSimon Glass char name[2];
301f8f7730SSimon Glass };
311f8f7730SSimon Glass
rockchip_gpio_direction_input(struct udevice * dev,unsigned offset)321f8f7730SSimon Glass static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset)
331f8f7730SSimon Glass {
341f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev);
351f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs;
361f8f7730SSimon Glass
371f8f7730SSimon Glass clrbits_le32(®s->swport_ddr, OFFSET_TO_BIT(offset));
381f8f7730SSimon Glass
391f8f7730SSimon Glass return 0;
401f8f7730SSimon Glass }
411f8f7730SSimon Glass
rockchip_gpio_direction_output(struct udevice * dev,unsigned offset,int value)421f8f7730SSimon Glass static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset,
431f8f7730SSimon Glass int value)
441f8f7730SSimon Glass {
451f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev);
461f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs;
471f8f7730SSimon Glass int mask = OFFSET_TO_BIT(offset);
481f8f7730SSimon Glass
491f8f7730SSimon Glass clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0);
501f8f7730SSimon Glass setbits_le32(®s->swport_ddr, mask);
511f8f7730SSimon Glass
521f8f7730SSimon Glass return 0;
531f8f7730SSimon Glass }
541f8f7730SSimon Glass
rockchip_gpio_get_value(struct udevice * dev,unsigned offset)551f8f7730SSimon Glass static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset)
561f8f7730SSimon Glass {
571f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev);
581f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs;
591f8f7730SSimon Glass
607d0c2c3fSSimon Glass return readl(®s->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0;
611f8f7730SSimon Glass }
621f8f7730SSimon Glass
rockchip_gpio_set_value(struct udevice * dev,unsigned offset,int value)631f8f7730SSimon Glass static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
641f8f7730SSimon Glass int value)
651f8f7730SSimon Glass {
661f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev);
671f8f7730SSimon Glass struct rockchip_gpio_regs *regs = priv->regs;
681f8f7730SSimon Glass int mask = OFFSET_TO_BIT(offset);
691f8f7730SSimon Glass
701f8f7730SSimon Glass clrsetbits_le32(®s->swport_dr, mask, value ? mask : 0);
711f8f7730SSimon Glass
721f8f7730SSimon Glass return 0;
731f8f7730SSimon Glass }
741f8f7730SSimon Glass
rockchip_gpio_get_function(struct udevice * dev,unsigned offset)751f8f7730SSimon Glass static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
761f8f7730SSimon Glass {
7748647828SSimon Glass #ifdef CONFIG_SPL_BUILD
7848647828SSimon Glass return -ENODATA;
7948647828SSimon Glass #else
8048647828SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev);
8148647828SSimon Glass struct rockchip_gpio_regs *regs = priv->regs;
8248647828SSimon Glass bool is_output;
8348647828SSimon Glass int ret;
8448647828SSimon Glass
8548647828SSimon Glass ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
8648647828SSimon Glass if (ret)
8748647828SSimon Glass return ret;
8848647828SSimon Glass is_output = readl(®s->swport_ddr) & OFFSET_TO_BIT(offset);
8948647828SSimon Glass
9048647828SSimon Glass return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
9148647828SSimon Glass #endif
921f8f7730SSimon Glass }
931f8f7730SSimon Glass
94*aa48c94cSSimon Glass /* Simple SPL interface to GPIOs */
95*aa48c94cSSimon Glass #ifdef CONFIG_SPL_BUILD
96*aa48c94cSSimon Glass
97*aa48c94cSSimon Glass enum {
98*aa48c94cSSimon Glass PULL_NONE_1V8 = 0,
99*aa48c94cSSimon Glass PULL_DOWN_1V8 = 1,
100*aa48c94cSSimon Glass PULL_UP_1V8 = 3,
101*aa48c94cSSimon Glass };
102*aa48c94cSSimon Glass
spl_gpio_set_pull(void * vregs,uint gpio,int pull)103*aa48c94cSSimon Glass int spl_gpio_set_pull(void *vregs, uint gpio, int pull)
104*aa48c94cSSimon Glass {
105*aa48c94cSSimon Glass u32 *regs = vregs;
106*aa48c94cSSimon Glass uint val;
107*aa48c94cSSimon Glass
108*aa48c94cSSimon Glass regs += gpio >> GPIO_BANK_SHIFT;
109*aa48c94cSSimon Glass gpio &= GPIO_OFFSET_MASK;
110*aa48c94cSSimon Glass switch (pull) {
111*aa48c94cSSimon Glass case GPIO_PULL_UP:
112*aa48c94cSSimon Glass val = PULL_UP_1V8;
113*aa48c94cSSimon Glass break;
114*aa48c94cSSimon Glass case GPIO_PULL_DOWN:
115*aa48c94cSSimon Glass val = PULL_DOWN_1V8;
116*aa48c94cSSimon Glass break;
117*aa48c94cSSimon Glass case GPIO_PULL_NORMAL:
118*aa48c94cSSimon Glass default:
119*aa48c94cSSimon Glass val = PULL_NONE_1V8;
120*aa48c94cSSimon Glass break;
121*aa48c94cSSimon Glass }
122*aa48c94cSSimon Glass clrsetbits_le32(regs, 3 << (gpio * 2), val << (gpio * 2));
123*aa48c94cSSimon Glass
124*aa48c94cSSimon Glass return 0;
125*aa48c94cSSimon Glass }
126*aa48c94cSSimon Glass
spl_gpio_output(void * vregs,uint gpio,int value)127*aa48c94cSSimon Glass int spl_gpio_output(void *vregs, uint gpio, int value)
128*aa48c94cSSimon Glass {
129*aa48c94cSSimon Glass struct rockchip_gpio_regs * const regs = vregs;
130*aa48c94cSSimon Glass
131*aa48c94cSSimon Glass clrsetbits_le32(®s->swport_dr, 1 << gpio, value << gpio);
132*aa48c94cSSimon Glass
133*aa48c94cSSimon Glass /* Set direction */
134*aa48c94cSSimon Glass clrsetbits_le32(®s->swport_ddr, 1 << gpio, 1 << gpio);
135*aa48c94cSSimon Glass
136*aa48c94cSSimon Glass return 0;
137*aa48c94cSSimon Glass }
138*aa48c94cSSimon Glass #endif /* CONFIG_SPL_BUILD */
139*aa48c94cSSimon Glass
rockchip_gpio_probe(struct udevice * dev)1401f8f7730SSimon Glass static int rockchip_gpio_probe(struct udevice *dev)
1411f8f7730SSimon Glass {
1421f8f7730SSimon Glass struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
1431f8f7730SSimon Glass struct rockchip_gpio_priv *priv = dev_get_priv(dev);
1441f8f7730SSimon Glass char *end;
14548647828SSimon Glass int ret;
1461f8f7730SSimon Glass
147a1d3480bSPhilipp Tomsich priv->regs = dev_read_addr_ptr(dev);
1483f603cbbSSimon Glass ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl);
14948647828SSimon Glass if (ret)
15048647828SSimon Glass return ret;
15148647828SSimon Glass
1521f8f7730SSimon Glass uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
1531f8f7730SSimon Glass end = strrchr(dev->name, '@');
15448647828SSimon Glass priv->bank = trailing_strtoln(dev->name, end);
15548647828SSimon Glass priv->name[0] = 'A' + priv->bank;
1561f8f7730SSimon Glass uc_priv->bank_name = priv->name;
1571f8f7730SSimon Glass
1581f8f7730SSimon Glass return 0;
1591f8f7730SSimon Glass }
1601f8f7730SSimon Glass
1611f8f7730SSimon Glass static const struct dm_gpio_ops gpio_rockchip_ops = {
1621f8f7730SSimon Glass .direction_input = rockchip_gpio_direction_input,
1631f8f7730SSimon Glass .direction_output = rockchip_gpio_direction_output,
1641f8f7730SSimon Glass .get_value = rockchip_gpio_get_value,
1651f8f7730SSimon Glass .set_value = rockchip_gpio_set_value,
1661f8f7730SSimon Glass .get_function = rockchip_gpio_get_function,
1671f8f7730SSimon Glass };
1681f8f7730SSimon Glass
1691f8f7730SSimon Glass static const struct udevice_id rockchip_gpio_ids[] = {
1701f8f7730SSimon Glass { .compatible = "rockchip,gpio-bank" },
1711f8f7730SSimon Glass { }
1721f8f7730SSimon Glass };
1731f8f7730SSimon Glass
1741f8f7730SSimon Glass U_BOOT_DRIVER(gpio_rockchip) = {
1751f8f7730SSimon Glass .name = "gpio_rockchip",
1761f8f7730SSimon Glass .id = UCLASS_GPIO,
1771f8f7730SSimon Glass .of_match = rockchip_gpio_ids,
1781f8f7730SSimon Glass .ops = &gpio_rockchip_ops,
1791f8f7730SSimon Glass .priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv),
1801f8f7730SSimon Glass .probe = rockchip_gpio_probe,
1811f8f7730SSimon Glass };
182