xref: /openbmc/u-boot/drivers/gpio/gpio-uniphier.c (revision b9a66b63)
1*b9a66b63SMasahiro Yamada /*
2*b9a66b63SMasahiro Yamada  * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com>
3*b9a66b63SMasahiro Yamada  *
4*b9a66b63SMasahiro Yamada  * SPDX-License-Identifier:	GPL-2.0+
5*b9a66b63SMasahiro Yamada  */
6*b9a66b63SMasahiro Yamada 
7*b9a66b63SMasahiro Yamada #include <common.h>
8*b9a66b63SMasahiro Yamada #include <dm/device.h>
9*b9a66b63SMasahiro Yamada #include <mapmem.h>
10*b9a66b63SMasahiro Yamada #include <linux/bitops.h>
11*b9a66b63SMasahiro Yamada #include <linux/io.h>
12*b9a66b63SMasahiro Yamada #include <asm/errno.h>
13*b9a66b63SMasahiro Yamada #include <asm/gpio.h>
14*b9a66b63SMasahiro Yamada 
15*b9a66b63SMasahiro Yamada #define UNIPHIER_GPIO_PORTS_PER_BANK	8
16*b9a66b63SMasahiro Yamada 
17*b9a66b63SMasahiro Yamada #define UNIPHIER_GPIO_REG_DATA		0	/* data */
18*b9a66b63SMasahiro Yamada #define UNIPHIER_GPIO_REG_DIR		4	/* direction (1:in, 0:out) */
19*b9a66b63SMasahiro Yamada 
20*b9a66b63SMasahiro Yamada struct uniphier_gpio_priv {
21*b9a66b63SMasahiro Yamada 	void __iomem *base;
22*b9a66b63SMasahiro Yamada 	char bank_name[16];
23*b9a66b63SMasahiro Yamada };
24*b9a66b63SMasahiro Yamada 
25*b9a66b63SMasahiro Yamada static void uniphier_gpio_offset_write(struct udevice *dev, unsigned offset,
26*b9a66b63SMasahiro Yamada 				       unsigned reg, int value)
27*b9a66b63SMasahiro Yamada {
28*b9a66b63SMasahiro Yamada 	struct uniphier_gpio_priv *priv = dev_get_priv(dev);
29*b9a66b63SMasahiro Yamada 	u32 tmp;
30*b9a66b63SMasahiro Yamada 
31*b9a66b63SMasahiro Yamada 	tmp = readl(priv->base + reg);
32*b9a66b63SMasahiro Yamada 	if (value)
33*b9a66b63SMasahiro Yamada 		tmp |= BIT(offset);
34*b9a66b63SMasahiro Yamada 	else
35*b9a66b63SMasahiro Yamada 		tmp &= ~BIT(offset);
36*b9a66b63SMasahiro Yamada 	writel(tmp, priv->base + reg);
37*b9a66b63SMasahiro Yamada }
38*b9a66b63SMasahiro Yamada 
39*b9a66b63SMasahiro Yamada static int uniphier_gpio_offset_read(struct udevice *dev, unsigned offset,
40*b9a66b63SMasahiro Yamada 				     unsigned reg)
41*b9a66b63SMasahiro Yamada {
42*b9a66b63SMasahiro Yamada 	struct uniphier_gpio_priv *priv = dev_get_priv(dev);
43*b9a66b63SMasahiro Yamada 
44*b9a66b63SMasahiro Yamada 	return !!(readl(priv->base + reg) & BIT(offset));
45*b9a66b63SMasahiro Yamada }
46*b9a66b63SMasahiro Yamada 
47*b9a66b63SMasahiro Yamada static int uniphier_gpio_direction_input(struct udevice *dev, unsigned offset)
48*b9a66b63SMasahiro Yamada {
49*b9a66b63SMasahiro Yamada 	uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DIR, 1);
50*b9a66b63SMasahiro Yamada 
51*b9a66b63SMasahiro Yamada 	return 0;
52*b9a66b63SMasahiro Yamada }
53*b9a66b63SMasahiro Yamada 
54*b9a66b63SMasahiro Yamada static int uniphier_gpio_direction_output(struct udevice *dev, unsigned offset,
55*b9a66b63SMasahiro Yamada 					  int value)
56*b9a66b63SMasahiro Yamada {
57*b9a66b63SMasahiro Yamada 	uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DATA, value);
58*b9a66b63SMasahiro Yamada 	uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DIR, 0);
59*b9a66b63SMasahiro Yamada 
60*b9a66b63SMasahiro Yamada 	return 0;
61*b9a66b63SMasahiro Yamada }
62*b9a66b63SMasahiro Yamada 
63*b9a66b63SMasahiro Yamada static int uniphier_gpio_get_value(struct udevice *dev, unsigned offset)
64*b9a66b63SMasahiro Yamada {
65*b9a66b63SMasahiro Yamada 	return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_REG_DATA);
66*b9a66b63SMasahiro Yamada }
67*b9a66b63SMasahiro Yamada 
68*b9a66b63SMasahiro Yamada static int uniphier_gpio_set_value(struct udevice *dev, unsigned offset,
69*b9a66b63SMasahiro Yamada 				   int value)
70*b9a66b63SMasahiro Yamada {
71*b9a66b63SMasahiro Yamada 	uniphier_gpio_offset_write(dev, offset, UNIPHIER_GPIO_REG_DATA, value);
72*b9a66b63SMasahiro Yamada 
73*b9a66b63SMasahiro Yamada 	return 0;
74*b9a66b63SMasahiro Yamada }
75*b9a66b63SMasahiro Yamada 
76*b9a66b63SMasahiro Yamada static int uniphier_gpio_get_function(struct udevice *dev, unsigned offset)
77*b9a66b63SMasahiro Yamada {
78*b9a66b63SMasahiro Yamada 	return uniphier_gpio_offset_read(dev, offset, UNIPHIER_GPIO_REG_DIR) ?
79*b9a66b63SMasahiro Yamada 						GPIOF_INPUT : GPIOF_OUTPUT;
80*b9a66b63SMasahiro Yamada }
81*b9a66b63SMasahiro Yamada 
82*b9a66b63SMasahiro Yamada static const struct dm_gpio_ops uniphier_gpio_ops = {
83*b9a66b63SMasahiro Yamada 	.direction_input	= uniphier_gpio_direction_input,
84*b9a66b63SMasahiro Yamada 	.direction_output	= uniphier_gpio_direction_output,
85*b9a66b63SMasahiro Yamada 	.get_value		= uniphier_gpio_get_value,
86*b9a66b63SMasahiro Yamada 	.set_value		= uniphier_gpio_set_value,
87*b9a66b63SMasahiro Yamada 	.get_function		= uniphier_gpio_get_function,
88*b9a66b63SMasahiro Yamada };
89*b9a66b63SMasahiro Yamada 
90*b9a66b63SMasahiro Yamada static int uniphier_gpio_probe(struct udevice *dev)
91*b9a66b63SMasahiro Yamada {
92*b9a66b63SMasahiro Yamada 	struct uniphier_gpio_priv *priv = dev_get_priv(dev);
93*b9a66b63SMasahiro Yamada 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
94*b9a66b63SMasahiro Yamada 	DECLARE_GLOBAL_DATA_PTR;
95*b9a66b63SMasahiro Yamada 	fdt_addr_t addr;
96*b9a66b63SMasahiro Yamada 	fdt_size_t size;
97*b9a66b63SMasahiro Yamada 	unsigned int tmp;
98*b9a66b63SMasahiro Yamada 
99*b9a66b63SMasahiro Yamada 	addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg",
100*b9a66b63SMasahiro Yamada 				    &size);
101*b9a66b63SMasahiro Yamada 	if (addr == FDT_ADDR_T_NONE)
102*b9a66b63SMasahiro Yamada 		return -EINVAL;
103*b9a66b63SMasahiro Yamada 
104*b9a66b63SMasahiro Yamada 	priv->base = map_sysmem(addr, size);
105*b9a66b63SMasahiro Yamada 	if (!priv->base)
106*b9a66b63SMasahiro Yamada 		return -ENOMEM;
107*b9a66b63SMasahiro Yamada 
108*b9a66b63SMasahiro Yamada 	uc_priv->gpio_count = UNIPHIER_GPIO_PORTS_PER_BANK;
109*b9a66b63SMasahiro Yamada 
110*b9a66b63SMasahiro Yamada 	tmp = (addr & 0xfff);
111*b9a66b63SMasahiro Yamada 
112*b9a66b63SMasahiro Yamada 	/* Unfortunately, there is a register hole at offset 0x90-0x9f. */
113*b9a66b63SMasahiro Yamada 	if (tmp > 0x90)
114*b9a66b63SMasahiro Yamada 		tmp -= 0x10;
115*b9a66b63SMasahiro Yamada 
116*b9a66b63SMasahiro Yamada 	snprintf(priv->bank_name, sizeof(priv->bank_name) - 1,
117*b9a66b63SMasahiro Yamada 		 "port%d-", (tmp - 8) / 8);
118*b9a66b63SMasahiro Yamada 
119*b9a66b63SMasahiro Yamada 	uc_priv->bank_name = priv->bank_name;
120*b9a66b63SMasahiro Yamada 
121*b9a66b63SMasahiro Yamada 	return 0;
122*b9a66b63SMasahiro Yamada }
123*b9a66b63SMasahiro Yamada 
124*b9a66b63SMasahiro Yamada static int uniphier_gpio_remove(struct udevice *dev)
125*b9a66b63SMasahiro Yamada {
126*b9a66b63SMasahiro Yamada 	struct uniphier_gpio_priv *priv = dev_get_priv(dev);
127*b9a66b63SMasahiro Yamada 
128*b9a66b63SMasahiro Yamada 	unmap_sysmem(priv->base);
129*b9a66b63SMasahiro Yamada 
130*b9a66b63SMasahiro Yamada 	return 0;
131*b9a66b63SMasahiro Yamada }
132*b9a66b63SMasahiro Yamada 
133*b9a66b63SMasahiro Yamada /* .data = the number of GPIO banks */
134*b9a66b63SMasahiro Yamada static const struct udevice_id uniphier_gpio_match[] = {
135*b9a66b63SMasahiro Yamada 	{ .compatible = "socionext,uniphier-gpio" },
136*b9a66b63SMasahiro Yamada 	{ /* sentinel */ }
137*b9a66b63SMasahiro Yamada };
138*b9a66b63SMasahiro Yamada 
139*b9a66b63SMasahiro Yamada U_BOOT_DRIVER(uniphier_gpio) = {
140*b9a66b63SMasahiro Yamada 	.name	= "uniphier_gpio",
141*b9a66b63SMasahiro Yamada 	.id	= UCLASS_GPIO,
142*b9a66b63SMasahiro Yamada 	.of_match = uniphier_gpio_match,
143*b9a66b63SMasahiro Yamada 	.probe	= uniphier_gpio_probe,
144*b9a66b63SMasahiro Yamada 	.remove	= uniphier_gpio_remove,
145*b9a66b63SMasahiro Yamada 	.priv_auto_alloc_size = sizeof(struct uniphier_gpio_priv),
146*b9a66b63SMasahiro Yamada 	.ops	= &uniphier_gpio_ops,
147*b9a66b63SMasahiro Yamada };
148