xref: /rk3399_rockchip-uboot/drivers/gpio/rk_gpio.c (revision 42b90858f890e089db22d863d9e2f1715ac6ad84)
11f8f7730SSimon Glass /*
21f8f7730SSimon Glass  * (C) Copyright 2015 Google, Inc
31f8f7730SSimon Glass  *
4d1aef94bSJianqun Xu  * (C) Copyright 2008-2020 Rockchip Electronics
51f8f7730SSimon Glass  * Peter, Software Engineering, <superpeter.cai@gmail.com>.
6d1aef94bSJianqun Xu  * Jianqun Xu, Software Engineering, <jay.xu@rock-chips.com>.
71f8f7730SSimon Glass  *
81f8f7730SSimon Glass  * SPDX-License-Identifier:     GPL-2.0+
91f8f7730SSimon Glass  */
101f8f7730SSimon Glass 
111f8f7730SSimon Glass #include <common.h>
121f8f7730SSimon Glass #include <dm.h>
13dbff1ed6SJianqun Xu #include <dm/of_access.h>
1448647828SSimon Glass #include <syscon.h>
151221ce45SMasahiro Yamada #include <linux/errno.h>
161f8f7730SSimon Glass #include <asm/gpio.h>
171f8f7730SSimon Glass #include <asm/io.h>
1848647828SSimon Glass #include <asm/arch/clock.h>
1948647828SSimon Glass #include <dm/pinctrl.h>
2048647828SSimon Glass #include <dt-bindings/clock/rk3288-cru.h>
211f8f7730SSimon Glass 
22dbff1ed6SJianqun Xu #include "../pinctrl/rockchip/pinctrl-rockchip.h"
231f8f7730SSimon Glass 
241f8f7730SSimon Glass #define OFFSET_TO_BIT(bit)	(1UL << (bit))
251f8f7730SSimon Glass 
26d1aef94bSJianqun Xu #ifdef CONFIG_ROCKCHIP_GPIO_V2
27d1aef94bSJianqun Xu #define REG_L(R)	(R##_l)
28d1aef94bSJianqun Xu #define REG_H(R)	(R##_h)
29d1aef94bSJianqun Xu #define READ_REG(REG)	((readl(REG_L(REG)) & 0xFFFF) | \
30d1aef94bSJianqun Xu 			((readl(REG_H(REG)) & 0xFFFF) << 16))
31d1aef94bSJianqun Xu #define WRITE_REG(REG, VAL)	\
32d1aef94bSJianqun Xu {\
33d1aef94bSJianqun Xu 	writel(((VAL) & 0xFFFF) | 0xFFFF0000, REG_L(REG)); \
34d1aef94bSJianqun Xu 	writel((((VAL) & 0xFFFF0000) >> 16) | 0xFFFF0000, REG_H(REG));\
35d1aef94bSJianqun Xu }
36d1aef94bSJianqun Xu #define CLRBITS_LE32(REG, MASK)	WRITE_REG(REG, READ_REG(REG) & ~(MASK))
37d1aef94bSJianqun Xu #define SETBITS_LE32(REG, MASK)	WRITE_REG(REG, READ_REG(REG) | (MASK))
38d1aef94bSJianqun Xu #define CLRSETBITS_LE32(REG, MASK, VAL)	WRITE_REG(REG, \
39d1aef94bSJianqun Xu 				(READ_REG(REG) & ~(MASK)) | (VAL))
40d1aef94bSJianqun Xu 
41d1aef94bSJianqun Xu #else
42d1aef94bSJianqun Xu #define READ_REG(REG)			readl(REG)
43d1aef94bSJianqun Xu #define WRITE_REG(REG, VAL)		writel(VAL, REG)
44d1aef94bSJianqun Xu #define CLRBITS_LE32(REG, MASK)		clrbits_le32(REG, MASK)
45d1aef94bSJianqun Xu #define SETBITS_LE32(REG, MASK)		setbits_le32(REG, MASK)
46d1aef94bSJianqun Xu #define CLRSETBITS_LE32(REG, MASK, VAL)	clrsetbits_le32(REG, MASK, VAL)
47d1aef94bSJianqun Xu #endif
48d1aef94bSJianqun Xu 
49d1aef94bSJianqun Xu 
501f8f7730SSimon Glass struct rockchip_gpio_priv {
511f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs;
5248647828SSimon Glass 	struct udevice *pinctrl;
5348647828SSimon Glass 	int bank;
541f8f7730SSimon Glass 	char name[2];
551f8f7730SSimon Glass };
561f8f7730SSimon Glass 
rockchip_gpio_direction_input(struct udevice * dev,unsigned offset)571f8f7730SSimon Glass static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset)
581f8f7730SSimon Glass {
591f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
601f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
611f8f7730SSimon Glass 
62d1aef94bSJianqun Xu 	CLRBITS_LE32(&regs->swport_ddr, OFFSET_TO_BIT(offset));
631f8f7730SSimon Glass 
641f8f7730SSimon Glass 	return 0;
651f8f7730SSimon Glass }
661f8f7730SSimon Glass 
rockchip_gpio_direction_output(struct udevice * dev,unsigned offset,int value)671f8f7730SSimon Glass static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset,
681f8f7730SSimon Glass 					  int value)
691f8f7730SSimon Glass {
701f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
711f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
721f8f7730SSimon Glass 	int mask = OFFSET_TO_BIT(offset);
731f8f7730SSimon Glass 
74d1aef94bSJianqun Xu 	CLRSETBITS_LE32(&regs->swport_dr, mask, value ? mask : 0);
75d1aef94bSJianqun Xu 	SETBITS_LE32(&regs->swport_ddr, mask);
761f8f7730SSimon Glass 
771f8f7730SSimon Glass 	return 0;
781f8f7730SSimon Glass }
791f8f7730SSimon Glass 
rockchip_gpio_get_value(struct udevice * dev,unsigned offset)801f8f7730SSimon Glass static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset)
811f8f7730SSimon Glass {
821f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
831f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
841f8f7730SSimon Glass 
857d0c2c3fSSimon Glass 	return readl(&regs->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0;
861f8f7730SSimon Glass }
871f8f7730SSimon Glass 
rockchip_gpio_set_value(struct udevice * dev,unsigned offset,int value)881f8f7730SSimon Glass static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
891f8f7730SSimon Glass 				   int value)
901f8f7730SSimon Glass {
911f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
921f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
931f8f7730SSimon Glass 	int mask = OFFSET_TO_BIT(offset);
941f8f7730SSimon Glass 
95d1aef94bSJianqun Xu 	CLRSETBITS_LE32(&regs->swport_dr, mask, value ? mask : 0);
961f8f7730SSimon Glass 
971f8f7730SSimon Glass 	return 0;
981f8f7730SSimon Glass }
991f8f7730SSimon Glass 
rockchip_gpio_get_function(struct udevice * dev,unsigned offset)1001f8f7730SSimon Glass static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
1011f8f7730SSimon Glass {
10248647828SSimon Glass #ifdef CONFIG_SPL_BUILD
10348647828SSimon Glass 	return -ENODATA;
10448647828SSimon Glass #else
10548647828SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
10648647828SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
10748647828SSimon Glass 	bool is_output;
10848647828SSimon Glass 	int ret;
10948647828SSimon Glass 
11048647828SSimon Glass 	ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
111e9c98b3bSJianqun Xu 	if (ret < 0) {
112e9c98b3bSJianqun Xu 		dev_err(dev, "fail to get gpio mux %d\n", ret);
11348647828SSimon Glass 		return ret;
114e9c98b3bSJianqun Xu 	}
11548647828SSimon Glass 
11648647828SSimon Glass 	/* If it's not 0, then it is not a GPIO */
117e9c98b3bSJianqun Xu 	if (ret > 0)
11848647828SSimon Glass 		return GPIOF_FUNC;
119d1aef94bSJianqun Xu 
120d1aef94bSJianqun Xu 	is_output = READ_REG(&regs->swport_ddr) & OFFSET_TO_BIT(offset);
12148647828SSimon Glass 
12248647828SSimon Glass 	return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
12348647828SSimon Glass #endif
1241f8f7730SSimon Glass }
1251f8f7730SSimon Glass 
rockchip_gpio_probe(struct udevice * dev)1261f8f7730SSimon Glass static int rockchip_gpio_probe(struct udevice *dev)
1271f8f7730SSimon Glass {
1281f8f7730SSimon Glass 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
1291f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
130dbff1ed6SJianqun Xu 	struct rockchip_pinctrl_priv *pctrl_priv;
131dbff1ed6SJianqun Xu 	struct rockchip_pin_bank *bank;
132dbff1ed6SJianqun Xu 	char *end = NULL;
133dbff1ed6SJianqun Xu 	int id = -1, ret;
1341f8f7730SSimon Glass 
13555efd69cSPhilipp Tomsich 	priv->regs = dev_read_addr_ptr(dev);
1360a5d7f3eSWyon Bi 	ret = uclass_get_device_by_seq(UCLASS_PINCTRL, 0, &priv->pinctrl);
1370a5d7f3eSWyon Bi 	if (ret) {
1383f603cbbSSimon Glass 		ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl);
139dbff1ed6SJianqun Xu 		if (ret) {
140dbff1ed6SJianqun Xu 			dev_err(dev, "failed to get pinctrl device %d\n", ret);
14148647828SSimon Glass 			return ret;
1429f32e0d2SJianqun Xu 		}
1430a5d7f3eSWyon Bi 	}
1447d13e745SJianqun Xu 
145dbff1ed6SJianqun Xu 	pctrl_priv = dev_get_priv(priv->pinctrl);
146dbff1ed6SJianqun Xu 	if (!pctrl_priv) {
147dbff1ed6SJianqun Xu 		dev_err(dev, "failed to get pinctrl priv\n");
148dbff1ed6SJianqun Xu 		return -EINVAL;
149dbff1ed6SJianqun Xu 	}
150dbff1ed6SJianqun Xu 
151dbff1ed6SJianqun Xu 	end = strrchr(dev->name, '@');
152dbff1ed6SJianqun Xu 	if (end)
153dbff1ed6SJianqun Xu 		id = trailing_strtoln(dev->name, end);
154d3909692SJianqun Xu 	if (id < 0)
155dbff1ed6SJianqun Xu 		dev_read_alias_seq(dev, &id);
156dbff1ed6SJianqun Xu 
157d3909692SJianqun Xu 	if (id < 0 || id >= pctrl_priv->ctrl->nr_banks) {
158*42b90858SJoseph Chen 		dev_err(dev, "nr_banks=%d, bank id=%d invalid\n",
159*42b90858SJoseph Chen 			pctrl_priv->ctrl->nr_banks, id);
160dbff1ed6SJianqun Xu 		return -EINVAL;
161dbff1ed6SJianqun Xu 	}
162dbff1ed6SJianqun Xu 
163dbff1ed6SJianqun Xu 	bank = &pctrl_priv->ctrl->pin_banks[id];
164dbff1ed6SJianqun Xu 	if (bank->bank_num != id) {
165dbff1ed6SJianqun Xu 		dev_err(dev, "bank id mismatch with pinctrl\n");
166dbff1ed6SJianqun Xu 		return -EINVAL;
167dbff1ed6SJianqun Xu 	}
168dbff1ed6SJianqun Xu 
169dbff1ed6SJianqun Xu 	priv->bank = bank->bank_num;
170dbff1ed6SJianqun Xu 	uc_priv->gpio_count = bank->nr_pins;
171dbff1ed6SJianqun Xu 	uc_priv->gpio_base = bank->pin_base;
172dbff1ed6SJianqun Xu 	uc_priv->bank_name = bank->name;
173dbff1ed6SJianqun Xu 
1741f8f7730SSimon Glass 	return 0;
1751f8f7730SSimon Glass }
1761f8f7730SSimon Glass 
1771f8f7730SSimon Glass static const struct dm_gpio_ops gpio_rockchip_ops = {
1781f8f7730SSimon Glass 	.direction_input	= rockchip_gpio_direction_input,
1791f8f7730SSimon Glass 	.direction_output	= rockchip_gpio_direction_output,
1801f8f7730SSimon Glass 	.get_value		= rockchip_gpio_get_value,
1811f8f7730SSimon Glass 	.set_value		= rockchip_gpio_set_value,
1821f8f7730SSimon Glass 	.get_function		= rockchip_gpio_get_function,
1831f8f7730SSimon Glass };
1841f8f7730SSimon Glass 
1851f8f7730SSimon Glass static const struct udevice_id rockchip_gpio_ids[] = {
1861f8f7730SSimon Glass 	{ .compatible = "rockchip,gpio-bank" },
1871f8f7730SSimon Glass 	{ }
1881f8f7730SSimon Glass };
1891f8f7730SSimon Glass 
1901f8f7730SSimon Glass U_BOOT_DRIVER(gpio_rockchip) = {
1911f8f7730SSimon Glass 	.name	= "gpio_rockchip",
1921f8f7730SSimon Glass 	.id	= UCLASS_GPIO,
1931f8f7730SSimon Glass 	.of_match = rockchip_gpio_ids,
1941f8f7730SSimon Glass 	.ops	= &gpio_rockchip_ops,
1951f8f7730SSimon Glass 	.priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv),
1961f8f7730SSimon Glass 	.probe	= rockchip_gpio_probe,
1971f8f7730SSimon Glass };
198