blob: 26fb5d61d5df7ce9367cdcb345b728b99a552995 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Wenyou Yang309686c2016-07-20 17:16:27 +08002/*
3 * Atmel PIO4 pinctrl driver
4 *
5 * Copyright (C) 2016 Atmel Corporation
6 * Wenyou.Yang <wenyou.yang@atmel.com>
Wenyou Yang309686c2016-07-20 17:16:27 +08007 */
8
9#include <common.h>
Simon Glass11c89f32017-05-17 17:18:03 -060010#include <dm.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060011#include <asm/global_data.h>
Wenyou Yang309686c2016-07-20 17:16:27 +080012#include <dm/pinctrl.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060013#include <linux/bitops.h>
Wenyou Yang309686c2016-07-20 17:16:27 +080014#include <linux/io.h>
15#include <linux/err.h>
16#include <mach/atmel_pio4.h>
17
18DECLARE_GLOBAL_DATA_PTR;
19
20/*
21 * Warning:
22 * In order to not introduce confusion between Atmel PIO groups and pinctrl
23 * framework groups, Atmel PIO groups will be called banks.
24 */
25
Simon Glassb75b15b2020-12-03 16:55:23 -070026struct atmel_pio4_plat {
Wenyou Yang309686c2016-07-20 17:16:27 +080027 struct atmel_pio4_port *reg_base;
Claudiu Beznea153a7932021-01-27 15:00:30 +020028 unsigned int slew_rate_support;
Wenyou Yang309686c2016-07-20 17:16:27 +080029};
30
31static const struct pinconf_param conf_params[] = {
32 { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
33 { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
34 { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
35 { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
36 { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
37 { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
38 { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
Eugen Hristev90add2b2021-01-05 10:54:01 +020039 { "atmel,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
Claudiu Beznea153a7932021-01-27 15:00:30 +020040 { "slew-rate", PIN_CONFIG_SLEW_RATE, 0},
Wenyou Yang309686c2016-07-20 17:16:27 +080041};
42
Claudiu Beznea153a7932021-01-27 15:00:30 +020043static u32 atmel_pinctrl_get_pinconf(struct udevice *config,
44 struct atmel_pio4_plat *plat)
Wenyou Yang309686c2016-07-20 17:16:27 +080045{
46 const struct pinconf_param *params;
47 u32 param, arg, conf = 0;
48 u32 i;
Eugen Hristev90add2b2021-01-05 10:54:01 +020049 u32 val;
Wenyou Yang309686c2016-07-20 17:16:27 +080050
51 for (i = 0; i < ARRAY_SIZE(conf_params); i++) {
52 params = &conf_params[i];
Eugen Hristeve58dc842021-01-05 10:51:53 +020053 if (!dev_read_prop(config, params->property, NULL))
Wenyou Yang309686c2016-07-20 17:16:27 +080054 continue;
55
56 param = params->param;
57 arg = params->default_value;
58
Claudiu Beznea153a7932021-01-27 15:00:30 +020059 /* Keep slew rate enabled by default. */
60 if (plat->slew_rate_support)
61 conf |= ATMEL_PIO_SR;
62
Wenyou Yang309686c2016-07-20 17:16:27 +080063 switch (param) {
64 case PIN_CONFIG_BIAS_DISABLE:
65 conf &= (~ATMEL_PIO_PUEN_MASK);
66 conf &= (~ATMEL_PIO_PDEN_MASK);
67 break;
68 case PIN_CONFIG_BIAS_PULL_UP:
69 conf |= ATMEL_PIO_PUEN_MASK;
70 break;
71 case PIN_CONFIG_BIAS_PULL_DOWN:
72 conf |= ATMEL_PIO_PDEN_MASK;
73 break;
74 case PIN_CONFIG_DRIVE_OPEN_DRAIN:
75 if (arg == 0)
76 conf &= (~ATMEL_PIO_OPD_MASK);
77 else
78 conf |= ATMEL_PIO_OPD_MASK;
79 break;
80 case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
81 if (arg == 0)
82 conf |= ATMEL_PIO_SCHMITT_MASK;
83 else
84 conf &= (~ATMEL_PIO_SCHMITT_MASK);
85 break;
86 case PIN_CONFIG_INPUT_DEBOUNCE:
87 if (arg == 0) {
88 conf &= (~ATMEL_PIO_IFEN_MASK);
89 conf &= (~ATMEL_PIO_IFSCEN_MASK);
90 } else {
91 conf |= ATMEL_PIO_IFEN_MASK;
92 conf |= ATMEL_PIO_IFSCEN_MASK;
93 }
94 break;
Eugen Hristev90add2b2021-01-05 10:54:01 +020095 case PIN_CONFIG_DRIVE_STRENGTH:
96 dev_read_u32(config, params->property, &val);
97 conf &= (~ATMEL_PIO_DRVSTR_MASK);
98 conf |= (val << ATMEL_PIO_DRVSTR_OFFSET)
99 & ATMEL_PIO_DRVSTR_MASK;
100 break;
Claudiu Beznea153a7932021-01-27 15:00:30 +0200101 case PIN_CONFIG_SLEW_RATE:
102 if (!plat->slew_rate_support)
103 break;
104
105 dev_read_u32(config, params->property, &val);
106 /* And disable it if requested. */
107 if (val == 0)
108 conf &= ~ATMEL_PIO_SR;
109 break;
Wenyou Yang309686c2016-07-20 17:16:27 +0800110 default:
111 printf("%s: Unsupported configuration parameter: %u\n",
112 __func__, param);
113 break;
114 }
115 }
116
117 return conf;
118}
119
120static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
121 u32 bank)
122{
Simon Glassb75b15b2020-12-03 16:55:23 -0700123 struct atmel_pio4_plat *plat = dev_get_plat(dev);
Wenyou Yang309686c2016-07-20 17:16:27 +0800124 struct atmel_pio4_port *bank_base =
125 (struct atmel_pio4_port *)((u32)plat->reg_base +
126 ATMEL_PIO_BANK_OFFSET * bank);
127
128 return bank_base;
129}
130
131#define MAX_PINMUX_ENTRIES 40
132
133static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
134{
Claudiu Beznea153a7932021-01-27 15:00:30 +0200135 struct atmel_pio4_plat *plat = dev_get_plat(dev);
Wenyou Yang309686c2016-07-20 17:16:27 +0800136 struct atmel_pio4_port *bank_base;
137 const void *blob = gd->fdt_blob;
Simon Glassdd79d6e2017-01-17 16:52:55 -0700138 int node = dev_of_offset(config);
Wenyou Yang309686c2016-07-20 17:16:27 +0800139 u32 offset, func, bank, line;
140 u32 cells[MAX_PINMUX_ENTRIES];
141 u32 i, conf;
142 int count;
143
Claudiu Beznea153a7932021-01-27 15:00:30 +0200144 conf = atmel_pinctrl_get_pinconf(config, plat);
Wenyou Yang309686c2016-07-20 17:16:27 +0800145
146 count = fdtdec_get_int_array_count(blob, node, "pinmux",
147 cells, ARRAY_SIZE(cells));
148 if (count < 0) {
149 printf("%s: bad pinmux array %d\n", __func__, count);
150 return -EINVAL;
151 }
152
153 if (count > MAX_PINMUX_ENTRIES) {
154 printf("%s: unsupported pinmux array count %d\n",
155 __func__, count);
156 return -EINVAL;
157 }
158
159 for (i = 0 ; i < count; i++) {
160 offset = ATMEL_GET_PIN_NO(cells[i]);
161 func = ATMEL_GET_PIN_FUNC(cells[i]);
162
163 bank = ATMEL_PIO_BANK(offset);
164 line = ATMEL_PIO_LINE(offset);
165
166 bank_base = atmel_pio4_bank_base(dev, bank);
167
168 writel(BIT(line), &bank_base->mskr);
169 conf &= (~ATMEL_PIO_CFGR_FUNC_MASK);
170 conf |= (func & ATMEL_PIO_CFGR_FUNC_MASK);
171 writel(conf, &bank_base->cfgr);
172 }
173
174 return 0;
175}
176
177const struct pinctrl_ops atmel_pinctrl_ops = {
178 .set_state = atmel_pinctrl_set_state,
179};
180
181static int atmel_pinctrl_probe(struct udevice *dev)
182{
Simon Glassb75b15b2020-12-03 16:55:23 -0700183 struct atmel_pio4_plat *plat = dev_get_plat(dev);
Claudiu Beznea153a7932021-01-27 15:00:30 +0200184 ulong priv = dev_get_driver_data(dev);
Wenyou Yang309686c2016-07-20 17:16:27 +0800185 fdt_addr_t addr_base;
186
187 dev = dev_get_parent(dev);
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900188 addr_base = dev_read_addr(dev);
Wenyou Yang309686c2016-07-20 17:16:27 +0800189 if (addr_base == FDT_ADDR_T_NONE)
190 return -EINVAL;
191
192 plat->reg_base = (struct atmel_pio4_port *)addr_base;
Claudiu Beznea153a7932021-01-27 15:00:30 +0200193 plat->slew_rate_support = priv;
Wenyou Yang309686c2016-07-20 17:16:27 +0800194
195 return 0;
196}
197
198static const struct udevice_id atmel_pinctrl_match[] = {
199 { .compatible = "atmel,sama5d2-pinctrl" },
Claudiu Beznea153a7932021-01-27 15:00:30 +0200200 { .compatible = "microchip,sama7g5-pinctrl",
201 .data = (ulong)1, },
Wenyou Yang309686c2016-07-20 17:16:27 +0800202 {}
203};
204
205U_BOOT_DRIVER(atmel_pinctrl) = {
206 .name = "pinctrl_atmel_pio4",
207 .id = UCLASS_PINCTRL,
208 .of_match = atmel_pinctrl_match,
209 .probe = atmel_pinctrl_probe,
Simon Glassb75b15b2020-12-03 16:55:23 -0700210 .plat_auto = sizeof(struct atmel_pio4_plat),
Wenyou Yang309686c2016-07-20 17:16:27 +0800211 .ops = &atmel_pinctrl_ops,
212};