blob: a860200dfb035392da545050fc7235d223f8c37d [file] [log] [blame]
Beniamino Galvani2176d732016-08-16 11:49:49 +02001/*
2 * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.h>
Simon Glass11c89f32017-05-17 17:18:03 -06008#include <dm.h>
Beniamino Galvani5aeb1352017-07-10 00:30:04 +02009#include <dm/device-internal.h>
10#include <dm/lists.h>
Beniamino Galvani2176d732016-08-16 11:49:49 +020011#include <dm/pinctrl.h>
12#include <fdt_support.h>
13#include <linux/err.h>
14#include <linux/io.h>
15#include <linux/sizes.h>
Beniamino Galvani5aeb1352017-07-10 00:30:04 +020016#include <asm/gpio.h>
Beniamino Galvani2176d732016-08-16 11:49:49 +020017
18#include "pinctrl-meson.h"
19
20DECLARE_GLOBAL_DATA_PTR;
21
22static const char *meson_pinctrl_dummy_name = "_dummy";
23
24static int meson_pinctrl_get_groups_count(struct udevice *dev)
25{
26 struct meson_pinctrl *priv = dev_get_priv(dev);
27
28 return priv->data->num_groups;
29}
30
31static const char *meson_pinctrl_get_group_name(struct udevice *dev,
32 unsigned selector)
33{
34 struct meson_pinctrl *priv = dev_get_priv(dev);
35
36 if (!priv->data->groups[selector].name)
37 return meson_pinctrl_dummy_name;
38
39 return priv->data->groups[selector].name;
40}
41
42static int meson_pinmux_get_functions_count(struct udevice *dev)
43{
44 struct meson_pinctrl *priv = dev_get_priv(dev);
45
46 return priv->data->num_funcs;
47}
48
49static const char *meson_pinmux_get_function_name(struct udevice *dev,
50 unsigned selector)
51{
52 struct meson_pinctrl *priv = dev_get_priv(dev);
53
54 return priv->data->funcs[selector].name;
55}
56
57static void meson_pinmux_disable_other_groups(struct meson_pinctrl *priv,
58 unsigned int pin, int sel_group)
59{
60 struct meson_pmx_group *group;
61 void __iomem *addr;
62 int i, j;
63
64 for (i = 0; i < priv->data->num_groups; i++) {
65 group = &priv->data->groups[i];
66 if (group->is_gpio || i == sel_group)
67 continue;
68
69 for (j = 0; j < group->num_pins; j++) {
70 if (group->pins[j] == pin) {
71 /* We have found a group using the pin */
72 debug("pinmux: disabling %s\n", group->name);
73 addr = priv->reg_mux + group->reg * 4;
74 writel(readl(addr) & ~BIT(group->bit), addr);
75 }
76 }
77 }
78}
79
80static int meson_pinmux_group_set(struct udevice *dev,
81 unsigned group_selector,
82 unsigned func_selector)
83{
84 struct meson_pinctrl *priv = dev_get_priv(dev);
85 const struct meson_pmx_group *group;
86 const struct meson_pmx_func *func;
87 void __iomem *addr;
88 int i;
89
90 group = &priv->data->groups[group_selector];
91 func = &priv->data->funcs[func_selector];
92
93 debug("pinmux: set group %s func %s\n", group->name, func->name);
94
95 /*
96 * Disable groups using the same pins.
97 * The selected group is not disabled to avoid glitches.
98 */
99 for (i = 0; i < group->num_pins; i++) {
100 meson_pinmux_disable_other_groups(priv,
101 group->pins[i],
102 group_selector);
103 }
104
105 /* Function 0 (GPIO) doesn't need any additional setting */
106 if (func_selector) {
107 addr = priv->reg_mux + group->reg * 4;
108 writel(readl(addr) | BIT(group->bit), addr);
109 }
110
111 return 0;
112}
113
114const struct pinctrl_ops meson_pinctrl_ops = {
115 .get_groups_count = meson_pinctrl_get_groups_count,
116 .get_group_name = meson_pinctrl_get_group_name,
117 .get_functions_count = meson_pinmux_get_functions_count,
118 .get_function_name = meson_pinmux_get_function_name,
119 .pinmux_group_set = meson_pinmux_group_set,
120 .set_state = pinctrl_generic_set_state,
121};
122
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200123static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset,
124 enum meson_reg_type reg_type,
125 unsigned int *reg, unsigned int *bit)
126{
127 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
128 struct meson_bank *bank = NULL;
129 struct meson_reg_desc *desc;
130 unsigned int pin;
131 int i;
132
133 pin = priv->data->pin_base + offset;
134
135 for (i = 0; i < priv->data->num_banks; i++) {
136 if (pin >= priv->data->banks[i].first &&
137 pin <= priv->data->banks[i].last) {
138 bank = &priv->data->banks[i];
139 break;
140 }
141 }
142
143 if (!bank)
144 return -EINVAL;
145
146 desc = &bank->regs[reg_type];
147 *reg = desc->reg * 4;
148 *bit = desc->bit + pin - bank->first;
149
150 return 0;
151}
152
153static int meson_gpio_get(struct udevice *dev, unsigned int offset)
154{
155 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
156 unsigned int reg, bit;
157 int ret;
158
159 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_IN, &reg, &bit);
160 if (ret)
161 return ret;
162
163 return !!(readl(priv->reg_gpio + reg) & BIT(bit));
164}
165
166static int meson_gpio_set(struct udevice *dev, unsigned int offset, int value)
167{
168 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
169 unsigned int reg, bit;
170 int ret;
171
172 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_OUT, &reg, &bit);
173 if (ret)
174 return ret;
175
176 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
177
178 return 0;
179}
180
181static int meson_gpio_get_direction(struct udevice *dev, unsigned int offset)
182{
183 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
184 unsigned int reg, bit, val;
185 int ret;
186
187 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, &reg, &bit);
188 if (ret)
189 return ret;
190
191 val = readl(priv->reg_gpio + reg);
192
193 return (val & BIT(bit)) ? GPIOF_INPUT : GPIOF_OUTPUT;
194}
195
196static int meson_gpio_direction_input(struct udevice *dev, unsigned int offset)
197{
198 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
199 unsigned int reg, bit;
200 int ret;
201
202 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, &reg, &bit);
203 if (ret)
204 return ret;
205
206 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), 1);
207
208 return 0;
209}
210
211static int meson_gpio_direction_output(struct udevice *dev,
212 unsigned int offset, int value)
213{
214 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
215 unsigned int reg, bit;
216 int ret;
217
218 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, &reg, &bit);
219 if (ret)
220 return ret;
221
222 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), 0);
223
224 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_OUT, &reg, &bit);
225 if (ret)
226 return ret;
227
228 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
229
230 return 0;
231}
232
233static int meson_gpio_probe(struct udevice *dev)
234{
235 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
236 struct gpio_dev_priv *uc_priv;
237
238 uc_priv = dev_get_uclass_priv(dev);
239 uc_priv->bank_name = priv->data->name;
240 uc_priv->gpio_count = priv->data->num_pins;
241
242 return 0;
243}
244
245static const struct dm_gpio_ops meson_gpio_ops = {
246 .set_value = meson_gpio_set,
247 .get_value = meson_gpio_get,
248 .get_function = meson_gpio_get_direction,
249 .direction_input = meson_gpio_direction_input,
250 .direction_output = meson_gpio_direction_output,
251};
252
253static struct driver meson_gpio_driver = {
254 .name = "meson-gpio",
255 .id = UCLASS_GPIO,
256 .probe = meson_gpio_probe,
257 .ops = &meson_gpio_ops,
258};
259
Beniamino Galvani2176d732016-08-16 11:49:49 +0200260static fdt_addr_t parse_address(int offset, const char *name, int na, int ns)
261{
262 int index, len = 0;
263 const fdt32_t *reg;
264
Simon Glassb0ea7402016-10-02 17:59:28 -0600265 index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names", name);
Beniamino Galvani2176d732016-08-16 11:49:49 +0200266 if (index < 0)
267 return FDT_ADDR_T_NONE;
268
269 reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
270 if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns))))
271 return FDT_ADDR_T_NONE;
272
273 reg += index * (na + ns);
274
275 return fdt_translate_address((void *)gd->fdt_blob, offset, reg);
276}
277
278int meson_pinctrl_probe(struct udevice *dev)
279{
280 struct meson_pinctrl *priv = dev_get_priv(dev);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200281 struct uclass_driver *drv;
282 struct udevice *gpio_dev;
Beniamino Galvani2176d732016-08-16 11:49:49 +0200283 fdt_addr_t addr;
284 int node, gpio = -1, len;
285 int na, ns;
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200286 char *name;
Beniamino Galvani2176d732016-08-16 11:49:49 +0200287
Simon Glassdd79d6e2017-01-17 16:52:55 -0700288 na = fdt_address_cells(gd->fdt_blob, dev_of_offset(dev->parent));
Beniamino Galvani2176d732016-08-16 11:49:49 +0200289 if (na < 1) {
290 debug("bad #address-cells\n");
291 return -EINVAL;
292 }
293
Simon Glassdd79d6e2017-01-17 16:52:55 -0700294 ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
Beniamino Galvani2176d732016-08-16 11:49:49 +0200295 if (ns < 1) {
296 debug("bad #size-cells\n");
297 return -EINVAL;
298 }
299
Simon Glassdd79d6e2017-01-17 16:52:55 -0700300 fdt_for_each_subnode(node, gd->fdt_blob, dev_of_offset(dev)) {
Beniamino Galvani2176d732016-08-16 11:49:49 +0200301 if (fdt_getprop(gd->fdt_blob, node, "gpio-controller", &len)) {
302 gpio = node;
303 break;
304 }
305 }
306
307 if (!gpio) {
308 debug("gpio node not found\n");
309 return -EINVAL;
310 }
311
312 addr = parse_address(gpio, "mux", na, ns);
313 if (addr == FDT_ADDR_T_NONE) {
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200314 debug("mux address not found\n");
Beniamino Galvani2176d732016-08-16 11:49:49 +0200315 return -EINVAL;
316 }
Beniamino Galvani2176d732016-08-16 11:49:49 +0200317 priv->reg_mux = (void __iomem *)addr;
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200318
319 addr = parse_address(gpio, "gpio", na, ns);
320 if (addr == FDT_ADDR_T_NONE) {
321 debug("gpio address not found\n");
322 return -EINVAL;
323 }
324 priv->reg_gpio = (void __iomem *)addr;
Beniamino Galvani2176d732016-08-16 11:49:49 +0200325 priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev);
326
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200327 /* Lookup GPIO driver */
328 drv = lists_uclass_lookup(UCLASS_GPIO);
329 if (!drv) {
330 puts("Cannot find GPIO driver\n");
331 return -ENOENT;
332 }
333
334 name = calloc(1, 32);
335 sprintf(name, "meson-gpio");
336
337 /* Create child device UCLASS_GPIO and bind it */
338 device_bind(dev, &meson_gpio_driver, name, NULL, gpio, &gpio_dev);
339 dev_set_of_offset(gpio_dev, gpio);
340
Beniamino Galvani2176d732016-08-16 11:49:49 +0200341 return 0;
342}