1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
// SPDX-License-Identifier: GPL-2.0+
/*
* TLMM driver for Qualcomm APQ8016, APQ8096
*
* (C) Copyright 2018 Ramon Fried <ramon.fried@gmail.com>
*
*/
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include <dm/device_compat.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <asm/gpio.h>
#include <dm/pinctrl.h>
#include <linux/bitops.h>
#include <linux/bitmap.h>
#include <linux/bug.h>
#include <mach/gpio.h>
#include "pinctrl-qcom.h"
#define MSM_PINCTRL_MAX_PINS 256
struct msm_pinctrl_priv {
phys_addr_t base;
struct msm_pinctrl_data *data;
DECLARE_BITMAP(reserved_map, MSM_PINCTRL_MAX_PINS);
};
#define GPIO_CONFIG_REG(priv, x) \
(qcom_pin_offset((priv)->data->pin_data.pin_offsets, x))
#define GPIO_IN_OUT_REG(priv, x) \
(GPIO_CONFIG_REG(priv, x) + 0x4)
#define TLMM_GPIO_PULL_MASK GENMASK(1, 0)
#define TLMM_FUNC_SEL_MASK GENMASK(5, 2)
#define TLMM_DRV_STRENGTH_MASK GENMASK(8, 6)
#define TLMM_GPIO_OUTPUT_MASK BIT(1)
#define TLMM_GPIO_OE_MASK BIT(9)
/* GPIO register shifts. */
#define GPIO_OUT_SHIFT 1
static const struct pinconf_param msm_conf_params[] = {
{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 2 },
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 3 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "output-high", PIN_CONFIG_OUTPUT, 1, },
{ "output-low", PIN_CONFIG_OUTPUT, 0, },
};
static int msm_get_functions_count(struct udevice *dev)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
return priv->data->functions_count;
}
static int msm_get_pins_count(struct udevice *dev)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
return priv->data->pin_data.pin_count;
}
static const char *msm_get_function_name(struct udevice *dev,
unsigned int selector)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
return priv->data->get_function_name(dev, selector);
}
static int msm_pinctrl_parse_ranges(struct udevice *dev)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
ofnode node = dev_ofnode(dev);
int ret, count, i;
u32 *ranges;
if (ofnode_read_prop(node, "gpio-reserved-ranges", &count)) {
if (count % 2 == 1) {
dev_err(dev, "gpio-reserved-ranges must be a multiple of 2\n");
return -EINVAL;
}
ranges = malloc(count);
if (!ranges)
return -ENOMEM;
ret = ofnode_read_u32_array(node, "gpio-reserved-ranges", ranges, count / 4);
if (ret) {
dev_err(dev, "failed to read gpio-reserved-ranges array (%d)\n", ret);
return ret;
}
for (i = 0; i < count / 4; i += 2) {
if (ranges[i] >= MSM_PINCTRL_MAX_PINS ||
(ranges[i] + ranges[i + 1]) >= MSM_PINCTRL_MAX_PINS) {
dev_err(dev, "invalid reserved-range (%d;%d)\n",
ranges[i], ranges[i + 1]);
return -EINVAL;
}
bitmap_set(priv->reserved_map, ranges[i], ranges[i + 1]);
}
free(ranges);
}
return 0;
}
static int msm_pinctrl_probe(struct udevice *dev)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
int ret;
priv->base = dev_read_addr(dev);
priv->data = (struct msm_pinctrl_data *)dev_get_driver_data(dev);
ret = msm_pinctrl_parse_ranges(dev);
if (ret) {
printf("Couldn't parse reserved GPIO ranges!\n");
return ret;
}
return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
}
static const char *msm_get_pin_name(struct udevice *dev, unsigned int selector)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
return priv->data->get_pin_name(dev, selector);
}
static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector,
unsigned int func_selector)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
int func = priv->data->get_function_mux(pin_selector, func_selector);
if (func < 0)
return func;
if (msm_pinctrl_is_reserved(dev, pin_selector))
return -EPERM;
/* Always NOP for special pins, assume they're in the correct state */
if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
return 0;
clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
TLMM_FUNC_SEL_MASK | TLMM_GPIO_OE_MASK, func << 2);
return 0;
}
static int msm_pinconf_set_special(struct msm_pinctrl_priv *priv, unsigned int pin_selector,
unsigned int param, unsigned int argument)
{
unsigned int offset = pin_selector - priv->data->pin_data.special_pins_start;
const struct msm_special_pin_data *data;
if (!priv->data->pin_data.special_pins_data)
return 0;
data = &priv->data->pin_data.special_pins_data[offset];
switch (param) {
case PIN_CONFIG_DRIVE_STRENGTH:
argument = (argument / 2) - 1;
clrsetbits_le32(priv->base + data->ctl_reg,
GENMASK(2, 0) << data->drv_bit,
argument << data->drv_bit);
break;
case PIN_CONFIG_BIAS_DISABLE:
clrbits_le32(priv->base + data->ctl_reg,
TLMM_GPIO_PULL_MASK << data->pull_bit);
break;
case PIN_CONFIG_BIAS_PULL_UP:
clrsetbits_le32(priv->base + data->ctl_reg,
TLMM_GPIO_PULL_MASK << data->pull_bit,
argument << data->pull_bit);
break;
default:
return 0;
}
return 0;
}
static int msm_pinconf_set(struct udevice *dev, unsigned int pin_selector,
unsigned int param, unsigned int argument)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
if (msm_pinctrl_is_reserved(dev, pin_selector))
return -EPERM;
if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
return msm_pinconf_set_special(priv, pin_selector, param, argument);
switch (param) {
case PIN_CONFIG_DRIVE_STRENGTH:
argument = (argument / 2) - 1;
clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
TLMM_DRV_STRENGTH_MASK, argument << 6);
break;
case PIN_CONFIG_BIAS_DISABLE:
clrbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
TLMM_GPIO_PULL_MASK);
break;
case PIN_CONFIG_BIAS_PULL_UP:
clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
TLMM_GPIO_PULL_MASK, argument);
break;
case PIN_CONFIG_OUTPUT:
writel(argument << GPIO_OUT_SHIFT,
priv->base + GPIO_IN_OUT_REG(priv, pin_selector));
setbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector),
TLMM_GPIO_OE_MASK);
break;
default:
return 0;
}
return 0;
}
struct pinctrl_ops msm_pinctrl_ops = {
.get_pins_count = msm_get_pins_count,
.get_pin_name = msm_get_pin_name,
.set_state = pinctrl_generic_set_state,
.pinmux_set = msm_pinmux_set,
.pinconf_num_params = ARRAY_SIZE(msm_conf_params),
.pinconf_params = msm_conf_params,
.pinconf_set = msm_pinconf_set,
.get_functions_count = msm_get_functions_count,
.get_function_name = msm_get_function_name,
};
int msm_pinctrl_bind(struct udevice *dev)
{
ofnode node = dev_ofnode(dev);
struct msm_pinctrl_data *data = (struct msm_pinctrl_data *)dev_get_driver_data(dev);
struct driver *drv;
struct udevice *pinctrl_dev;
const char *name;
int ret;
if (!data->pin_data.special_pins_start)
dev_warn(dev, "Special pins start index not defined!\n");
drv = lists_driver_lookup_name("pinctrl_qcom");
if (!drv)
return -ENOENT;
ret = device_bind_with_driver_data(dev_get_parent(dev), drv, ofnode_get_name(node), (ulong)data,
dev_ofnode(dev), &pinctrl_dev);
if (ret)
return ret;
ofnode_get_property(node, "gpio-controller", &ret);
if (ret < 0)
return 0;
/* Get the name of gpio node */
name = ofnode_get_name(node);
if (!name)
return -EINVAL;
drv = lists_driver_lookup_name("gpio_msm");
if (!drv) {
printf("Can't find gpio_msm driver\n");
return -ENODEV;
}
/* Bind gpio device as a child of the pinctrl device */
ret = device_bind_with_driver_data(pinctrl_dev, drv,
name, (ulong)&data->pin_data, node, NULL);
if (ret) {
device_unbind(pinctrl_dev);
return ret;
}
return 0;
}
U_BOOT_DRIVER(pinctrl_qcom) = {
.name = "pinctrl_qcom",
.id = UCLASS_PINCTRL,
.priv_auto = sizeof(struct msm_pinctrl_priv),
.ops = &msm_pinctrl_ops,
.probe = msm_pinctrl_probe,
};
bool msm_pinctrl_is_reserved(struct udevice *dev, unsigned int pin)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
if (pin >= MSM_PINCTRL_MAX_PINS)
return false;
return test_bit(pin, priv->reserved_map);
}
|