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
|
// 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/bug.h>
#include <mach/gpio.h>
#include "pinctrl-qcom.h"
struct msm_pinctrl_priv {
phys_addr_t base;
struct msm_pinctrl_data *data;
};
#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 },
{ "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_probe(struct udevice *dev)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
priv->base = dev_read_addr(dev);
priv->data = (struct msm_pinctrl_data *)dev_get_driver_data(dev);
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);
u32 func = priv->data->get_function_mux(pin_selector, func_selector);
/* 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(struct udevice *dev, unsigned int pin_selector,
unsigned int param, unsigned int argument)
{
struct msm_pinctrl_priv *priv = dev_get_priv(dev);
/* Always NOP for special pins */
if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
return 0;
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,
};
|