summaryrefslogtreecommitdiffstats
path: root/drivers/sh/pfc/pinctrl.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-07-20 16:39:09 +0900
committerPaul Mundt <lethal@linux-sh.org>2012-07-20 16:39:09 +0900
commitfdd85ec3eb8cc1b663678a3efa16ee59a32e0277 (patch)
tree3864b4b2d6db5ff5815cc1ea60610aa1e2cacc7c /drivers/sh/pfc/pinctrl.c
parent5440711073157576eb4658c19019b66b25140860 (diff)
downloadop-kernel-dev-fdd85ec3eb8cc1b663678a3efa16ee59a32e0277.zip
op-kernel-dev-fdd85ec3eb8cc1b663678a3efa16ee59a32e0277.tar.gz
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/pfc/pinctrl.c')
-rw-r--r--drivers/sh/pfc/pinctrl.c147
1 files changed, 97 insertions, 50 deletions
diff --git a/drivers/sh/pfc/pinctrl.c b/drivers/sh/pfc/pinctrl.c
index 900afa5..0802b6c 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,
return 0;
}
+static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, "%s", DRV_NAME);
+}
+
static struct pinctrl_ops sh_pfc_pinctrl_ops = {
.get_groups_count = sh_pfc_get_groups_count,
.get_group_name = sh_pfc_get_group_name,
.get_group_pins = sh_pfc_get_group_pins,
+ .pin_dbg_show = sh_pfc_pin_dbg_show,
};
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)
return 0;
}
+static int sh_pfc_reconfig_pin(struct sh_pfc *pfc, unsigned offset,
+ int new_type)
+{
+ unsigned long flags;
+ int pinmux_type;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&pfc->lock, flags);
+
+ pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
+
+ /*
+ * See if the present config needs to first be de-configured.
+ */
+ switch (pinmux_type) {
+ case PINMUX_TYPE_GPIO:
+ break;
+ case PINMUX_TYPE_OUTPUT:
+ case PINMUX_TYPE_INPUT:
+ case PINMUX_TYPE_INPUT_PULLUP:
+ case PINMUX_TYPE_INPUT_PULLDOWN:
+ sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE);
+ break;
+ default:
+ goto err;
+ }
+
+ /*
+ * Dry run
+ */
+ if (sh_pfc_config_gpio(pfc, offset, new_type,
+ GPIO_CFG_DRYRUN) != 0)
+ goto err;
+
+ /*
+ * Request
+ */
+ if (sh_pfc_config_gpio(pfc, offset, new_type,
+ GPIO_CFG_REQ) != 0)
+ goto err;
+
+ pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+ pfc->gpios[offset].flags |= new_type;
+
+ ret = 0;
+
+err:
+ spin_unlock_irqrestore(&pfc->lock, flags);
+
+ return ret;
+}
+
+
static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
@@ -185,49 +245,9 @@ static int sh_pfc_gpio_set_direction(struct pinctrl_dev *pctldev,
unsigned offset, bool input)
{
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
- struct sh_pfc *pfc = pmx->pfc;
- unsigned long flags;
- int pinmux_type, new_pinmux_type;
- int ret = -EINVAL;
+ int type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT;
- new_pinmux_type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT;
-
- spin_lock_irqsave(&pfc->lock, flags);
-
- pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
-
- switch (pinmux_type) {
- case PINMUX_TYPE_GPIO:
- break;
- case PINMUX_TYPE_OUTPUT:
- case PINMUX_TYPE_INPUT:
- case PINMUX_TYPE_INPUT_PULLUP:
- case PINMUX_TYPE_INPUT_PULLDOWN:
- sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE);
- break;
- default:
- goto err;
- }
-
- if (sh_pfc_config_gpio(pfc, offset,
- new_pinmux_type,
- GPIO_CFG_DRYRUN) != 0)
- goto err;
-
- if (sh_pfc_config_gpio(pfc, offset,
- new_pinmux_type,
- GPIO_CFG_REQ) != 0)
- BUG();
-
- pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
- pfc->gpios[offset].flags |= new_pinmux_type;
-
- ret = 0;
-
-err:
- spin_unlock_irqrestore(&pfc->lock, flags);
-
- return ret;
+ return sh_pfc_reconfig_pin(pmx->pfc, offset, type);
}
static struct pinmux_ops sh_pfc_pinmux_ops = {
@@ -244,26 +264,53 @@ static struct pinmux_ops sh_pfc_pinmux_ops = {
static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *config)
{
- enum pin_config_param param = (enum pin_config_param)(*config);
+ struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct sh_pfc *pfc = pmx->pfc;
- switch (param) {
- default:
- break;
- }
+ *config = pfc->gpios[pin].flags & PINMUX_FLAG_TYPE;
- return -ENOTSUPP;
+ return 0;
}
static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long config)
{
- return -EINVAL;
+ struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct sh_pfc *pfc = pmx->pfc;
+
+ /* Validate the new type */
+ if (config >= PINMUX_FLAG_TYPE)
+ return -EINVAL;
+
+ return sh_pfc_reconfig_pin(pmx->pfc, pin, config);
+}
+
+static void sh_pfc_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned pin)
+{
+ const char *pinmux_type_str[] = {
+ [PINMUX_TYPE_NONE] = "none",
+ [PINMUX_TYPE_FUNCTION] = "function",
+ [PINMUX_TYPE_GPIO] = "gpio",
+ [PINMUX_TYPE_OUTPUT] = "output",
+ [PINMUX_TYPE_INPUT] = "input",
+ [PINMUX_TYPE_INPUT_PULLUP] = "input bias pull up",
+ [PINMUX_TYPE_INPUT_PULLDOWN] = "input bias pull down",
+ };
+ unsigned long config;
+ int rc;
+
+ rc = sh_pfc_pinconf_get(pctldev, pin, &config);
+ if (unlikely(rc != 0))
+ return;
+
+ seq_printf(s, " %s", pinmux_type_str[config]);
}
static struct pinconf_ops sh_pfc_pinconf_ops = {
- .is_generic = true,
.pin_config_get = sh_pfc_pinconf_get,
.pin_config_set = sh_pfc_pinconf_set,
+ .pin_config_dbg_show = sh_pfc_pinconf_dbg_show,
};
static struct pinctrl_gpio_range sh_pfc_gpio_range = {
OpenPOWER on IntegriCloud