1*4751e559SStefan Roese // SPDX-License-Identifier: GPL-2.0+
2*4751e559SStefan Roese /*
3*4751e559SStefan Roese * Copyright (C) 2018 Stefan Roese <sr@denx.de>
4*4751e559SStefan Roese *
5*4751e559SStefan Roese * Based on the Linux driver version which is:
6*4751e559SStefan Roese * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
7*4751e559SStefan Roese * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
8*4751e559SStefan Roese */
9*4751e559SStefan Roese
10*4751e559SStefan Roese #include <common.h>
11*4751e559SStefan Roese #include <dm.h>
12*4751e559SStefan Roese #include <errno.h>
13*4751e559SStefan Roese #include <fdtdec.h>
14*4751e559SStefan Roese #include <malloc.h>
15*4751e559SStefan Roese #include <linux/io.h>
16*4751e559SStefan Roese #include <asm/io.h>
17*4751e559SStefan Roese #include <asm/gpio.h>
18*4751e559SStefan Roese #include <dm/device-internal.h>
19*4751e559SStefan Roese #include <dt-bindings/gpio/gpio.h>
20*4751e559SStefan Roese
21*4751e559SStefan Roese #define MTK_MAX_BANK 3
22*4751e559SStefan Roese #define MTK_BANK_WIDTH 32
23*4751e559SStefan Roese
24*4751e559SStefan Roese enum mediatek_gpio_reg {
25*4751e559SStefan Roese GPIO_REG_CTRL = 0,
26*4751e559SStefan Roese GPIO_REG_POL,
27*4751e559SStefan Roese GPIO_REG_DATA,
28*4751e559SStefan Roese GPIO_REG_DSET,
29*4751e559SStefan Roese GPIO_REG_DCLR,
30*4751e559SStefan Roese GPIO_REG_REDGE,
31*4751e559SStefan Roese GPIO_REG_FEDGE,
32*4751e559SStefan Roese GPIO_REG_HLVL,
33*4751e559SStefan Roese GPIO_REG_LLVL,
34*4751e559SStefan Roese GPIO_REG_STAT,
35*4751e559SStefan Roese GPIO_REG_EDGE,
36*4751e559SStefan Roese };
37*4751e559SStefan Roese
38*4751e559SStefan Roese static void __iomem *mediatek_gpio_membase;
39*4751e559SStefan Roese
40*4751e559SStefan Roese struct mediatek_gpio_platdata {
41*4751e559SStefan Roese char bank_name[3]; /* Name of bank, e.g. "PA", "PB" etc */
42*4751e559SStefan Roese int gpio_count;
43*4751e559SStefan Roese int bank;
44*4751e559SStefan Roese };
45*4751e559SStefan Roese
reg_offs(struct mediatek_gpio_platdata * plat,int reg)46*4751e559SStefan Roese static u32 reg_offs(struct mediatek_gpio_platdata *plat, int reg)
47*4751e559SStefan Roese {
48*4751e559SStefan Roese return (reg * 0x10) + (plat->bank * 0x4);
49*4751e559SStefan Roese }
50*4751e559SStefan Roese
mediatek_gpio_get_value(struct udevice * dev,unsigned int offset)51*4751e559SStefan Roese static int mediatek_gpio_get_value(struct udevice *dev, unsigned int offset)
52*4751e559SStefan Roese {
53*4751e559SStefan Roese struct mediatek_gpio_platdata *plat = dev_get_platdata(dev);
54*4751e559SStefan Roese
55*4751e559SStefan Roese return !!(ioread32(mediatek_gpio_membase +
56*4751e559SStefan Roese reg_offs(plat, GPIO_REG_DATA)) & BIT(offset));
57*4751e559SStefan Roese }
58*4751e559SStefan Roese
mediatek_gpio_set_value(struct udevice * dev,unsigned int offset,int value)59*4751e559SStefan Roese static int mediatek_gpio_set_value(struct udevice *dev, unsigned int offset,
60*4751e559SStefan Roese int value)
61*4751e559SStefan Roese {
62*4751e559SStefan Roese struct mediatek_gpio_platdata *plat = dev_get_platdata(dev);
63*4751e559SStefan Roese
64*4751e559SStefan Roese iowrite32(BIT(offset), mediatek_gpio_membase +
65*4751e559SStefan Roese reg_offs(plat, value ? GPIO_REG_DSET : GPIO_REG_DCLR));
66*4751e559SStefan Roese
67*4751e559SStefan Roese return 0;
68*4751e559SStefan Roese }
69*4751e559SStefan Roese
mediatek_gpio_direction_input(struct udevice * dev,unsigned int offset)70*4751e559SStefan Roese static int mediatek_gpio_direction_input(struct udevice *dev, unsigned int offset)
71*4751e559SStefan Roese {
72*4751e559SStefan Roese struct mediatek_gpio_platdata *plat = dev_get_platdata(dev);
73*4751e559SStefan Roese
74*4751e559SStefan Roese clrbits_le32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL),
75*4751e559SStefan Roese BIT(offset));
76*4751e559SStefan Roese
77*4751e559SStefan Roese return 0;
78*4751e559SStefan Roese }
79*4751e559SStefan Roese
mediatek_gpio_direction_output(struct udevice * dev,unsigned int offset,int value)80*4751e559SStefan Roese static int mediatek_gpio_direction_output(struct udevice *dev, unsigned int offset,
81*4751e559SStefan Roese int value)
82*4751e559SStefan Roese {
83*4751e559SStefan Roese struct mediatek_gpio_platdata *plat = dev_get_platdata(dev);
84*4751e559SStefan Roese
85*4751e559SStefan Roese setbits_le32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL),
86*4751e559SStefan Roese BIT(offset));
87*4751e559SStefan Roese mediatek_gpio_set_value(dev, offset, value);
88*4751e559SStefan Roese
89*4751e559SStefan Roese return 0;
90*4751e559SStefan Roese }
91*4751e559SStefan Roese
mediatek_gpio_get_function(struct udevice * dev,unsigned int offset)92*4751e559SStefan Roese static int mediatek_gpio_get_function(struct udevice *dev, unsigned int offset)
93*4751e559SStefan Roese {
94*4751e559SStefan Roese struct mediatek_gpio_platdata *plat = dev_get_platdata(dev);
95*4751e559SStefan Roese u32 t;
96*4751e559SStefan Roese
97*4751e559SStefan Roese t = ioread32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL));
98*4751e559SStefan Roese if (t & BIT(offset))
99*4751e559SStefan Roese return GPIOF_OUTPUT;
100*4751e559SStefan Roese
101*4751e559SStefan Roese return GPIOF_INPUT;
102*4751e559SStefan Roese }
103*4751e559SStefan Roese
104*4751e559SStefan Roese static const struct dm_gpio_ops gpio_mediatek_ops = {
105*4751e559SStefan Roese .direction_input = mediatek_gpio_direction_input,
106*4751e559SStefan Roese .direction_output = mediatek_gpio_direction_output,
107*4751e559SStefan Roese .get_value = mediatek_gpio_get_value,
108*4751e559SStefan Roese .set_value = mediatek_gpio_set_value,
109*4751e559SStefan Roese .get_function = mediatek_gpio_get_function,
110*4751e559SStefan Roese };
111*4751e559SStefan Roese
gpio_mediatek_probe(struct udevice * dev)112*4751e559SStefan Roese static int gpio_mediatek_probe(struct udevice *dev)
113*4751e559SStefan Roese {
114*4751e559SStefan Roese struct mediatek_gpio_platdata *plat = dev_get_platdata(dev);
115*4751e559SStefan Roese struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
116*4751e559SStefan Roese
117*4751e559SStefan Roese /* Tell the uclass how many GPIOs we have */
118*4751e559SStefan Roese if (plat) {
119*4751e559SStefan Roese uc_priv->gpio_count = plat->gpio_count;
120*4751e559SStefan Roese uc_priv->bank_name = plat->bank_name;
121*4751e559SStefan Roese }
122*4751e559SStefan Roese
123*4751e559SStefan Roese return 0;
124*4751e559SStefan Roese }
125*4751e559SStefan Roese
126*4751e559SStefan Roese /**
127*4751e559SStefan Roese * We have a top-level GPIO device with no actual GPIOs. It has a child
128*4751e559SStefan Roese * device for each Mediatek bank.
129*4751e559SStefan Roese */
gpio_mediatek_bind(struct udevice * parent)130*4751e559SStefan Roese static int gpio_mediatek_bind(struct udevice *parent)
131*4751e559SStefan Roese {
132*4751e559SStefan Roese struct mediatek_gpio_platdata *plat = parent->platdata;
133*4751e559SStefan Roese ofnode node;
134*4751e559SStefan Roese int bank = 0;
135*4751e559SStefan Roese int ret;
136*4751e559SStefan Roese
137*4751e559SStefan Roese /* If this is a child device, there is nothing to do here */
138*4751e559SStefan Roese if (plat)
139*4751e559SStefan Roese return 0;
140*4751e559SStefan Roese
141*4751e559SStefan Roese mediatek_gpio_membase = dev_remap_addr(parent);
142*4751e559SStefan Roese if (!mediatek_gpio_membase)
143*4751e559SStefan Roese return -EINVAL;
144*4751e559SStefan Roese
145*4751e559SStefan Roese for (node = dev_read_first_subnode(parent); ofnode_valid(node);
146*4751e559SStefan Roese node = dev_read_next_subnode(node)) {
147*4751e559SStefan Roese struct mediatek_gpio_platdata *plat;
148*4751e559SStefan Roese struct udevice *dev;
149*4751e559SStefan Roese
150*4751e559SStefan Roese plat = calloc(1, sizeof(*plat));
151*4751e559SStefan Roese if (!plat)
152*4751e559SStefan Roese return -ENOMEM;
153*4751e559SStefan Roese plat->bank_name[0] = 'P';
154*4751e559SStefan Roese plat->bank_name[1] = 'A' + bank;
155*4751e559SStefan Roese plat->bank_name[2] = '\0';
156*4751e559SStefan Roese plat->gpio_count = MTK_BANK_WIDTH;
157*4751e559SStefan Roese plat->bank = bank;
158*4751e559SStefan Roese
159*4751e559SStefan Roese ret = device_bind(parent, parent->driver,
160*4751e559SStefan Roese plat->bank_name, plat, -1, &dev);
161*4751e559SStefan Roese if (ret)
162*4751e559SStefan Roese return ret;
163*4751e559SStefan Roese
164*4751e559SStefan Roese dev->node = node;
165*4751e559SStefan Roese bank++;
166*4751e559SStefan Roese }
167*4751e559SStefan Roese
168*4751e559SStefan Roese return 0;
169*4751e559SStefan Roese }
170*4751e559SStefan Roese
171*4751e559SStefan Roese static const struct udevice_id mediatek_gpio_ids[] = {
172*4751e559SStefan Roese { .compatible = "mtk,mt7621-gpio" },
173*4751e559SStefan Roese { }
174*4751e559SStefan Roese };
175*4751e559SStefan Roese
176*4751e559SStefan Roese U_BOOT_DRIVER(gpio_mediatek) = {
177*4751e559SStefan Roese .name = "gpio_mediatek",
178*4751e559SStefan Roese .id = UCLASS_GPIO,
179*4751e559SStefan Roese .ops = &gpio_mediatek_ops,
180*4751e559SStefan Roese .of_match = mediatek_gpio_ids,
181*4751e559SStefan Roese .bind = gpio_mediatek_bind,
182*4751e559SStefan Roese .probe = gpio_mediatek_probe,
183*4751e559SStefan Roese };
184