pinctrl: Pass all configs to driver on pin_config_set()
authorMark Brown <broonie@linaro.org>
Fri, 4 Apr 2014 16:16:57 +0000 (17:16 +0100)
committerMark Brown <broonie@linaro.org>
Fri, 4 Apr 2014 19:20:07 +0000 (20:20 +0100)
When setting pin configuration in the pinctrl framework, pin_config_set() or
pin_config_group_set() is called in a loop to set one configuration at a time
for the specified pin or group.

This patch 1) removes the loop and 2) changes the API to pass the whole pin
config array to the driver.  It is now up to the driver to loop through the
configs.  This allows the driver to potentially combine configs and reduce the
number of writes to pin config registers.

All c files changed have been build-tested to verify the change compiles and
that the corresponding .o is successfully generated.

[For LSK this has been modified such that the old API is still present and
instead a new pinconf_set_bulk() callback has been added in order to avoid
breaking other users in the stable kernel -- broonie]

Signed-off-by: Sherman Yin <syin@broadcom.com>
Reviewed-by: Christian Daudt <csd@broadcom.com>
Reviewed-by: Matt Porter <matt.porter@linaro.org>
Tested-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
(cherry picked from commit 03b054e9696c3cbd3d5905ec96da15acd0a2fe8d)
Signed-off-by: Mark Brown <broonie@linaro.org>
drivers/pinctrl/pinconf.c
include/linux/pinctrl/pinconf.h

index e875f21a5908a7aca89ca13fa75c4dcab5e7b0d3..ad30263a74106c993043fe1b5b44ced5ac4140ed 100644 (file)
@@ -158,7 +158,7 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
 {
        struct pinctrl_dev *pctldev = setting->pctldev;
        const struct pinconf_ops *ops = pctldev->desc->confops;
-       int i, ret;
+       int ret, i;
 
        if (!ops) {
                dev_err(pctldev->dev, "missing confops\n");
@@ -167,39 +167,66 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
 
        switch (setting->type) {
        case PIN_MAP_TYPE_CONFIGS_PIN:
-               if (!ops->pin_config_set) {
+               if (!ops->pin_config_set && !ops->pin_config_set_bulk) {
                        dev_err(pctldev->dev, "missing pin_config_set op\n");
                        return -EINVAL;
                }
-               for (i = 0; i < setting->data.configs.num_configs; i++) {
-                       ret = ops->pin_config_set(pctldev,
+               if (ops->pin_config_group_set_bulk) {
+                       ret = ops->pin_config_group_set_bulk(pctldev,
                                        setting->data.configs.group_or_pin,
-                                       setting->data.configs.configs[i]);
+                                       setting->data.configs.configs,
+                                       setting->data.configs.num_configs);
                        if (ret < 0) {
                                dev_err(pctldev->dev,
-                                       "pin_config_set op failed for pin %d config %08lx\n",
-                                       setting->data.configs.group_or_pin,
-                                       setting->data.configs.configs[i]);
+                                       "pin_config_set op failed for pin %d\n",
+                                       setting->data.configs.group_or_pin);
                                return ret;
                        }
+               } else if (ops->pin_config_set) {
+                       for (i = 0; i < setting->data.configs.num_configs; i++) {
+                               ret = ops->pin_config_set(pctldev,
+                                                         setting->data.configs.group_or_pin,
+                                                         setting->data.configs.configs[i]);
+                               if (ret < 0) {
+                                       dev_err(pctldev->dev,
+                                               "pin_config_set op failed for pin %d config %08lx\n",
+                                               setting->data.configs.group_or_pin,
+                                               setting->data.configs.configs[i]);
+                                       return ret;
+                               }
+                       }
                }
                break;
        case PIN_MAP_TYPE_CONFIGS_GROUP:
-               if (!ops->pin_config_group_set) {
+               if (!ops->pin_config_group_set &&
+                   !ops->pin_config_group_set_bulk) {
                        dev_err(pctldev->dev,
                                "missing pin_config_group_set op\n");
                        return -EINVAL;
                }
-               for (i = 0; i < setting->data.configs.num_configs; i++) {
-                       ret = ops->pin_config_group_set(pctldev,
+               if (ops->pin_config_group_set_bulk) {
+                       ret = ops->pin_config_group_set_bulk(pctldev,
                                        setting->data.configs.group_or_pin,
-                                       setting->data.configs.configs[i]);
+                                       setting->data.configs.configs,
+                                       setting->data.configs.num_configs);
                        if (ret < 0) {
                                dev_err(pctldev->dev,
-                                       "pin_config_group_set op failed for group %d config %08lx\n",
+                                       "pin_config_group_set op failed for group %d\n",
+                                       setting->data.configs.group_or_pin);
+                               return ret;
+                       }
+               } else if (ops->pin_config_group_set) {
+                       for (i = 0; i < setting->data.configs.num_configs; i++) {
+                               ret = ops->pin_config_group_set(pctldev,
                                        setting->data.configs.group_or_pin,
                                        setting->data.configs.configs[i]);
-                               return ret;
+                               if (ret < 0) {
+                                       dev_err(pctldev->dev,
+                                               "pin_config_group_set op failed for group %d config %08lx\n",
+                                               setting->data.configs.group_or_pin,
+                                               setting->data.configs.configs[i]);
+                                       return ret;
+                               }
                        }
                }
                break;
index 1ad4f31ef6b8e2074546443465338b8f04b04e69..e6a68e476aef9f858bd44ffe4bd24f87f000b4ed 100644 (file)
@@ -48,12 +48,20 @@ struct pinconf_ops {
        int (*pin_config_set) (struct pinctrl_dev *pctldev,
                               unsigned pin,
                               unsigned long config);
+       int (*pin_config_set_bulk) (struct pinctrl_dev *pctldev,
+                                   unsigned pin,
+                                   unsigned long *configs,
+                                   unsigned num_configs);
        int (*pin_config_group_get) (struct pinctrl_dev *pctldev,
                                     unsigned selector,
                                     unsigned long *config);
        int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
                                     unsigned selector,
                                     unsigned long config);
+       int (*pin_config_group_set_bulk) (struct pinctrl_dev *pctldev,
+                                         unsigned selector,
+                                         unsigned long *configs,
+                                         unsigned num_configs);
        int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,
                                           const char *arg,
                                           unsigned long *config);