xref: /rk3399_rockchip-uboot/drivers/gpio/rk_gpio.c (revision 9f32e0d2ecc1596d29f334a5e042fe8cd84d62b4)
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>
1348647828SSimon Glass #include <syscon.h>
141221ce45SMasahiro Yamada #include <linux/errno.h>
151f8f7730SSimon Glass #include <asm/gpio.h>
161f8f7730SSimon Glass #include <asm/io.h>
1748647828SSimon Glass #include <asm/arch/clock.h>
1848647828SSimon Glass #include <dm/pinctrl.h>
1948647828SSimon Glass #include <dt-bindings/clock/rk3288-cru.h>
201f8f7730SSimon Glass 
211f8f7730SSimon Glass enum {
221f8f7730SSimon Glass 	ROCKCHIP_GPIOS_PER_BANK		= 32,
231f8f7730SSimon Glass };
241f8f7730SSimon Glass 
251f8f7730SSimon Glass #define OFFSET_TO_BIT(bit)	(1UL << (bit))
261f8f7730SSimon Glass 
27d1aef94bSJianqun Xu #ifdef CONFIG_ROCKCHIP_GPIO_V2
28d1aef94bSJianqun Xu #define REG_L(R)	(R##_l)
29d1aef94bSJianqun Xu #define REG_H(R)	(R##_h)
30d1aef94bSJianqun Xu #define READ_REG(REG)	((readl(REG_L(REG)) & 0xFFFF) | \
31d1aef94bSJianqun Xu 			((readl(REG_H(REG)) & 0xFFFF) << 16))
32d1aef94bSJianqun Xu #define WRITE_REG(REG, VAL)	\
33d1aef94bSJianqun Xu {\
34d1aef94bSJianqun Xu 	writel(((VAL) & 0xFFFF) | 0xFFFF0000, REG_L(REG)); \
35d1aef94bSJianqun Xu 	writel((((VAL) & 0xFFFF0000) >> 16) | 0xFFFF0000, REG_H(REG));\
36d1aef94bSJianqun Xu }
37d1aef94bSJianqun Xu #define CLRBITS_LE32(REG, MASK)	WRITE_REG(REG, READ_REG(REG) & ~(MASK))
38d1aef94bSJianqun Xu #define SETBITS_LE32(REG, MASK)	WRITE_REG(REG, READ_REG(REG) | (MASK))
39d1aef94bSJianqun Xu #define CLRSETBITS_LE32(REG, MASK, VAL)	WRITE_REG(REG, \
40d1aef94bSJianqun Xu 				(READ_REG(REG) & ~(MASK)) | (VAL))
41d1aef94bSJianqun Xu 
42d1aef94bSJianqun Xu #else
43d1aef94bSJianqun Xu #define READ_REG(REG)			readl(REG)
44d1aef94bSJianqun Xu #define WRITE_REG(REG, VAL)		writel(VAL, REG)
45d1aef94bSJianqun Xu #define CLRBITS_LE32(REG, MASK)		clrbits_le32(REG, MASK)
46d1aef94bSJianqun Xu #define SETBITS_LE32(REG, MASK)		setbits_le32(REG, MASK)
47d1aef94bSJianqun Xu #define CLRSETBITS_LE32(REG, MASK, VAL)	clrsetbits_le32(REG, MASK, VAL)
48d1aef94bSJianqun Xu #endif
49d1aef94bSJianqun Xu 
50d1aef94bSJianqun Xu 
511f8f7730SSimon Glass struct rockchip_gpio_priv {
521f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs;
5348647828SSimon Glass 	struct udevice *pinctrl;
5448647828SSimon Glass 	int bank;
551f8f7730SSimon Glass 	char name[2];
561f8f7730SSimon Glass };
571f8f7730SSimon Glass 
581f8f7730SSimon Glass static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset)
591f8f7730SSimon Glass {
601f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
611f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
621f8f7730SSimon Glass 
63d1aef94bSJianqun Xu 	CLRBITS_LE32(&regs->swport_ddr, OFFSET_TO_BIT(offset));
641f8f7730SSimon Glass 
651f8f7730SSimon Glass 	return 0;
661f8f7730SSimon Glass }
671f8f7730SSimon Glass 
681f8f7730SSimon Glass static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset,
691f8f7730SSimon Glass 					  int value)
701f8f7730SSimon Glass {
711f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
721f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
731f8f7730SSimon Glass 	int mask = OFFSET_TO_BIT(offset);
741f8f7730SSimon Glass 
75d1aef94bSJianqun Xu 	CLRSETBITS_LE32(&regs->swport_dr, mask, value ? mask : 0);
76d1aef94bSJianqun Xu 	SETBITS_LE32(&regs->swport_ddr, mask);
771f8f7730SSimon Glass 
781f8f7730SSimon Glass 	return 0;
791f8f7730SSimon Glass }
801f8f7730SSimon Glass 
811f8f7730SSimon Glass static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset)
821f8f7730SSimon Glass {
831f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
841f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
851f8f7730SSimon Glass 
867d0c2c3fSSimon Glass 	return readl(&regs->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0;
871f8f7730SSimon Glass }
881f8f7730SSimon Glass 
891f8f7730SSimon Glass static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
901f8f7730SSimon Glass 				   int value)
911f8f7730SSimon Glass {
921f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
931f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
941f8f7730SSimon Glass 	int mask = OFFSET_TO_BIT(offset);
951f8f7730SSimon Glass 
96d1aef94bSJianqun Xu 	CLRSETBITS_LE32(&regs->swport_dr, mask, value ? mask : 0);
971f8f7730SSimon Glass 
981f8f7730SSimon Glass 	return 0;
991f8f7730SSimon Glass }
1001f8f7730SSimon Glass 
1011f8f7730SSimon Glass static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
1021f8f7730SSimon Glass {
10348647828SSimon Glass #ifdef CONFIG_SPL_BUILD
10448647828SSimon Glass 	return -ENODATA;
10548647828SSimon Glass #else
10648647828SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
10748647828SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
10848647828SSimon Glass 	bool is_output;
10948647828SSimon Glass 	int ret;
11048647828SSimon Glass 
11148647828SSimon Glass 	ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
11248647828SSimon Glass 	if (ret)
11348647828SSimon Glass 		return ret;
11448647828SSimon Glass 
11548647828SSimon Glass 	/* If it's not 0, then it is not a GPIO */
11648647828SSimon Glass 	if (ret)
11748647828SSimon Glass 		return GPIOF_FUNC;
118d1aef94bSJianqun Xu 
119d1aef94bSJianqun Xu 	is_output = READ_REG(&regs->swport_ddr) & OFFSET_TO_BIT(offset);
12048647828SSimon Glass 
12148647828SSimon Glass 	return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
12248647828SSimon Glass #endif
1231f8f7730SSimon Glass }
1241f8f7730SSimon Glass 
1251f8f7730SSimon Glass static int rockchip_gpio_probe(struct udevice *dev)
1261f8f7730SSimon Glass {
1271f8f7730SSimon Glass 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
1281f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
1291f8f7730SSimon Glass 	char *end;
1307d13e745SJianqun Xu 	int pins_num;
13148647828SSimon Glass 	int ret;
1321f8f7730SSimon Glass 
13355efd69cSPhilipp Tomsich 	priv->regs = dev_read_addr_ptr(dev);
1343f603cbbSSimon Glass 	ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl);
13548647828SSimon Glass 	if (ret)
13648647828SSimon Glass 		return ret;
13748647828SSimon Glass 
1381f8f7730SSimon Glass 	uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
1391f8f7730SSimon Glass 	end = strrchr(dev->name, '@');
14048647828SSimon Glass 	priv->bank = trailing_strtoln(dev->name, end);
14148647828SSimon Glass 	priv->name[0] = 'A' + priv->bank;
1421f8f7730SSimon Glass 	uc_priv->bank_name = priv->name;
1431f8f7730SSimon Glass 
1447d13e745SJianqun Xu 	pins_num = pinctrl_get_pins_count(priv->pinctrl);
145*9f32e0d2SJianqun Xu 	if (pins_num <= 0) {
146*9f32e0d2SJianqun Xu 		printf("%s: fail to get pins from pinctrl\n", __func__);
147*9f32e0d2SJianqun Xu 	} else if ((priv->bank + 1) * ROCKCHIP_GPIOS_PER_BANK >= pins_num) {
1487d13e745SJianqun Xu 		uc_priv->gpio_count = pins_num - priv->bank * ROCKCHIP_GPIOS_PER_BANK;
149*9f32e0d2SJianqun Xu 	}
1507d13e745SJianqun Xu 
1511f8f7730SSimon Glass 	return 0;
1521f8f7730SSimon Glass }
1531f8f7730SSimon Glass 
1541f8f7730SSimon Glass static const struct dm_gpio_ops gpio_rockchip_ops = {
1551f8f7730SSimon Glass 	.direction_input	= rockchip_gpio_direction_input,
1561f8f7730SSimon Glass 	.direction_output	= rockchip_gpio_direction_output,
1571f8f7730SSimon Glass 	.get_value		= rockchip_gpio_get_value,
1581f8f7730SSimon Glass 	.set_value		= rockchip_gpio_set_value,
1591f8f7730SSimon Glass 	.get_function		= rockchip_gpio_get_function,
1601f8f7730SSimon Glass };
1611f8f7730SSimon Glass 
1621f8f7730SSimon Glass static const struct udevice_id rockchip_gpio_ids[] = {
1631f8f7730SSimon Glass 	{ .compatible = "rockchip,gpio-bank" },
1641f8f7730SSimon Glass 	{ }
1651f8f7730SSimon Glass };
1661f8f7730SSimon Glass 
1671f8f7730SSimon Glass U_BOOT_DRIVER(gpio_rockchip) = {
1681f8f7730SSimon Glass 	.name	= "gpio_rockchip",
1691f8f7730SSimon Glass 	.id	= UCLASS_GPIO,
1701f8f7730SSimon Glass 	.of_match = rockchip_gpio_ids,
1711f8f7730SSimon Glass 	.ops	= &gpio_rockchip_ops,
1721f8f7730SSimon Glass 	.priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv),
1731f8f7730SSimon Glass 	.probe	= rockchip_gpio_probe,
1741f8f7730SSimon Glass };
175