pinctrl: core: add support to configure user specified states
Laxman Dewangan [Wed, 27 Nov 2013 09:54:16 +0000 (14:54 +0530)]
Currently, pincontrol driver defines three states i.e. default, idle and
sleep. The default state get sets when the pincontrol driver gets
regsitered.

In tegra boards, we define three types of default, commpn pinmux table,
driver setting table and unused low-power pins pinmux tables.

Add the API to support the user specified state names to configure the
pinmux.

Change-Id: I0a6a234e891b5d53dbb8996db47984323463da48
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/336158
GVS: Gerrit_Virtual_Submit

drivers/pinctrl/core.c
include/linux/pinctrl/consumer.h

index 5327f35..7be3dba 100644 (file)
@@ -1020,6 +1020,65 @@ unapply_new_state:
 }
 EXPORT_SYMBOL_GPL(pinctrl_select_state);
 
+int pinctrl_configure_user_state(struct pinctrl_dev *pctldev,
+               const char *user_state_name)
+{
+       struct pinctrl_setting *setting, *setting2;
+       struct pinctrl_state *user_state;
+       int ret;
+
+       if (!pctldev || IS_ERR(pctldev->p)) {
+               pr_err("The pincontrol driver is not valid\n");
+               return -EINVAL;
+       }
+
+       user_state = pinctrl_lookup_state(pctldev->p, user_state_name);
+       if (IS_ERR(user_state)) {
+               ret = PTR_ERR(user_state);
+               dev_info(pctldev->dev, "lookup the user state %s not found\n",
+                       user_state_name);
+               return ret;
+       }
+
+       list_for_each_entry(setting, &user_state->settings, node) {
+               switch (setting->type) {
+               case PIN_MAP_TYPE_MUX_GROUP:
+                       ret = pinmux_enable_setting(setting);
+                       break;
+               case PIN_MAP_TYPE_CONFIGS_PIN:
+               case PIN_MAP_TYPE_CONFIGS_GROUP:
+                       ret = pinconf_apply_setting(setting);
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (ret < 0)
+                       goto unapply_new_state;
+       }
+       return 0;
+
+unapply_new_state:
+       dev_err(pctldev->dev, "Error applying setting, reverse things back\n");
+
+       list_for_each_entry(setting2, &user_state->settings, node) {
+               if (&setting2->node == &setting->node)
+                       break;
+               /*
+                * All we can do here is pinmux_disable_setting.
+                * That means that some pins are muxed differently now
+                * than they were before applying the setting (We can't
+                * "unmux a pin"!), but it's not a big deal since the pins
+                * are free to be muxed by another apply_setting.
+                */
+               if (setting2->type == PIN_MAP_TYPE_MUX_GROUP)
+                       pinmux_disable_setting(setting2);
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_configure_user_state);
+
 static void devm_pinctrl_release(struct device *dev, void *res)
 {
        pinctrl_put(*(struct pinctrl **)res);
index 4aad3ce..e924625 100644 (file)
@@ -21,6 +21,7 @@
 struct pinctrl;
 struct pinctrl_state;
 struct device;
+struct pinctrl_dev;
 
 #ifdef CONFIG_PINCTRL
 
@@ -36,6 +37,8 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
                                                        struct pinctrl *p,
                                                        const char *name);
 extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
+extern int pinctrl_configure_user_state(struct pinctrl_dev *pctldev,
+               const char *user_state_name);
 
 extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
 extern void devm_pinctrl_put(struct pinctrl *p);
@@ -82,6 +85,12 @@ static inline int pinctrl_select_state(struct pinctrl *p,
 {
        return 0;
 }
+static inline int pinctrl_configure_user_state(
+       struct pinctrl_dev *pctldev,
+       const char *user_state_name)
+{
+       return 0;
+}
 
 static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
 {