xref: /openbmc/u-boot/drivers/gpio/rk_gpio.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
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>
111f8f7730SSimon Glass #include <dm.h>
1248647828SSimon Glass #include <syscon.h>
13*1221ce45SMasahiro Yamada #include <linux/errno.h>
141f8f7730SSimon Glass #include <asm/gpio.h>
151f8f7730SSimon Glass #include <asm/io.h>
1648647828SSimon Glass #include <asm/arch/clock.h>
1748647828SSimon Glass #include <dm/pinctrl.h>
1848647828SSimon Glass #include <dt-bindings/clock/rk3288-cru.h>
191f8f7730SSimon Glass 
201f8f7730SSimon Glass enum {
211f8f7730SSimon Glass 	ROCKCHIP_GPIOS_PER_BANK		= 32,
221f8f7730SSimon Glass };
231f8f7730SSimon Glass 
241f8f7730SSimon Glass #define OFFSET_TO_BIT(bit)	(1UL << (bit))
251f8f7730SSimon Glass 
261f8f7730SSimon Glass struct rockchip_gpio_priv {
271f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs;
2848647828SSimon Glass 	struct udevice *pinctrl;
2948647828SSimon Glass 	int bank;
301f8f7730SSimon Glass 	char name[2];
311f8f7730SSimon Glass };
321f8f7730SSimon Glass 
331f8f7730SSimon Glass static int rockchip_gpio_direction_input(struct udevice *dev, unsigned offset)
341f8f7730SSimon Glass {
351f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
361f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
371f8f7730SSimon Glass 
381f8f7730SSimon Glass 	clrbits_le32(&regs->swport_ddr, OFFSET_TO_BIT(offset));
391f8f7730SSimon Glass 
401f8f7730SSimon Glass 	return 0;
411f8f7730SSimon Glass }
421f8f7730SSimon Glass 
431f8f7730SSimon Glass static int rockchip_gpio_direction_output(struct udevice *dev, unsigned offset,
441f8f7730SSimon Glass 					  int value)
451f8f7730SSimon Glass {
461f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
471f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
481f8f7730SSimon Glass 	int mask = OFFSET_TO_BIT(offset);
491f8f7730SSimon Glass 
501f8f7730SSimon Glass 	clrsetbits_le32(&regs->swport_dr, mask, value ? mask : 0);
511f8f7730SSimon Glass 	setbits_le32(&regs->swport_ddr, mask);
521f8f7730SSimon Glass 
531f8f7730SSimon Glass 	return 0;
541f8f7730SSimon Glass }
551f8f7730SSimon Glass 
561f8f7730SSimon Glass static int rockchip_gpio_get_value(struct udevice *dev, unsigned offset)
571f8f7730SSimon Glass {
581f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
591f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
601f8f7730SSimon Glass 
617d0c2c3fSSimon Glass 	return readl(&regs->ext_port) & OFFSET_TO_BIT(offset) ? 1 : 0;
621f8f7730SSimon Glass }
631f8f7730SSimon Glass 
641f8f7730SSimon Glass static int rockchip_gpio_set_value(struct udevice *dev, unsigned offset,
651f8f7730SSimon Glass 				   int value)
661f8f7730SSimon Glass {
671f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
681f8f7730SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
691f8f7730SSimon Glass 	int mask = OFFSET_TO_BIT(offset);
701f8f7730SSimon Glass 
711f8f7730SSimon Glass 	clrsetbits_le32(&regs->swport_dr, mask, value ? mask : 0);
721f8f7730SSimon Glass 
731f8f7730SSimon Glass 	return 0;
741f8f7730SSimon Glass }
751f8f7730SSimon Glass 
761f8f7730SSimon Glass static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset)
771f8f7730SSimon Glass {
7848647828SSimon Glass #ifdef CONFIG_SPL_BUILD
7948647828SSimon Glass 	return -ENODATA;
8048647828SSimon Glass #else
8148647828SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
8248647828SSimon Glass 	struct rockchip_gpio_regs *regs = priv->regs;
8348647828SSimon Glass 	bool is_output;
8448647828SSimon Glass 	int ret;
8548647828SSimon Glass 
8648647828SSimon Glass 	ret = pinctrl_get_gpio_mux(priv->pinctrl, priv->bank, offset);
8748647828SSimon Glass 	if (ret)
8848647828SSimon Glass 		return ret;
8948647828SSimon Glass 
9048647828SSimon Glass 	/* If it's not 0, then it is not a GPIO */
9148647828SSimon Glass 	if (ret)
9248647828SSimon Glass 		return GPIOF_FUNC;
9348647828SSimon Glass 	is_output = readl(&regs->swport_ddr) & OFFSET_TO_BIT(offset);
9448647828SSimon Glass 
9548647828SSimon Glass 	return is_output ? GPIOF_OUTPUT : GPIOF_INPUT;
9648647828SSimon Glass #endif
971f8f7730SSimon Glass }
981f8f7730SSimon Glass 
991f8f7730SSimon Glass static int rockchip_gpio_probe(struct udevice *dev)
1001f8f7730SSimon Glass {
1011f8f7730SSimon Glass 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
1021f8f7730SSimon Glass 	struct rockchip_gpio_priv *priv = dev_get_priv(dev);
1031f8f7730SSimon Glass 	char *end;
10448647828SSimon Glass 	int ret;
1051f8f7730SSimon Glass 
10648647828SSimon Glass 	/* This only supports RK3288 at present */
1071f8f7730SSimon Glass 	priv->regs = (struct rockchip_gpio_regs *)dev_get_addr(dev);
1083f603cbbSSimon Glass 	ret = uclass_first_device_err(UCLASS_PINCTRL, &priv->pinctrl);
10948647828SSimon Glass 	if (ret)
11048647828SSimon Glass 		return ret;
11148647828SSimon Glass 
1121f8f7730SSimon Glass 	uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK;
1131f8f7730SSimon Glass 	end = strrchr(dev->name, '@');
11448647828SSimon Glass 	priv->bank = trailing_strtoln(dev->name, end);
11548647828SSimon Glass 	priv->name[0] = 'A' + priv->bank;
1161f8f7730SSimon Glass 	uc_priv->bank_name = priv->name;
1171f8f7730SSimon Glass 
1181f8f7730SSimon Glass 	return 0;
1191f8f7730SSimon Glass }
1201f8f7730SSimon Glass 
1211f8f7730SSimon Glass static const struct dm_gpio_ops gpio_rockchip_ops = {
1221f8f7730SSimon Glass 	.direction_input	= rockchip_gpio_direction_input,
1231f8f7730SSimon Glass 	.direction_output	= rockchip_gpio_direction_output,
1241f8f7730SSimon Glass 	.get_value		= rockchip_gpio_get_value,
1251f8f7730SSimon Glass 	.set_value		= rockchip_gpio_set_value,
1261f8f7730SSimon Glass 	.get_function		= rockchip_gpio_get_function,
1271f8f7730SSimon Glass };
1281f8f7730SSimon Glass 
1291f8f7730SSimon Glass static const struct udevice_id rockchip_gpio_ids[] = {
1301f8f7730SSimon Glass 	{ .compatible = "rockchip,gpio-bank" },
1311f8f7730SSimon Glass 	{ }
1321f8f7730SSimon Glass };
1331f8f7730SSimon Glass 
1341f8f7730SSimon Glass U_BOOT_DRIVER(gpio_rockchip) = {
1351f8f7730SSimon Glass 	.name	= "gpio_rockchip",
1361f8f7730SSimon Glass 	.id	= UCLASS_GPIO,
1371f8f7730SSimon Glass 	.of_match = rockchip_gpio_ids,
1381f8f7730SSimon Glass 	.ops	= &gpio_rockchip_ops,
1391f8f7730SSimon Glass 	.priv_auto_alloc_size = sizeof(struct rockchip_gpio_priv),
1401f8f7730SSimon Glass 	.probe	= rockchip_gpio_probe,
1411f8f7730SSimon Glass };
142