blob: babf1bccc9697596522dc93d8906ff0454cfebf5 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Beniamino Galvani2176d732016-08-16 11:49:49 +02002/*
3 * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
Beniamino Galvani2176d732016-08-16 11:49:49 +02004 */
5
Simon Glass11c89f32017-05-17 17:18:03 -06006#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -06007#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -07008#include <malloc.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06009#include <asm/global_data.h>
Beniamino Galvani5aeb1352017-07-10 00:30:04 +020010#include <dm/device-internal.h>
Simon Glass9bc15642020-02-03 07:36:16 -070011#include <dm/device_compat.h>
Beniamino Galvani5aeb1352017-07-10 00:30:04 +020012#include <dm/lists.h>
Beniamino Galvani2176d732016-08-16 11:49:49 +020013#include <dm/pinctrl.h>
14#include <fdt_support.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060015#include <linux/bitops.h>
Beniamino Galvani2176d732016-08-16 11:49:49 +020016#include <linux/err.h>
17#include <linux/io.h>
Simon Glass2dc9c342020-05-10 11:40:01 -060018#include <linux/libfdt.h>
Beniamino Galvani2176d732016-08-16 11:49:49 +020019#include <linux/sizes.h>
Beniamino Galvani5aeb1352017-07-10 00:30:04 +020020#include <asm/gpio.h>
Beniamino Galvani2176d732016-08-16 11:49:49 +020021
22#include "pinctrl-meson.h"
23
24DECLARE_GLOBAL_DATA_PTR;
25
26static const char *meson_pinctrl_dummy_name = "_dummy";
27
Neil Armstronga5ea1572019-06-04 11:04:52 +020028static char pin_name[PINNAME_SIZE];
29
Jerome Brunet707bff42018-10-05 09:35:26 +020030int meson_pinctrl_get_groups_count(struct udevice *dev)
Beniamino Galvani2176d732016-08-16 11:49:49 +020031{
32 struct meson_pinctrl *priv = dev_get_priv(dev);
33
34 return priv->data->num_groups;
35}
36
Jerome Brunet707bff42018-10-05 09:35:26 +020037const char *meson_pinctrl_get_group_name(struct udevice *dev,
38 unsigned int selector)
Beniamino Galvani2176d732016-08-16 11:49:49 +020039{
40 struct meson_pinctrl *priv = dev_get_priv(dev);
41
42 if (!priv->data->groups[selector].name)
43 return meson_pinctrl_dummy_name;
44
45 return priv->data->groups[selector].name;
46}
47
Neil Armstronga5ea1572019-06-04 11:04:52 +020048int meson_pinctrl_get_pins_count(struct udevice *dev)
49{
50 struct meson_pinctrl *priv = dev_get_priv(dev);
51
52 return priv->data->num_pins;
53}
54
55const char *meson_pinctrl_get_pin_name(struct udevice *dev,
56 unsigned int selector)
57{
58 struct meson_pinctrl *priv = dev_get_priv(dev);
59
60 if (selector > priv->data->num_pins ||
61 selector > priv->data->funcs[0].num_groups)
62 snprintf(pin_name, PINNAME_SIZE, "Error");
63 else
64 snprintf(pin_name, PINNAME_SIZE, "%s",
65 priv->data->funcs[0].groups[selector]);
66
67 return pin_name;
68}
69
Jerome Brunet707bff42018-10-05 09:35:26 +020070int meson_pinmux_get_functions_count(struct udevice *dev)
Beniamino Galvani2176d732016-08-16 11:49:49 +020071{
72 struct meson_pinctrl *priv = dev_get_priv(dev);
73
74 return priv->data->num_funcs;
75}
76
Jerome Brunet707bff42018-10-05 09:35:26 +020077const char *meson_pinmux_get_function_name(struct udevice *dev,
78 unsigned int selector)
Beniamino Galvani2176d732016-08-16 11:49:49 +020079{
80 struct meson_pinctrl *priv = dev_get_priv(dev);
81
82 return priv->data->funcs[selector].name;
83}
84
Beniamino Galvani5aeb1352017-07-10 00:30:04 +020085static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset,
86 enum meson_reg_type reg_type,
87 unsigned int *reg, unsigned int *bit)
88{
Jerome Brunet87021992019-01-04 15:44:34 +010089 struct meson_pinctrl *priv = dev_get_priv(dev);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +020090 struct meson_bank *bank = NULL;
91 struct meson_reg_desc *desc;
92 unsigned int pin;
93 int i;
94
95 pin = priv->data->pin_base + offset;
96
97 for (i = 0; i < priv->data->num_banks; i++) {
98 if (pin >= priv->data->banks[i].first &&
99 pin <= priv->data->banks[i].last) {
100 bank = &priv->data->banks[i];
101 break;
102 }
103 }
104
105 if (!bank)
106 return -EINVAL;
107
108 desc = &bank->regs[reg_type];
109 *reg = desc->reg * 4;
110 *bit = desc->bit + pin - bank->first;
111
112 return 0;
113}
114
Jerome Brunet707bff42018-10-05 09:35:26 +0200115int meson_gpio_get(struct udevice *dev, unsigned int offset)
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200116{
117 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
118 unsigned int reg, bit;
119 int ret;
120
Jerome Brunet87021992019-01-04 15:44:34 +0100121 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_IN, &reg,
122 &bit);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200123 if (ret)
124 return ret;
125
126 return !!(readl(priv->reg_gpio + reg) & BIT(bit));
127}
128
Jerome Brunet707bff42018-10-05 09:35:26 +0200129int meson_gpio_set(struct udevice *dev, unsigned int offset, int value)
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200130{
131 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
132 unsigned int reg, bit;
133 int ret;
134
Jerome Brunet87021992019-01-04 15:44:34 +0100135 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, &reg,
136 &bit);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200137 if (ret)
138 return ret;
139
140 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
141
142 return 0;
143}
144
Jerome Brunet707bff42018-10-05 09:35:26 +0200145int meson_gpio_get_direction(struct udevice *dev, unsigned int offset)
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200146{
147 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
148 unsigned int reg, bit, val;
149 int ret;
150
Jerome Brunet87021992019-01-04 15:44:34 +0100151 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
152 &bit);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200153 if (ret)
154 return ret;
155
156 val = readl(priv->reg_gpio + reg);
157
158 return (val & BIT(bit)) ? GPIOF_INPUT : GPIOF_OUTPUT;
159}
160
Jerome Brunet707bff42018-10-05 09:35:26 +0200161int meson_gpio_direction_input(struct udevice *dev, unsigned int offset)
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200162{
163 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
164 unsigned int reg, bit;
165 int ret;
166
Jerome Brunet87021992019-01-04 15:44:34 +0100167 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
168 &bit);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200169 if (ret)
170 return ret;
171
Carlo Caioneb3805702018-12-03 18:00:42 +0000172 setbits_le32(priv->reg_gpio + reg, BIT(bit));
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200173
174 return 0;
175}
176
Jerome Brunet707bff42018-10-05 09:35:26 +0200177int meson_gpio_direction_output(struct udevice *dev,
178 unsigned int offset, int value)
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200179{
180 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
181 unsigned int reg, bit;
182 int ret;
183
Jerome Brunet87021992019-01-04 15:44:34 +0100184 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, &reg,
185 &bit);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200186 if (ret)
187 return ret;
188
Carlo Caioneb3805702018-12-03 18:00:42 +0000189 clrbits_le32(priv->reg_gpio + reg, BIT(bit));
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200190
Jerome Brunet87021992019-01-04 15:44:34 +0100191 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, &reg,
192 &bit);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200193 if (ret)
194 return ret;
195
196 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
197
198 return 0;
199}
200
Jerome Brunet87021992019-01-04 15:44:34 +0100201static int meson_pinconf_bias_set(struct udevice *dev, unsigned int pin,
202 unsigned int param)
203{
204 struct meson_pinctrl *priv = dev_get_priv(dev);
205 unsigned int offset = pin - priv->data->pin_base;
206 unsigned int reg, bit;
207 int ret;
208
209 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULLEN, &reg, &bit);
210 if (ret)
211 return ret;
212
213 if (param == PIN_CONFIG_BIAS_DISABLE) {
214 clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 0);
215 return 0;
216 }
217
218 /* othewise, enable the bias and select level */
Neil Armstrongcf1b5692020-12-14 19:39:07 +0100219 clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), BIT(bit));
Jerome Brunet87021992019-01-04 15:44:34 +0100220 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULL, &reg, &bit);
221 if (ret)
222 return ret;
223
224 clrsetbits_le32(priv->reg_pull + reg, BIT(bit),
Neil Armstrongcf1b5692020-12-14 19:39:07 +0100225 (param == PIN_CONFIG_BIAS_PULL_UP ? BIT(bit) : 0));
Jerome Brunet87021992019-01-04 15:44:34 +0100226
227 return 0;
228}
229
Guillaume La Roque30767352019-06-04 13:53:07 +0200230static int meson_pinconf_drive_strength_set(struct udevice *dev,
231 unsigned int pin,
232 unsigned int drive_strength_ua)
233{
234 struct meson_pinctrl *priv = dev_get_priv(dev);
235 unsigned int offset = pin - priv->data->pin_base;
236 unsigned int reg, bit;
237 unsigned int ds_val;
238 int ret;
239
240 if (!priv->reg_ds) {
241 dev_err(dev, "drive-strength-microamp not supported\n");
242 return -ENOTSUPP;
243 }
244
245 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DS, &reg, &bit);
246 if (ret)
247 return ret;
248
249 bit = bit << 1;
250
251 if (drive_strength_ua <= 500) {
252 ds_val = MESON_PINCONF_DRV_500UA;
253 } else if (drive_strength_ua <= 2500) {
254 ds_val = MESON_PINCONF_DRV_2500UA;
255 } else if (drive_strength_ua <= 3000) {
256 ds_val = MESON_PINCONF_DRV_3000UA;
257 } else if (drive_strength_ua <= 4000) {
258 ds_val = MESON_PINCONF_DRV_4000UA;
259 } else {
260 dev_warn(dev,
261 "pin %u: invalid drive-strength-microamp : %d , default to 4mA\n",
262 pin, drive_strength_ua);
263 ds_val = MESON_PINCONF_DRV_4000UA;
264 }
265
266 clrsetbits_le32(priv->reg_ds + reg, 0x3 << bit, ds_val << bit);
267
268 return 0;
269}
270
Jerome Brunet87021992019-01-04 15:44:34 +0100271int meson_pinconf_set(struct udevice *dev, unsigned int pin,
272 unsigned int param, unsigned int arg)
273{
274 int ret;
275
276 switch (param) {
277 case PIN_CONFIG_BIAS_DISABLE:
278 case PIN_CONFIG_BIAS_PULL_UP:
279 case PIN_CONFIG_BIAS_PULL_DOWN:
280 ret = meson_pinconf_bias_set(dev, pin, param);
281 break;
Guillaume La Roque30767352019-06-04 13:53:07 +0200282 case PIN_CONFIG_DRIVE_STRENGTH_UA:
283 ret = meson_pinconf_drive_strength_set(dev, pin, arg);
284 break;
Jerome Brunet87021992019-01-04 15:44:34 +0100285 default:
286 dev_err(dev, "unsupported configuration parameter %u\n", param);
287 return -EINVAL;
288 }
289
290 return ret;
291}
292
293int meson_pinconf_group_set(struct udevice *dev,
294 unsigned int group_selector,
295 unsigned int param, unsigned int arg)
296{
297 struct meson_pinctrl *priv = dev_get_priv(dev);
298 struct meson_pmx_group *grp = &priv->data->groups[group_selector];
299 int i, ret;
300
301 for (i = 0; i < grp->num_pins; i++) {
302 ret = meson_pinconf_set(dev, grp->pins[i], param, arg);
303 if (ret)
304 return ret;
305 }
306
307 return 0;
308}
309
Jerome Brunet707bff42018-10-05 09:35:26 +0200310int meson_gpio_probe(struct udevice *dev)
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200311{
312 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
313 struct gpio_dev_priv *uc_priv;
314
315 uc_priv = dev_get_uclass_priv(dev);
316 uc_priv->bank_name = priv->data->name;
317 uc_priv->gpio_count = priv->data->num_pins;
318
319 return 0;
320}
321
Beniamino Galvani2176d732016-08-16 11:49:49 +0200322static fdt_addr_t parse_address(int offset, const char *name, int na, int ns)
323{
324 int index, len = 0;
325 const fdt32_t *reg;
326
Simon Glassb0ea7402016-10-02 17:59:28 -0600327 index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names", name);
Beniamino Galvani2176d732016-08-16 11:49:49 +0200328 if (index < 0)
329 return FDT_ADDR_T_NONE;
330
331 reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
332 if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns))))
333 return FDT_ADDR_T_NONE;
334
335 reg += index * (na + ns);
336
337 return fdt_translate_address((void *)gd->fdt_blob, offset, reg);
338}
339
340int meson_pinctrl_probe(struct udevice *dev)
341{
342 struct meson_pinctrl *priv = dev_get_priv(dev);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200343 struct uclass_driver *drv;
344 struct udevice *gpio_dev;
Beniamino Galvani2176d732016-08-16 11:49:49 +0200345 fdt_addr_t addr;
346 int node, gpio = -1, len;
347 int na, ns;
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200348 char *name;
Beniamino Galvani2176d732016-08-16 11:49:49 +0200349
Simon Glass6996c662020-11-28 17:50:03 -0700350 /* FIXME: Should use livetree */
Simon Glassdd79d6e2017-01-17 16:52:55 -0700351 na = fdt_address_cells(gd->fdt_blob, dev_of_offset(dev->parent));
Beniamino Galvani2176d732016-08-16 11:49:49 +0200352 if (na < 1) {
353 debug("bad #address-cells\n");
354 return -EINVAL;
355 }
356
Simon Glassdd79d6e2017-01-17 16:52:55 -0700357 ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
Beniamino Galvani2176d732016-08-16 11:49:49 +0200358 if (ns < 1) {
359 debug("bad #size-cells\n");
360 return -EINVAL;
361 }
362
Simon Glassdd79d6e2017-01-17 16:52:55 -0700363 fdt_for_each_subnode(node, gd->fdt_blob, dev_of_offset(dev)) {
Beniamino Galvani2176d732016-08-16 11:49:49 +0200364 if (fdt_getprop(gd->fdt_blob, node, "gpio-controller", &len)) {
365 gpio = node;
366 break;
367 }
368 }
369
370 if (!gpio) {
371 debug("gpio node not found\n");
372 return -EINVAL;
373 }
374
375 addr = parse_address(gpio, "mux", na, ns);
376 if (addr == FDT_ADDR_T_NONE) {
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200377 debug("mux address not found\n");
Beniamino Galvani2176d732016-08-16 11:49:49 +0200378 return -EINVAL;
379 }
Beniamino Galvani2176d732016-08-16 11:49:49 +0200380 priv->reg_mux = (void __iomem *)addr;
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200381
382 addr = parse_address(gpio, "gpio", na, ns);
383 if (addr == FDT_ADDR_T_NONE) {
384 debug("gpio address not found\n");
385 return -EINVAL;
386 }
387 priv->reg_gpio = (void __iomem *)addr;
Jerome Brunet87021992019-01-04 15:44:34 +0100388
389 addr = parse_address(gpio, "pull", na, ns);
Jerome Brunet0ff3cd02019-02-08 17:40:57 +0100390 /* Use gpio region if pull one is not present */
391 if (addr == FDT_ADDR_T_NONE)
392 priv->reg_pull = priv->reg_gpio;
393 else
394 priv->reg_pull = (void __iomem *)addr;
Jerome Brunet87021992019-01-04 15:44:34 +0100395
396 addr = parse_address(gpio, "pull-enable", na, ns);
397 /* Use pull region if pull-enable one is not present */
398 if (addr == FDT_ADDR_T_NONE)
399 priv->reg_pullen = priv->reg_pull;
400 else
401 priv->reg_pullen = (void __iomem *)addr;
402
Jerome Brunet0ff3cd02019-02-08 17:40:57 +0100403 addr = parse_address(gpio, "ds", na, ns);
404 /* Drive strength region is optional */
405 if (addr == FDT_ADDR_T_NONE)
406 priv->reg_ds = NULL;
407 else
408 priv->reg_ds = (void __iomem *)addr;
409
Beniamino Galvani2176d732016-08-16 11:49:49 +0200410 priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev);
411
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200412 /* Lookup GPIO driver */
413 drv = lists_uclass_lookup(UCLASS_GPIO);
414 if (!drv) {
415 puts("Cannot find GPIO driver\n");
416 return -ENOENT;
417 }
418
419 name = calloc(1, 32);
420 sprintf(name, "meson-gpio");
421
422 /* Create child device UCLASS_GPIO and bind it */
Simon Glass6996c662020-11-28 17:50:03 -0700423 device_bind(dev, priv->data->gpio_driver, name, NULL,
424 offset_to_ofnode(gpio), &gpio_dev);
Beniamino Galvani5aeb1352017-07-10 00:30:04 +0200425
Beniamino Galvani2176d732016-08-16 11:49:49 +0200426 return 0;
427}