]> git.sur5r.net Git - u-boot/blob - drivers/gpio/tegra186_gpio.c
Merge branch 'master' of git://git.denx.de/u-boot-sunxi
[u-boot] / drivers / gpio / tegra186_gpio.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2010-2016, NVIDIA CORPORATION.
4  * (based on tegra_gpio.c)
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <malloc.h>
10 #include <errno.h>
11 #include <fdtdec.h>
12 #include <asm/io.h>
13 #include <asm/bitops.h>
14 #include <asm/gpio.h>
15 #include <dm/device-internal.h>
16 #include <dt-bindings/gpio/gpio.h>
17 #include "tegra186_gpio_priv.h"
18
19 struct tegra186_gpio_port_data {
20         const char *name;
21         uint32_t offset;
22 };
23
24 struct tegra186_gpio_ctlr_data {
25         const struct tegra186_gpio_port_data *ports;
26         uint32_t port_count;
27 };
28
29 struct tegra186_gpio_platdata {
30         const char *name;
31         uint32_t *regs;
32 };
33
34 static uint32_t *tegra186_gpio_reg(struct udevice *dev, uint32_t reg,
35                                    uint32_t gpio)
36 {
37         struct tegra186_gpio_platdata *plat = dev->platdata;
38         uint32_t index = (reg + (gpio * TEGRA186_GPIO_PER_GPIO_STRIDE)) / 4;
39
40         return &(plat->regs[index]);
41 }
42
43 static int tegra186_gpio_set_out(struct udevice *dev, unsigned offset,
44                                  bool output)
45 {
46         uint32_t *reg;
47         uint32_t rval;
48
49         reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_CONTROL, offset);
50         rval = readl(reg);
51         if (output)
52                 rval &= ~TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
53         else
54                 rval |= TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
55         writel(rval, reg);
56
57         reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
58         rval = readl(reg);
59         if (output)
60                 rval |= TEGRA186_GPIO_ENABLE_CONFIG_OUT;
61         else
62                 rval &= ~TEGRA186_GPIO_ENABLE_CONFIG_OUT;
63         rval |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
64         writel(rval, reg);
65
66         return 0;
67 }
68
69 static int tegra186_gpio_set_val(struct udevice *dev, unsigned offset, bool val)
70 {
71         uint32_t *reg;
72         uint32_t rval;
73
74         reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE, offset);
75         rval = readl(reg);
76         if (val)
77                 rval |= TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
78         else
79                 rval &= ~TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
80         writel(rval, reg);
81
82         return 0;
83 }
84
85 static int tegra186_gpio_direction_input(struct udevice *dev, unsigned offset)
86 {
87         return tegra186_gpio_set_out(dev, offset, false);
88 }
89
90 static int tegra186_gpio_direction_output(struct udevice *dev, unsigned offset,
91                                        int value)
92 {
93         int ret;
94
95         ret = tegra186_gpio_set_val(dev, offset, value != 0);
96         if (ret)
97                 return ret;
98         return tegra186_gpio_set_out(dev, offset, true);
99 }
100
101 static int tegra186_gpio_get_value(struct udevice *dev, unsigned offset)
102 {
103         uint32_t *reg;
104         uint32_t rval;
105
106         reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
107         rval = readl(reg);
108
109         if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
110                 reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_OUTPUT_VALUE,
111                                         offset);
112         else
113                 reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_INPUT, offset);
114
115         rval = readl(reg);
116         return !!rval;
117 }
118
119 static int tegra186_gpio_set_value(struct udevice *dev, unsigned offset,
120                                    int value)
121 {
122         return tegra186_gpio_set_val(dev, offset, value != 0);
123 }
124
125 static int tegra186_gpio_get_function(struct udevice *dev, unsigned offset)
126 {
127         uint32_t *reg;
128         uint32_t rval;
129
130         reg = tegra186_gpio_reg(dev, TEGRA186_GPIO_ENABLE_CONFIG, offset);
131         rval = readl(reg);
132         if (rval & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
133                 return GPIOF_OUTPUT;
134         else
135                 return GPIOF_INPUT;
136 }
137
138 static int tegra186_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
139                                struct ofnode_phandle_args *args)
140 {
141         int gpio, port, ret;
142
143         gpio = args->args[0];
144         port = gpio / TEGRA186_GPIO_PER_GPIO_COUNT;
145         ret = device_get_child(dev, port, &desc->dev);
146         if (ret)
147                 return ret;
148         desc->offset = gpio % TEGRA186_GPIO_PER_GPIO_COUNT;
149         desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
150
151         return 0;
152 }
153
154 static const struct dm_gpio_ops tegra186_gpio_ops = {
155         .direction_input        = tegra186_gpio_direction_input,
156         .direction_output       = tegra186_gpio_direction_output,
157         .get_value              = tegra186_gpio_get_value,
158         .set_value              = tegra186_gpio_set_value,
159         .get_function           = tegra186_gpio_get_function,
160         .xlate                  = tegra186_gpio_xlate,
161 };
162
163 /**
164  * We have a top-level GPIO device with no actual GPIOs. It has a child device
165  * for each port within the controller.
166  */
167 static int tegra186_gpio_bind(struct udevice *parent)
168 {
169         struct tegra186_gpio_platdata *parent_plat = parent->platdata;
170         struct tegra186_gpio_ctlr_data *ctlr_data =
171                 (struct tegra186_gpio_ctlr_data *)dev_get_driver_data(parent);
172         uint32_t *regs;
173         int port, ret;
174
175         /* If this is a child device, there is nothing to do here */
176         if (parent_plat)
177                 return 0;
178
179         regs = (uint32_t *)devfdt_get_addr_name(parent, "gpio");
180         if (regs == (uint32_t *)FDT_ADDR_T_NONE)
181                 return -EINVAL;
182
183         for (port = 0; port < ctlr_data->port_count; port++) {
184                 struct tegra186_gpio_platdata *plat;
185                 struct udevice *dev;
186
187                 plat = calloc(1, sizeof(*plat));
188                 if (!plat)
189                         return -ENOMEM;
190                 plat->name = ctlr_data->ports[port].name;
191                 plat->regs = &(regs[ctlr_data->ports[port].offset / 4]);
192
193                 ret = device_bind(parent, parent->driver, plat->name, plat,
194                                   -1, &dev);
195                 if (ret)
196                         return ret;
197                 dev_set_of_offset(dev, dev_of_offset(parent));
198         }
199
200         return 0;
201 }
202
203 static int tegra186_gpio_probe(struct udevice *dev)
204 {
205         struct tegra186_gpio_platdata *plat = dev->platdata;
206         struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
207
208         /* Only child devices have ports */
209         if (!plat)
210                 return 0;
211
212         uc_priv->gpio_count = TEGRA186_GPIO_PER_GPIO_COUNT;
213         uc_priv->bank_name = plat->name;
214
215         return 0;
216 }
217
218 static const struct tegra186_gpio_port_data tegra186_gpio_main_ports[] = {
219         {"A",  0x2000},
220         {"B",  0x3000},
221         {"C",  0x3200},
222         {"D",  0x3400},
223         {"E",  0x2200},
224         {"F",  0x2400},
225         {"G",  0x4200},
226         {"H",  0x1000},
227         {"I",  0x0800},
228         {"J",  0x5000},
229         {"K",  0x5200},
230         {"L",  0x1200},
231         {"M",  0x5600},
232         {"N",  0x0000},
233         {"O",  0x0200},
234         {"P",  0x4000},
235         {"Q",  0x0400},
236         {"R",  0x0a00},
237         {"T",  0x0600},
238         {"X",  0x1400},
239         {"Y",  0x1600},
240         {"BB", 0x2600},
241         {"CC", 0x5400},
242 };
243
244 static const struct tegra186_gpio_ctlr_data tegra186_gpio_main_data = {
245         .ports = tegra186_gpio_main_ports,
246         .port_count = ARRAY_SIZE(tegra186_gpio_main_ports),
247 };
248
249 static const struct tegra186_gpio_port_data tegra186_gpio_aon_ports[] = {
250         {"S",  0x0200},
251         {"U",  0x0400},
252         {"V",  0x0800},
253         {"W",  0x0a00},
254         {"Z",  0x0e00},
255         {"AA", 0x0c00},
256         {"EE", 0x0600},
257         {"FF", 0x0000},
258 };
259
260 static const struct tegra186_gpio_ctlr_data tegra186_gpio_aon_data = {
261         .ports = tegra186_gpio_aon_ports,
262         .port_count = ARRAY_SIZE(tegra186_gpio_aon_ports),
263 };
264
265 static const struct udevice_id tegra186_gpio_ids[] = {
266         {
267                 .compatible = "nvidia,tegra186-gpio",
268                 .data = (ulong)&tegra186_gpio_main_data,
269         },
270         {
271                 .compatible = "nvidia,tegra186-gpio-aon",
272                 .data = (ulong)&tegra186_gpio_aon_data,
273         },
274         { }
275 };
276
277 U_BOOT_DRIVER(tegra186_gpio) = {
278         .name = "tegra186_gpio",
279         .id = UCLASS_GPIO,
280         .of_match = tegra186_gpio_ids,
281         .bind = tegra186_gpio_bind,
282         .probe = tegra186_gpio_probe,
283         .ops = &tegra186_gpio_ops,
284         .flags = DM_FLAG_PRE_RELOC,
285 };