xref: /openbmc/u-boot/drivers/gpio/rk_gpio.c (revision 486478282e537f0e594ec68d6d7481e3220a7b47)
11f8f7730SSimon Glass /*
21f8f7730SSimon Glass  * (C) Copyright 2015 Google, Inc
31f8f7730SSimon Glass  *
41f8f7730SSimon Glass  * (C) Copyright 2008-2014 Rockchip Electronics
51f8f7730SSimon Glass  * Peter, Software Engineering, <superpeter.cai@gmail.com>.
61f8f7730SSimon Glass  *
71f8f7730SSimon Glass  * SPDX-License-Identifier:     GPL-2.0+
81f8f7730SSimon Glass  */
91f8f7730SSimon Glass 
101f8f7730SSimon Glass #include <common.h>
11*48647828SSimon Glass #include <clk.h>
121f8f7730SSimon Glass #include <dm.h>
13*48647828SSimon Glass #include <syscon.h>
141f8f7730SSimon Glass #include <asm/errno.h>
151f8f7730SSimon Glass #include <asm/gpio.h>
161f8f7730SSimon Glass #include <asm/io.h>
17*48647828SSimon Glass #include <asm/arch/clock.h>
18*48647828SSimon Glass #include <dm/pinctrl.h>
191f8f7730SSimon Glass #include <dt-bindings/gpio/gpio.h>
20*48647828SSimon Glass #include <dt-bindings/clock/rk3288-cru.h>
211f8f7730SSimon Glass 
221f8f7730SSimon Glass enum {
231f8f7730SSimon Glass 	ROCKCHIP_GPIOS_PER_BANK		= 32,
241f8f7730SSimon Glass };
251f8f7730SSimon Glass 
261f8f7730SSimon Glass #define OFFSET_TO_BIT(bit)	(1UL << (bit))
271f8f7730SSimon Glass 
281f8f7730SSimon Glass struct rockchip_gpio_priv {
291f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs;
30*48647828SSimon Glass 	struct udevice *pinctrl;
31*48647828SSimon Glass 	int bank;
321f8f7730SSimon Glass 	char name[2];
331f8f7730SSimon Glass };
341f8f7730SSimon Glass 
351f8f7730SSimon Glass static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset)
361f8f7730SSimon Glass {
371f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
381f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
391f8f7730SSimon Glass 
401f8f7730SSimon Glass 	clrbits_le32(&regs->swport_ddr, OFFSET_TO_BIT(offset));
411f8f7730SSimon Glass 
421f8f7730SSimon Glass 	return 0;
431f8f7730SSimon Glass }
441f8f7730SSimon Glass 
451f8f7730SSimon Glass static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset,
461f8f7730SSimon Glass 					  int value)
471f8f7730SSimon Glass {
481f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
491f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
501f8f7730SSimon Glass 	int mask = OFFSET_TO_BIT(offset);
511f8f7730SSimon Glass 
521f8f7730SSimon Glass 	clrsetbits_le32(&regs->swport_dr, mask, value ? mask : 0);
531f8f7730SSimon Glass 	setbits_le32(&regs->swport_ddr, mask);
541f8f7730SSimon Glass 
551f8f7730SSimon Glass 	return 0;
561f8f7730SSimon Glass }
571f8f7730SSimon Glass 
581f8f7730SSimon Glass static int rockchip_gpio_get_value(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 
637d0c2c3fSSimon Glass 	return readl(&regs->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0;
641f8f7730SSimon Glass }
651f8f7730SSimon Glass 
661f8f7730SSimon Glass static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
671f8f7730SSimon Glass 				   int value)
681f8f7730SSimon Glass {
691f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
701f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
711f8f7730SSimon Glass 	int mask = OFFSET_TO_BIT(offset);
721f8f7730SSimon Glass 
731f8f7730SSimon Glass 	clrsetbits_le32(&regs->swport_dr, mask, value ? mask : 0);
741f8f7730SSimon Glass 
751f8f7730SSimon Glass 	return 0;
761f8f7730SSimon Glass }
771f8f7730SSimon Glass 
781f8f7730SSimon Glass static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
791f8f7730SSimon Glass {
80*48647828SSimon Glass #ifdef CONFIG_SPL_BUILD
81*48647828SSimon Glass 	return -ENODATA;
82*48647828SSimon Glass #else
83*48647828SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
84*48647828SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
85*48647828SSimon Glass 	bool is_output;
86*48647828SSimon Glass 	int ret;
87*48647828SSimon Glass 
88*48647828SSimon Glass 	ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
89*48647828SSimon Glass 	if (ret)
90*48647828SSimon Glass 		return ret;
91*48647828SSimon Glass 
92*48647828SSimon Glass 	/* If it's not 0, then it is not a GPIO */
93*48647828SSimon Glass 	if (ret)
94*48647828SSimon Glass 		return GPIOF_FUNC;
95*48647828SSimon Glass 	is_output = readl(&regs->swport_ddr) & OFFSET_TO_BIT(offset);
96*48647828SSimon Glass 
97*48647828SSimon Glass 	return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
98*48647828SSimon Glass #endif
991f8f7730SSimon Glass }
1001f8f7730SSimon Glass 
1011f8f7730SSimon Glass static int rockchip_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
1021f8f7730SSimon Glass 			    struct fdtdec_phandle_args *args)
1031f8f7730SSimon Glass {
1041f8f7730SSimon Glass 	desc->offset = args->args[0];
1051f8f7730SSimon Glass 	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
1061f8f7730SSimon Glass 
1071f8f7730SSimon Glass 	return 0;
1081f8f7730SSimon Glass }
1091f8f7730SSimon Glass 
1101f8f7730SSimon Glass static int rockchip_gpio_probe(struct udevice *dev)
1111f8f7730SSimon Glass {
1121f8f7730SSimon Glass 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
1131f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
1141f8f7730SSimon Glass 	char *end;
115*48647828SSimon Glass 	int ret;
1161f8f7730SSimon Glass 
117*48647828SSimon Glass 	/* This only supports RK3288 at present */
1181f8f7730SSimon Glass 	priv->regs = (struct rockchip_gpio_regs *)dev_get_addr(dev);
119*48647828SSimon Glass 	ret = uclass_first_device(UCLASS_PINCTRL, &priv->pinctrl);
120*48647828SSimon Glass 	if (ret)
121*48647828SSimon Glass 		return ret;
122*48647828SSimon Glass 	if (!priv->pinctrl)
123*48647828SSimon Glass 		return -ENODEV;
124*48647828SSimon Glass 
1251f8f7730SSimon Glass 	uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
1261f8f7730SSimon Glass 	end = strrchr(dev->name, '@');
127*48647828SSimon Glass 	priv->bank = trailing_strtoln(dev->name, end);
128*48647828SSimon Glass 	priv->name[0] = 'A' + priv->bank;
1291f8f7730SSimon Glass 	uc_priv->bank_name = priv->name;
1301f8f7730SSimon Glass 
1311f8f7730SSimon Glass 	return 0;
1321f8f7730SSimon Glass }
1331f8f7730SSimon Glass 
1341f8f7730SSimon Glass static const struct dm_gpio_ops gpio_rockchip_ops = {
1351f8f7730SSimon Glass 	.direction_input	= rockchip_gpio_direction_input,
1361f8f7730SSimon Glass 	.direction_output	= rockchip_gpio_direction_output,
1371f8f7730SSimon Glass 	.get_value		= rockchip_gpio_get_value,
1381f8f7730SSimon Glass 	.set_value		= rockchip_gpio_set_value,
1391f8f7730SSimon Glass 	.get_function		= rockchip_gpio_get_function,
1401f8f7730SSimon Glass 	.xlate			= rockchip_gpio_xlate,
1411f8f7730SSimon Glass };
1421f8f7730SSimon Glass 
1431f8f7730SSimon Glass static const struct udevice_id rockchip_gpio_ids[] = {
1441f8f7730SSimon Glass 	{ .compatible = "rockchip,gpio-bank" },
1451f8f7730SSimon Glass 	{ }
1461f8f7730SSimon Glass };
1471f8f7730SSimon Glass 
1481f8f7730SSimon Glass U_BOOT_DRIVER(gpio_rockchip) = {
1491f8f7730SSimon Glass 	.name	= "gpio_rockchip",
1501f8f7730SSimon Glass 	.id	= UCLASS_GPIO,
1511f8f7730SSimon Glass 	.of_match = rockchip_gpio_ids,
1521f8f7730SSimon Glass 	.ops	= &gpio_rockchip_ops,
1531f8f7730SSimon Glass 	.priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv),
1541f8f7730SSimon Glass 	.probe	= rockchip_gpio_probe,
1551f8f7730SSimon Glass };
156