blob: 3a5143adc38108ee911cf4401c4cfa88d0d38a2d [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>
Wenyou Yang309686c2016-07-20 17:16:27 +080011#include <dm/pinctrl.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060012#include <linux/bitops.h>
Wenyou Yang309686c2016-07-20 17:16:27 +080013#include <linux/io.h>
14#include <linux/err.h>
15#include <mach/atmel_pio4.h>
16
17DECLARE_GLOBAL_DATA_PTR;
18
19/*
20 * Warning:
21 * In order to not introduce confusion between Atmel PIO groups and pinctrl
22 * framework groups, Atmel PIO groups will be called banks.
23 */
24
Simon Glassb75b15b2020-12-03 16:55:23 -070025struct atmel_pio4_plat {
Wenyou Yang309686c2016-07-20 17:16:27 +080026 struct atmel_pio4_port *reg_base;
27};
28
29static const struct pinconf_param conf_params[] = {
30 { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
31 { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
32 { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
33 { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
34 { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
35 { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
36 { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
Eugen Hristev90add2b2021-01-05 10:54:01 +020037 { "atmel,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
Wenyou Yang309686c2016-07-20 17:16:27 +080038};
39
Eugen Hristeve58dc842021-01-05 10:51:53 +020040static u32 atmel_pinctrl_get_pinconf(struct udevice *config)
Wenyou Yang309686c2016-07-20 17:16:27 +080041{
42 const struct pinconf_param *params;
43 u32 param, arg, conf = 0;
44 u32 i;
Eugen Hristev90add2b2021-01-05 10:54:01 +020045 u32 val;
Wenyou Yang309686c2016-07-20 17:16:27 +080046
47 for (i = 0; i < ARRAY_SIZE(conf_params); i++) {
48 params = &conf_params[i];
Eugen Hristeve58dc842021-01-05 10:51:53 +020049 if (!dev_read_prop(config, params->property, NULL))
Wenyou Yang309686c2016-07-20 17:16:27 +080050 continue;
51
52 param = params->param;
53 arg = params->default_value;
54
55 switch (param) {
56 case PIN_CONFIG_BIAS_DISABLE:
57 conf &= (~ATMEL_PIO_PUEN_MASK);
58 conf &= (~ATMEL_PIO_PDEN_MASK);
59 break;
60 case PIN_CONFIG_BIAS_PULL_UP:
61 conf |= ATMEL_PIO_PUEN_MASK;
62 break;
63 case PIN_CONFIG_BIAS_PULL_DOWN:
64 conf |= ATMEL_PIO_PDEN_MASK;
65 break;
66 case PIN_CONFIG_DRIVE_OPEN_DRAIN:
67 if (arg == 0)
68 conf &= (~ATMEL_PIO_OPD_MASK);
69 else
70 conf |= ATMEL_PIO_OPD_MASK;
71 break;
72 case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
73 if (arg == 0)
74 conf |= ATMEL_PIO_SCHMITT_MASK;
75 else
76 conf &= (~ATMEL_PIO_SCHMITT_MASK);
77 break;
78 case PIN_CONFIG_INPUT_DEBOUNCE:
79 if (arg == 0) {
80 conf &= (~ATMEL_PIO_IFEN_MASK);
81 conf &= (~ATMEL_PIO_IFSCEN_MASK);
82 } else {
83 conf |= ATMEL_PIO_IFEN_MASK;
84 conf |= ATMEL_PIO_IFSCEN_MASK;
85 }
86 break;
Eugen Hristev90add2b2021-01-05 10:54:01 +020087 case PIN_CONFIG_DRIVE_STRENGTH:
88 dev_read_u32(config, params->property, &val);
89 conf &= (~ATMEL_PIO_DRVSTR_MASK);
90 conf |= (val << ATMEL_PIO_DRVSTR_OFFSET)
91 & ATMEL_PIO_DRVSTR_MASK;
92 break;
Wenyou Yang309686c2016-07-20 17:16:27 +080093 default:
94 printf("%s: Unsupported configuration parameter: %u\n",
95 __func__, param);
96 break;
97 }
98 }
99
100 return conf;
101}
102
103static inline struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
104 u32 bank)
105{
Simon Glassb75b15b2020-12-03 16:55:23 -0700106 struct atmel_pio4_plat *plat = dev_get_plat(dev);
Wenyou Yang309686c2016-07-20 17:16:27 +0800107 struct atmel_pio4_port *bank_base =
108 (struct atmel_pio4_port *)((u32)plat->reg_base +
109 ATMEL_PIO_BANK_OFFSET * bank);
110
111 return bank_base;
112}
113
114#define MAX_PINMUX_ENTRIES 40
115
116static int atmel_pinctrl_set_state(struct udevice *dev, struct udevice *config)
117{
118 struct atmel_pio4_port *bank_base;
119 const void *blob = gd->fdt_blob;
Simon Glassdd79d6e2017-01-17 16:52:55 -0700120 int node = dev_of_offset(config);
Wenyou Yang309686c2016-07-20 17:16:27 +0800121 u32 offset, func, bank, line;
122 u32 cells[MAX_PINMUX_ENTRIES];
123 u32 i, conf;
124 int count;
125
Eugen Hristeve58dc842021-01-05 10:51:53 +0200126 conf = atmel_pinctrl_get_pinconf(config);
Wenyou Yang309686c2016-07-20 17:16:27 +0800127
128 count = fdtdec_get_int_array_count(blob, node, "pinmux",
129 cells, ARRAY_SIZE(cells));
130 if (count < 0) {
131 printf("%s: bad pinmux array %d\n", __func__, count);
132 return -EINVAL;
133 }
134
135 if (count > MAX_PINMUX_ENTRIES) {
136 printf("%s: unsupported pinmux array count %d\n",
137 __func__, count);
138 return -EINVAL;
139 }
140
141 for (i = 0 ; i < count; i++) {
142 offset = ATMEL_GET_PIN_NO(cells[i]);
143 func = ATMEL_GET_PIN_FUNC(cells[i]);
144
145 bank = ATMEL_PIO_BANK(offset);
146 line = ATMEL_PIO_LINE(offset);
147
148 bank_base = atmel_pio4_bank_base(dev, bank);
149
150 writel(BIT(line), &bank_base->mskr);
151 conf &= (~ATMEL_PIO_CFGR_FUNC_MASK);
152 conf |= (func & ATMEL_PIO_CFGR_FUNC_MASK);
153 writel(conf, &bank_base->cfgr);
154 }
155
156 return 0;
157}
158
159const struct pinctrl_ops atmel_pinctrl_ops = {
160 .set_state = atmel_pinctrl_set_state,
161};
162
163static int atmel_pinctrl_probe(struct udevice *dev)
164{
Simon Glassb75b15b2020-12-03 16:55:23 -0700165 struct atmel_pio4_plat *plat = dev_get_plat(dev);
Wenyou Yang309686c2016-07-20 17:16:27 +0800166 fdt_addr_t addr_base;
167
168 dev = dev_get_parent(dev);
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900169 addr_base = dev_read_addr(dev);
Wenyou Yang309686c2016-07-20 17:16:27 +0800170 if (addr_base == FDT_ADDR_T_NONE)
171 return -EINVAL;
172
173 plat->reg_base = (struct atmel_pio4_port *)addr_base;
174
175 return 0;
176}
177
178static const struct udevice_id atmel_pinctrl_match[] = {
179 { .compatible = "atmel,sama5d2-pinctrl" },
Eugen Hristevd05b43d2020-08-27 12:04:40 +0300180 { .compatible = "microchip,sama7g5-pinctrl" },
Wenyou Yang309686c2016-07-20 17:16:27 +0800181 {}
182};
183
184U_BOOT_DRIVER(atmel_pinctrl) = {
185 .name = "pinctrl_atmel_pio4",
186 .id = UCLASS_PINCTRL,
187 .of_match = atmel_pinctrl_match,
188 .probe = atmel_pinctrl_probe,
Simon Glassb75b15b2020-12-03 16:55:23 -0700189 .plat_auto = sizeof(struct atmel_pio4_plat),
Wenyou Yang309686c2016-07-20 17:16:27 +0800190 .ops = &atmel_pinctrl_ops,
191};