diff options
author | Paul Mundt <lethal@linux-sh.org> | 2012-07-20 03:39:09 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2012-07-20 03:39:09 -0400 |
commit | fdd85ec3eb8cc1b663678a3efa16ee59a32e0277 (patch) | |
tree | 3864b4b2d6db5ff5815cc1ea60610aa1e2cacc7c /drivers/sh | |
parent | 5440711073157576eb4658c19019b66b25140860 (diff) |
sh: pfc: pin config get/set support.
This implements simple support for adjusting the pin config value via the
pinctrl API. The pinconf-generic code is abandoned for now until we've
got a chance to revamp the pinmux_type state tracking that's needed by
legacy code.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/sh')
-rw-r--r-- | drivers/sh/pfc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/sh/pfc/pinctrl.c | 147 |
2 files changed, 97 insertions, 51 deletions
diff --git a/drivers/sh/pfc/Kconfig b/drivers/sh/pfc/Kconfig index b743aaa543f8..804f9ad1bf4a 100644 --- a/drivers/sh/pfc/Kconfig +++ b/drivers/sh/pfc/Kconfig | |||
@@ -17,7 +17,6 @@ config PINCTRL_SH_PFC | |||
17 | select PINCTRL | 17 | select PINCTRL |
18 | select PINMUX | 18 | select PINMUX |
19 | select PINCONF | 19 | select PINCONF |
20 | select GENERIC_PINCONF | ||
21 | 20 | ||
22 | config GPIO_SH_PFC | 21 | config GPIO_SH_PFC |
23 | tristate "SuperH PFC GPIO support" | 22 | tristate "SuperH PFC GPIO support" |
diff --git a/drivers/sh/pfc/pinctrl.c b/drivers/sh/pfc/pinctrl.c index 900afa5f4069..0802b6c0d653 100644 --- a/drivers/sh/pfc/pinctrl.c +++ b/drivers/sh/pfc/pinctrl.c | |||
@@ -65,10 +65,17 @@ static int sh_pfc_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, | |||
65 | return 0; | 65 | return 0; |
66 | } | 66 | } |
67 | 67 | ||
68 | static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, | ||
69 | unsigned offset) | ||
70 | { | ||
71 | seq_printf(s, "%s", DRV_NAME); | ||
72 | } | ||
73 | |||
68 | static struct pinctrl_ops sh_pfc_pinctrl_ops = { | 74 | static struct pinctrl_ops sh_pfc_pinctrl_ops = { |
69 | .get_groups_count = sh_pfc_get_groups_count, | 75 | .get_groups_count = sh_pfc_get_groups_count, |
70 | .get_group_name = sh_pfc_get_group_name, | 76 | .get_group_name = sh_pfc_get_group_name, |
71 | .get_group_pins = sh_pfc_get_group_pins, | 77 | .get_group_pins = sh_pfc_get_group_pins, |
78 | .pin_dbg_show = sh_pfc_pin_dbg_show, | ||
72 | }; | 79 | }; |
73 | 80 | ||
74 | static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev) | 81 | static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev) |
@@ -124,6 +131,59 @@ static inline int sh_pfc_config_function(struct sh_pfc *pfc, unsigned offset) | |||
124 | return 0; | 131 | return 0; |
125 | } | 132 | } |
126 | 133 | ||
134 | static int sh_pfc_reconfig_pin(struct sh_pfc *pfc, unsigned offset, | ||
135 | int new_type) | ||
136 | { | ||
137 | unsigned long flags; | ||
138 | int pinmux_type; | ||
139 | int ret = -EINVAL; | ||
140 | |||
141 | spin_lock_irqsave(&pfc->lock, flags); | ||
142 | |||
143 | pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE; | ||
144 | |||
145 | /* | ||
146 | * See if the present config needs to first be de-configured. | ||
147 | */ | ||
148 | switch (pinmux_type) { | ||
149 | case PINMUX_TYPE_GPIO: | ||
150 | break; | ||
151 | case PINMUX_TYPE_OUTPUT: | ||
152 | case PINMUX_TYPE_INPUT: | ||
153 | case PINMUX_TYPE_INPUT_PULLUP: | ||
154 | case PINMUX_TYPE_INPUT_PULLDOWN: | ||
155 | sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE); | ||
156 | break; | ||
157 | default: | ||
158 | goto err; | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * Dry run | ||
163 | */ | ||
164 | if (sh_pfc_config_gpio(pfc, offset, new_type, | ||
165 | GPIO_CFG_DRYRUN) != 0) | ||
166 | goto err; | ||
167 | |||
168 | /* | ||
169 | * Request | ||
170 | */ | ||
171 | if (sh_pfc_config_gpio(pfc, offset, new_type, | ||
172 | GPIO_CFG_REQ) != 0) | ||
173 | goto err; | ||
174 | |||
175 | pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | ||
176 | pfc->gpios[offset].flags |= new_type; | ||
177 | |||
178 | ret = 0; | ||
179 | |||
180 | err: | ||
181 | spin_unlock_irqrestore(&pfc->lock, flags); | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | |||
127 | static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev, | 187 | static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev, |
128 | struct pinctrl_gpio_range *range, | 188 | struct pinctrl_gpio_range *range, |
129 | unsigned offset) | 189 | unsigned offset) |
@@ -185,49 +245,9 @@ static int sh_pfc_gpio_set_direction(struct pinctrl_dev *pctldev, | |||
185 | unsigned offset, bool input) | 245 | unsigned offset, bool input) |
186 | { | 246 | { |
187 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); | 247 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
188 | struct sh_pfc *pfc = pmx->pfc; | 248 | int type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT; |
189 | unsigned long flags; | ||
190 | int pinmux_type, new_pinmux_type; | ||
191 | int ret = -EINVAL; | ||
192 | 249 | ||
193 | new_pinmux_type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT; | 250 | return sh_pfc_reconfig_pin(pmx->pfc, offset, type); |
194 | |||
195 | spin_lock_irqsave(&pfc->lock, flags); | ||
196 | |||
197 | pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE; | ||
198 | |||
199 | switch (pinmux_type) { | ||
200 | case PINMUX_TYPE_GPIO: | ||
201 | break; | ||
202 | case PINMUX_TYPE_OUTPUT: | ||
203 | case PINMUX_TYPE_INPUT: | ||
204 | case PINMUX_TYPE_INPUT_PULLUP: | ||
205 | case PINMUX_TYPE_INPUT_PULLDOWN: | ||
206 | sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE); | ||
207 | break; | ||
208 | default: | ||
209 | goto err; | ||
210 | } | ||
211 | |||
212 | if (sh_pfc_config_gpio(pfc, offset, | ||
213 | new_pinmux_type, | ||
214 | GPIO_CFG_DRYRUN) != 0) | ||
215 | goto err; | ||
216 | |||
217 | if (sh_pfc_config_gpio(pfc, offset, | ||
218 | new_pinmux_type, | ||
219 | GPIO_CFG_REQ) != 0) | ||
220 | BUG(); | ||
221 | |||
222 | pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | ||
223 | pfc->gpios[offset].flags |= new_pinmux_type; | ||
224 | |||
225 | ret = 0; | ||
226 | |||
227 | err: | ||
228 | spin_unlock_irqrestore(&pfc->lock, flags); | ||
229 | |||
230 | return ret; | ||
231 | } | 251 | } |
232 | 252 | ||
233 | static struct pinmux_ops sh_pfc_pinmux_ops = { | 253 | static struct pinmux_ops sh_pfc_pinmux_ops = { |
@@ -244,26 +264,53 @@ static struct pinmux_ops sh_pfc_pinmux_ops = { | |||
244 | static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, | 264 | static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, |
245 | unsigned long *config) | 265 | unsigned long *config) |
246 | { | 266 | { |
247 | enum pin_config_param param = (enum pin_config_param)(*config); | 267 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
268 | struct sh_pfc *pfc = pmx->pfc; | ||
248 | 269 | ||
249 | switch (param) { | 270 | *config = pfc->gpios[pin].flags & PINMUX_FLAG_TYPE; |
250 | default: | ||
251 | break; | ||
252 | } | ||
253 | 271 | ||
254 | return -ENOTSUPP; | 272 | return 0; |
255 | } | 273 | } |
256 | 274 | ||
257 | static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, | 275 | static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, |
258 | unsigned long config) | 276 | unsigned long config) |
259 | { | 277 | { |
260 | return -EINVAL; | 278 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
279 | struct sh_pfc *pfc = pmx->pfc; | ||
280 | |||
281 | /* Validate the new type */ | ||
282 | if (config >= PINMUX_FLAG_TYPE) | ||
283 | return -EINVAL; | ||
284 | |||
285 | return sh_pfc_reconfig_pin(pmx->pfc, pin, config); | ||
286 | } | ||
287 | |||
288 | static void sh_pfc_pinconf_dbg_show(struct pinctrl_dev *pctldev, | ||
289 | struct seq_file *s, unsigned pin) | ||
290 | { | ||
291 | const char *pinmux_type_str[] = { | ||
292 | [PINMUX_TYPE_NONE] = "none", | ||
293 | [PINMUX_TYPE_FUNCTION] = "function", | ||
294 | [PINMUX_TYPE_GPIO] = "gpio", | ||
295 | [PINMUX_TYPE_OUTPUT] = "output", | ||
296 | [PINMUX_TYPE_INPUT] = "input", | ||
297 | [PINMUX_TYPE_INPUT_PULLUP] = "input bias pull up", | ||
298 | [PINMUX_TYPE_INPUT_PULLDOWN] = "input bias pull down", | ||
299 | }; | ||
300 | unsigned long config; | ||
301 | int rc; | ||
302 | |||
303 | rc = sh_pfc_pinconf_get(pctldev, pin, &config); | ||
304 | if (unlikely(rc != 0)) | ||
305 | return; | ||
306 | |||
307 | seq_printf(s, " %s", pinmux_type_str[config]); | ||
261 | } | 308 | } |
262 | 309 | ||
263 | static struct pinconf_ops sh_pfc_pinconf_ops = { | 310 | static struct pinconf_ops sh_pfc_pinconf_ops = { |
264 | .is_generic = true, | ||
265 | .pin_config_get = sh_pfc_pinconf_get, | 311 | .pin_config_get = sh_pfc_pinconf_get, |
266 | .pin_config_set = sh_pfc_pinconf_set, | 312 | .pin_config_set = sh_pfc_pinconf_set, |
313 | .pin_config_dbg_show = sh_pfc_pinconf_dbg_show, | ||
267 | }; | 314 | }; |
268 | 315 | ||
269 | static struct pinctrl_gpio_range sh_pfc_gpio_range = { | 316 | static struct pinctrl_gpio_range sh_pfc_gpio_range = { |