aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-07-20 03:39:09 -0400
committerPaul Mundt <lethal@linux-sh.org>2012-07-20 03:39:09 -0400
commitfdd85ec3eb8cc1b663678a3efa16ee59a32e0277 (patch)
tree3864b4b2d6db5ff5815cc1ea60610aa1e2cacc7c /drivers/sh
parent5440711073157576eb4658c19019b66b25140860 (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/Kconfig1
-rw-r--r--drivers/sh/pfc/pinctrl.c147
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
22config GPIO_SH_PFC 21config 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
68static 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
68static struct pinctrl_ops sh_pfc_pinctrl_ops = { 74static 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
74static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev) 81static 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
134static 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
180err:
181 spin_unlock_irqrestore(&pfc->lock, flags);
182
183 return ret;
184}
185
186
127static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev, 187static 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
227err:
228 spin_unlock_irqrestore(&pfc->lock, flags);
229
230 return ret;
231} 251}
232 252
233static struct pinmux_ops sh_pfc_pinmux_ops = { 253static struct pinmux_ops sh_pfc_pinmux_ops = {
@@ -244,26 +264,53 @@ static struct pinmux_ops sh_pfc_pinmux_ops = {
244static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, 264static 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
257static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, 275static 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
288static 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
263static struct pinconf_ops sh_pfc_pinconf_ops = { 310static 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
269static struct pinctrl_gpio_range sh_pfc_gpio_range = { 316static struct pinctrl_gpio_range sh_pfc_gpio_range = {