Merge remote-tracking branch 'lsk/v3.10/topic/gator' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / drivers / pinctrl / pinconf.c
index 694c3ace45204c11eeed4518f82b901c92489b59..596a2522a6b1750b2c4c94c22f7c4177847f5bb4 100644 (file)
@@ -35,7 +35,9 @@ int pinconf_check_ops(struct pinctrl_dev *pctldev)
                return -EINVAL;
        }
        /* We have to be able to config the pins in SOME way */
-       if (!ops->pin_config_set && !ops->pin_config_group_set) {
+       if (!ops->pin_config_set && !ops->pin_config_group_set
+               && !ops->pin_config_set_bulk
+               && !ops->pin_config_group_set_bulk) {
                dev_err(pctldev->dev,
                        "pinconf has to be able to set a pins config\n");
                return -EINVAL;
@@ -75,98 +77,6 @@ int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
        return ops->pin_config_get(pctldev, pin, config);
 }
 
-/**
- * pin_config_get() - get the configuration of a single pin parameter
- * @dev_name: name of the pin controller device for this pin
- * @name: name of the pin to get the config for
- * @config: the config pointed to by this argument will be filled in with the
- *     current pin state, it can be used directly by drivers as a numeral, or
- *     it can be dereferenced to any struct.
- */
-int pin_config_get(const char *dev_name, const char *name,
-                         unsigned long *config)
-{
-       struct pinctrl_dev *pctldev;
-       int pin;
-
-       pctldev = get_pinctrl_dev_from_devname(dev_name);
-       if (!pctldev) {
-               pin = -EINVAL;
-               return pin;
-       }
-
-       mutex_lock(&pctldev->mutex);
-
-       pin = pin_get_from_name(pctldev, name);
-       if (pin < 0)
-               goto unlock;
-
-       pin = pin_config_get_for_pin(pctldev, pin, config);
-
-unlock:
-       mutex_unlock(&pctldev->mutex);
-       return pin;
-}
-EXPORT_SYMBOL(pin_config_get);
-
-static int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
-                          unsigned long config)
-{
-       const struct pinconf_ops *ops = pctldev->desc->confops;
-       int ret;
-
-       if (!ops || !ops->pin_config_set) {
-               dev_err(pctldev->dev, "cannot configure pin, missing "
-                       "config function in driver\n");
-               return -EINVAL;
-       }
-
-       ret = ops->pin_config_set(pctldev, pin, config);
-       if (ret) {
-               dev_err(pctldev->dev,
-                       "unable to set pin configuration on pin %d\n", pin);
-               return ret;
-       }
-
-       return 0;
-}
-
-/**
- * pin_config_set() - set the configuration of a single pin parameter
- * @dev_name: name of pin controller device for this pin
- * @name: name of the pin to set the config for
- * @config: the config in this argument will contain the desired pin state, it
- *     can be used directly by drivers as a numeral, or it can be dereferenced
- *     to any struct.
- */
-int pin_config_set(const char *dev_name, const char *name,
-                  unsigned long config)
-{
-       struct pinctrl_dev *pctldev;
-       int pin, ret;
-
-       pctldev = get_pinctrl_dev_from_devname(dev_name);
-       if (!pctldev) {
-               ret = -EINVAL;
-               return ret;
-       }
-
-       mutex_lock(&pctldev->mutex);
-
-       pin = pin_get_from_name(pctldev, name);
-       if (pin < 0) {
-               ret = pin;
-               goto unlock;
-       }
-
-       ret = pin_config_set_for_pin(pctldev, pin, config);
-
-unlock:
-       mutex_unlock(&pctldev->mutex);
-       return ret;
-}
-EXPORT_SYMBOL(pin_config_set);
-
 int pin_config_group_get(const char *dev_name, const char *pin_group,
                         unsigned long *config)
 {
@@ -204,88 +114,6 @@ unlock:
        mutex_unlock(&pctldev->mutex);
        return ret;
 }
-EXPORT_SYMBOL(pin_config_group_get);
-
-int pin_config_group_set(const char *dev_name, const char *pin_group,
-                        unsigned long config)
-{
-       struct pinctrl_dev *pctldev;
-       const struct pinconf_ops *ops;
-       const struct pinctrl_ops *pctlops;
-       int selector;
-       const unsigned *pins;
-       unsigned num_pins;
-       int ret;
-       int i;
-
-       pctldev = get_pinctrl_dev_from_devname(dev_name);
-       if (!pctldev) {
-               ret = -EINVAL;
-               return ret;
-       }
-
-       mutex_lock(&pctldev->mutex);
-
-       ops = pctldev->desc->confops;
-       pctlops = pctldev->desc->pctlops;
-
-       if (!ops || (!ops->pin_config_group_set && !ops->pin_config_set)) {
-               dev_err(pctldev->dev, "cannot configure pin group, missing "
-                       "config function in driver\n");
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       selector = pinctrl_get_group_selector(pctldev, pin_group);
-       if (selector < 0) {
-               ret = selector;
-               goto unlock;
-       }
-
-       ret = pctlops->get_group_pins(pctldev, selector, &pins, &num_pins);
-       if (ret) {
-               dev_err(pctldev->dev, "cannot configure pin group, error "
-                       "getting pins\n");
-               goto unlock;
-       }
-
-       /*
-        * If the pin controller supports handling entire groups we use that
-        * capability.
-        */
-       if (ops->pin_config_group_set) {
-               ret = ops->pin_config_group_set(pctldev, selector, config);
-               /*
-                * If the pin controller prefer that a certain group be handled
-                * pin-by-pin as well, it returns -EAGAIN.
-                */
-               if (ret != -EAGAIN)
-                       goto unlock;
-       }
-
-       /*
-        * If the controller cannot handle entire groups, we configure each pin
-        * individually.
-        */
-       if (!ops->pin_config_set) {
-               ret = 0;
-               goto unlock;
-       }
-
-       for (i = 0; i < num_pins; i++) {
-               ret = ops->pin_config_set(pctldev, pins[i], config);
-               if (ret < 0)
-                       goto unlock;
-       }
-
-       ret = 0;
-
-unlock:
-       mutex_unlock(&pctldev->mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL(pin_config_group_set);
 
 int pinconf_map_to_setting(struct pinctrl_map const *map,
                          struct pinctrl_setting *setting)
@@ -332,7 +160,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");
@@ -341,39 +169,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_set_bulk) {
+                       ret = ops->pin_config_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_bulk 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_bulk 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;