diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2015-11-21 13:04:50 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-12-10 10:11:35 -0500 |
commit | d530ef9b88e5162a1972050994264d66ca884f3f (patch) | |
tree | 3b6f36d479d9b8ec8788577ef72e58e206ad8134 | |
parent | 73317712d9277407b726917de7c4e6d5a4b7df99 (diff) |
pinctrl: pxa: pxa2xx: add pin muxing
The driver is inspired from the sunxi driver. The pxa architecture
specificities leading to the driver are :
- each pin has 8 possible alternate functions
- 4 of these are output kind
- 4 of these are input kind
- there is always a "gpio input" and "gpio output" function
- the function matrix is very scattered :
- some functions can be found on 5 different pads
- the number of functions is greater than the number of pins
- there is no "topology" grouping of pins (such as all SPI in one
corner of the die)
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/pinctrl/pxa/pinctrl-pxa2xx.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c index baded1a8745b..a4ba82459af8 100644 --- a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c +++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c | |||
@@ -64,8 +64,129 @@ static const struct pinctrl_ops pxa2xx_pctl_ops = { | |||
64 | .get_group_pins = pxa2xx_pctrl_get_group_pins, | 64 | .get_group_pins = pxa2xx_pctrl_get_group_pins, |
65 | }; | 65 | }; |
66 | 66 | ||
67 | static struct pxa_desc_function * | ||
68 | pxa_desc_by_func_group(struct pxa_pinctrl *pctl, const char *pin_name, | ||
69 | const char *func_name) | ||
70 | { | ||
71 | int i; | ||
72 | struct pxa_desc_function *df; | ||
73 | |||
74 | for (i = 0; i < pctl->npins; i++) { | ||
75 | const struct pxa_desc_pin *pin = pctl->ppins + i; | ||
76 | |||
77 | if (!strcmp(pin->pin.name, pin_name)) | ||
78 | for (df = pin->functions; df->name; df++) | ||
79 | if (!strcmp(df->name, func_name)) | ||
80 | return df; | ||
81 | } | ||
82 | |||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | static int pxa2xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
87 | struct pinctrl_gpio_range *range, | ||
88 | unsigned pin, | ||
89 | bool input) | ||
90 | { | ||
91 | struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
92 | unsigned long flags; | ||
93 | uint32_t val; | ||
94 | void __iomem *gpdr; | ||
95 | |||
96 | gpdr = pctl->base_gpdr[pin / 32]; | ||
97 | dev_dbg(pctl->dev, "set_direction(pin=%d): dir=%d\n", | ||
98 | pin, !input); | ||
99 | |||
100 | spin_lock_irqsave(&pctl->lock, flags); | ||
101 | |||
102 | val = readl_relaxed(gpdr); | ||
103 | val = (val & ~BIT(pin % 32)) | (input ? 0 : BIT(pin % 32)); | ||
104 | writel_relaxed(val, gpdr); | ||
105 | |||
106 | spin_unlock_irqrestore(&pctl->lock, flags); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static const char *pxa2xx_pmx_get_func_name(struct pinctrl_dev *pctldev, | ||
112 | unsigned function) | ||
113 | { | ||
114 | struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
115 | struct pxa_pinctrl_function *pf = pctl->functions + function; | ||
116 | |||
117 | return pf->name; | ||
118 | } | ||
119 | |||
120 | static int pxa2xx_get_functions_count(struct pinctrl_dev *pctldev) | ||
121 | { | ||
122 | struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
123 | |||
124 | return pctl->nfuncs; | ||
125 | } | ||
126 | |||
127 | static int pxa2xx_pmx_get_func_groups(struct pinctrl_dev *pctldev, | ||
128 | unsigned function, | ||
129 | const char * const **groups, | ||
130 | unsigned * const num_groups) | ||
131 | { | ||
132 | struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
133 | struct pxa_pinctrl_function *pf = pctl->functions + function; | ||
134 | |||
135 | *groups = pf->groups; | ||
136 | *num_groups = pf->ngroups; | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int pxa2xx_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned function, | ||
142 | unsigned tgroup) | ||
143 | { | ||
144 | struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
145 | struct pxa_pinctrl_group *group = pctl->groups + tgroup; | ||
146 | struct pxa_desc_function *df; | ||
147 | int pin, shift; | ||
148 | unsigned long flags; | ||
149 | void __iomem *gafr, *gpdr; | ||
150 | u32 val; | ||
151 | |||
152 | |||
153 | df = pxa_desc_by_func_group(pctl, group->name, | ||
154 | (pctl->functions + function)->name); | ||
155 | if (!df) | ||
156 | return -EINVAL; | ||
157 | |||
158 | pin = group->pin; | ||
159 | gafr = pctl->base_gafr[pin / 16]; | ||
160 | gpdr = pctl->base_gpdr[pin / 32]; | ||
161 | shift = (pin % 16) << 1; | ||
162 | dev_dbg(pctl->dev, "set_mux(pin=%d): af=%d dir=%d\n", | ||
163 | pin, df->muxval >> 1, df->muxval & 0x1); | ||
164 | |||
165 | spin_lock_irqsave(&pctl->lock, flags); | ||
166 | |||
167 | val = readl_relaxed(gafr); | ||
168 | val = (val & ~(0x3 << shift)) | ((df->muxval >> 1) << shift); | ||
169 | writel_relaxed(val, gafr); | ||
170 | |||
171 | val = readl_relaxed(gpdr); | ||
172 | val = (val & ~BIT(pin % 32)) | ((df->muxval & 1) ? BIT(pin % 32) : 0); | ||
173 | writel_relaxed(val, gpdr); | ||
174 | |||
175 | spin_unlock_irqrestore(&pctl->lock, flags); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | static const struct pinmux_ops pxa2xx_pinmux_ops = { | ||
180 | .get_functions_count = pxa2xx_get_functions_count, | ||
181 | .get_function_name = pxa2xx_pmx_get_func_name, | ||
182 | .get_function_groups = pxa2xx_pmx_get_func_groups, | ||
183 | .set_mux = pxa2xx_pmx_set_mux, | ||
184 | .gpio_set_direction = pxa2xx_pmx_gpio_set_direction, | ||
185 | }; | ||
186 | |||
67 | static struct pinctrl_desc pxa2xx_pinctrl_desc = { | 187 | static struct pinctrl_desc pxa2xx_pinctrl_desc = { |
68 | .pctlops = &pxa2xx_pctl_ops, | 188 | .pctlops = &pxa2xx_pctl_ops, |
189 | .pmxops = &pxa2xx_pinmux_ops, | ||
69 | }; | 190 | }; |
70 | 191 | ||
71 | static const struct pxa_pinctrl_function * | 192 | static const struct pxa_pinctrl_function * |