xref: /openbmc/u-boot/drivers/gpio/rk_gpio.c (revision 3f603cbbb8e175e545d6037a783e1ef82bab30f9)
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>
1148647828SSimon Glass #include <clk.h>
121f8f7730SSimon Glass #include <dm.h>
1348647828SSimon Glass #include <syscon.h>
141f8f7730SSimon Glass #include <asm/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>
191f8f7730SSimon Glass #include <dt-bindings/gpio/gpio.h>
2048647828SSimon 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;
3048647828SSimon Glass 	struct udevice *pinctrl;
3148647828SSimon 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 {
8048647828SSimon Glass #ifdef CONFIG_SPL_BUILD
8148647828SSimon Glass 	return -ENODATA;
8248647828SSimon Glass #else
8348647828SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
8448647828SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
8548647828SSimon Glass 	bool is_output;
8648647828SSimon Glass 	int ret;
8748647828SSimon Glass 
8848647828SSimon Glass 	ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
8948647828SSimon Glass 	if (ret)
9048647828SSimon Glass 		return ret;
9148647828SSimon Glass 
9248647828SSimon Glass 	/* If it's not 0, then it is not a GPIO */
9348647828SSimon Glass 	if (ret)
9448647828SSimon Glass 		return GPIOF_FUNC;
9548647828SSimon Glass 	is_output = readl(&regs->swport_ddr) & OFFSET_TO_BIT(offset);
9648647828SSimon Glass 
9748647828SSimon Glass 	return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
9848647828SSimon 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;
11548647828SSimon Glass 	int ret;
1161f8f7730SSimon Glass 
11748647828SSimon Glass 	/* This only supports RK3288 at present */
1181f8f7730SSimon Glass 	priv->regs = (struct rockchip_gpio_regs *)dev_get_addr(dev);
119*3f603cbbSSimon Glass 	ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl);
12048647828SSimon Glass 	if (ret)
12148647828SSimon Glass 		return ret;
12248647828SSimon Glass 
1231f8f7730SSimon Glass 	uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
1241f8f7730SSimon Glass 	end = strrchr(dev->name, '@');
12548647828SSimon Glass 	priv->bank = trailing_strtoln(dev->name, end);
12648647828SSimon Glass 	priv->name[0] = 'A' + priv->bank;
1271f8f7730SSimon Glass 	uc_priv->bank_name = priv->name;
1281f8f7730SSimon Glass 
1291f8f7730SSimon Glass 	return 0;
1301f8f7730SSimon Glass }
1311f8f7730SSimon Glass 
1321f8f7730SSimon Glass static const struct dm_gpio_ops gpio_rockchip_ops = {
1331f8f7730SSimon Glass 	.direction_input	= rockchip_gpio_direction_input,
1341f8f7730SSimon Glass 	.direction_output	= rockchip_gpio_direction_output,
1351f8f7730SSimon Glass 	.get_value		= rockchip_gpio_get_value,
1361f8f7730SSimon Glass 	.set_value		= rockchip_gpio_set_value,
1371f8f7730SSimon Glass 	.get_function		= rockchip_gpio_get_function,
1381f8f7730SSimon Glass 	.xlate			= rockchip_gpio_xlate,
1391f8f7730SSimon Glass };
1401f8f7730SSimon Glass 
1411f8f7730SSimon Glass static const struct udevice_id rockchip_gpio_ids[] = {
1421f8f7730SSimon Glass 	{ .compatible = "rockchip,gpio-bank" },
1431f8f7730SSimon Glass 	{ }
1441f8f7730SSimon Glass };
1451f8f7730SSimon Glass 
1461f8f7730SSimon Glass U_BOOT_DRIVER(gpio_rockchip) = {
1471f8f7730SSimon Glass 	.name	= "gpio_rockchip",
1481f8f7730SSimon Glass 	.id	= UCLASS_GPIO,
1491f8f7730SSimon Glass 	.of_match = rockchip_gpio_ids,
1501f8f7730SSimon Glass 	.ops	= &gpio_rockchip_ops,
1511f8f7730SSimon Glass 	.priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv),
1521f8f7730SSimon Glass 	.probe	= rockchip_gpio_probe,
1531f8f7730SSimon Glass };
154