drivers: pinctrl sleep and idle states in the core
authorLinus Walleij <linus.walleij@linaro.org>
Wed, 5 Jun 2013 13:30:33 +0000 (15:30 +0200)
committerLinus Walleij <linus.walleij@linaro.org>
Sun, 16 Jun 2013 09:56:52 +0000 (11:56 +0200)
If a device have sleep and idle states in addition to the
default state, look up these in the core and stash them in
the pinctrl state container.

Add accessor functions for pinctrl consumers to put the pins
into "default", "sleep" and "idle" states passing nothing but
the struct device * affected.

Solution suggested by Kevin Hilman, Mark Brown and Dmitry
Torokhov in response to a patch series from Hebbar
Gururaja.

Cc: Hebbar Gururaja <gururaja.hebbar@ti.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Acked-by: Wolfram Sang <wsa@the-dreams.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Mark Brown <broonie@kernel.org>
Reviewed-by: Kevin Hilman <khilman@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/base/pinctrl.c
drivers/pinctrl/core.c
include/linux/pinctrl/consumer.h
include/linux/pinctrl/devinfo.h

index 67a274e8672703bc17bb57e96f3262b4effe184e..5fb74b43848e21369670b4503fdee13b0d4f255e 100644 (file)
@@ -48,6 +48,25 @@ int pinctrl_bind_pins(struct device *dev)
                goto cleanup_get;
        }
 
+#ifdef CONFIG_PM
+       /*
+        * If power management is enabled, we also look for the optional
+        * sleep and idle pin states, with semantics as defined in
+        * <linux/pinctrl/pinctrl-state.h>
+        */
+       dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,
+                                       PINCTRL_STATE_SLEEP);
+       if (IS_ERR(dev->pins->sleep_state))
+               /* Not supplying this state is perfectly legal */
+               dev_dbg(dev, "no sleep pinctrl state\n");
+
+       dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,
+                                       PINCTRL_STATE_IDLE);
+       if (IS_ERR(dev->pins->idle_state))
+               /* Not supplying this state is perfectly legal */
+               dev_dbg(dev, "no idle pinctrl state\n");
+#endif
+
        return 0;
 
        /*
index 1f9608bd237ebccec0eeeb3f3dfea8751de73e50..dca9208f54633dc404956a74a1afd39fe7f09e85 100644 (file)
@@ -1196,6 +1196,67 @@ int pinctrl_force_default(struct pinctrl_dev *pctldev)
 }
 EXPORT_SYMBOL_GPL(pinctrl_force_default);
 
+#ifdef CONFIG_PM
+
+/**
+ * pinctrl_pm_select_default_state() - select default pinctrl state for PM
+ * @dev: device to select default state for
+ */
+int pinctrl_pm_select_default_state(struct device *dev)
+{
+       struct dev_pin_info *pins = dev->pins;
+       int ret;
+
+       if (!pins)
+               return 0;
+       if (IS_ERR(pins->default_state))
+               return 0; /* No default state */
+       ret = pinctrl_select_state(pins->p, pins->default_state);
+       if (ret)
+               dev_err(dev, "failed to activate default pinctrl state\n");
+       return ret;
+}
+
+/**
+ * pinctrl_pm_select_sleep_state() - select sleep pinctrl state for PM
+ * @dev: device to select sleep state for
+ */
+int pinctrl_pm_select_sleep_state(struct device *dev)
+{
+       struct dev_pin_info *pins = dev->pins;
+       int ret;
+
+       if (!pins)
+               return 0;
+       if (IS_ERR(pins->sleep_state))
+               return 0; /* No sleep state */
+       ret = pinctrl_select_state(pins->p, pins->sleep_state);
+       if (ret)
+               dev_err(dev, "failed to activate pinctrl sleep state\n");
+       return ret;
+}
+
+/**
+ * pinctrl_pm_select_idle_state() - select idle pinctrl state for PM
+ * @dev: device to select idle state for
+ */
+int pinctrl_pm_select_idle_state(struct device *dev)
+{
+       struct dev_pin_info *pins = dev->pins;
+       int ret;
+
+       if (!pins)
+               return 0;
+       if (IS_ERR(pins->idle_state))
+               return 0; /* No idle state */
+       ret = pinctrl_select_state(pins->p, pins->idle_state);
+       if (ret)
+               dev_err(dev, "failed to activate pinctrl idle state\n");
+       return ret;
+}
+
+#endif
+
 #ifdef CONFIG_DEBUG_FS
 
 static int pinctrl_pins_show(struct seq_file *s, void *what)
index 4aad3cea69ae3034f451a0d67b406483d5d7e9e9..0f32f10e347d9dbd7e3a7411054873bf7d294b0f 100644 (file)
@@ -40,6 +40,25 @@ extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
 extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
 extern void devm_pinctrl_put(struct pinctrl *p);
 
+#ifdef CONFIG_PM
+extern int pinctrl_pm_select_default_state(struct device *dev);
+extern int pinctrl_pm_select_sleep_state(struct device *dev);
+extern int pinctrl_pm_select_idle_state(struct device *dev);
+#else
+static inline int pinctrl_pm_select_default_state(struct device *dev)
+{
+       return 0;
+}
+static inline int pinctrl_pm_select_sleep_state(struct device *dev)
+{
+       return 0;
+}
+static inline int pinctrl_pm_select_idle_state(struct device *dev)
+{
+       return 0;
+}
+#endif
+
 #else /* !CONFIG_PINCTRL */
 
 static inline int pinctrl_request_gpio(unsigned gpio)
@@ -199,6 +218,21 @@ static inline int pin_config_group_set(const char *dev_name,
        return 0;
 }
 
+static inline int pinctrl_pm_select_default_state(struct device *dev)
+{
+       return 0;
+}
+
+static inline int pinctrl_pm_select_sleep_state(struct device *dev)
+{
+       return 0;
+}
+
+static inline int pinctrl_pm_select_idle_state(struct device *dev)
+{
+       return 0;
+}
+
 #endif
 
 #endif /* __LINUX_PINCTRL_CONSUMER_H */
index 6e5f8a985ea7ddf6690679c5908b348d863ac735..281cb91ddcf54c3a5275acbbc30abd9f0e9d11b1 100644 (file)
 struct dev_pin_info {
        struct pinctrl *p;
        struct pinctrl_state *default_state;
+#ifdef CONFIG_PM
+       struct pinctrl_state *sleep_state;
+       struct pinctrl_state *idle_state;
+#endif
 };
 
 extern int pinctrl_bind_pins(struct device *dev);