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