These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / pinctrl / sh-pfc / pinctrl.c
index 072e7c6..863c3e3 100644 (file)
@@ -40,6 +40,10 @@ struct sh_pfc_pinctrl {
 
        struct pinctrl_pin_desc *pins;
        struct sh_pfc_pin_config *configs;
+
+       const char *func_prop_name;
+       const char *groups_prop_name;
+       const char *pins_prop_name;
 };
 
 static int sh_pfc_get_groups_count(struct pinctrl_dev *pctldev)
@@ -96,10 +100,13 @@ static int sh_pfc_map_add_config(struct pinctrl_map *map,
        return 0;
 }
 
-static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
+static int sh_pfc_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+                                   struct device_node *np,
                                    struct pinctrl_map **map,
                                    unsigned int *num_maps, unsigned int *index)
 {
+       struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
+       struct device *dev = pmx->pfc->dev;
        struct pinctrl_map *maps = *map;
        unsigned int nmaps = *num_maps;
        unsigned int idx = *index;
@@ -113,10 +120,27 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
        const char *pin;
        int ret;
 
+       /* Support both the old Renesas-specific properties and the new standard
+        * properties. Mixing old and new properties isn't allowed, neither
+        * inside a subnode nor across subnodes.
+        */
+       if (!pmx->func_prop_name) {
+               if (of_find_property(np, "groups", NULL) ||
+                   of_find_property(np, "pins", NULL)) {
+                       pmx->func_prop_name = "function";
+                       pmx->groups_prop_name = "groups";
+                       pmx->pins_prop_name = "pins";
+               } else {
+                       pmx->func_prop_name = "renesas,function";
+                       pmx->groups_prop_name = "renesas,groups";
+                       pmx->pins_prop_name = "renesas,pins";
+               }
+       }
+
        /* Parse the function and configuration properties. At least a function
         * or one configuration must be specified.
         */
-       ret = of_property_read_string(np, "renesas,function", &function);
+       ret = of_property_read_string(np, pmx->func_prop_name, &function);
        if (ret < 0 && ret != -EINVAL) {
                dev_err(dev, "Invalid function in DT\n");
                return ret;
@@ -129,11 +153,12 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
        if (!function && num_configs == 0) {
                dev_err(dev,
                        "DT node must contain at least a function or config\n");
+               ret = -ENODEV;
                goto done;
        }
 
        /* Count the number of pins and groups and reallocate mappings. */
-       ret = of_property_count_strings(np, "renesas,pins");
+       ret = of_property_count_strings(np, pmx->pins_prop_name);
        if (ret == -EINVAL) {
                num_pins = 0;
        } else if (ret < 0) {
@@ -143,7 +168,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
                num_pins = ret;
        }
 
-       ret = of_property_count_strings(np, "renesas,groups");
+       ret = of_property_count_strings(np, pmx->groups_prop_name);
        if (ret == -EINVAL) {
                num_groups = 0;
        } else if (ret < 0) {
@@ -174,7 +199,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
        *num_maps = nmaps;
 
        /* Iterate over pins and groups and create the mappings. */
-       of_property_for_each_string(np, "renesas,groups", prop, group) {
+       of_property_for_each_string(np, pmx->groups_prop_name, prop, group) {
                if (function) {
                        maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
                        maps[idx].data.mux.group = group;
@@ -198,7 +223,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
                goto done;
        }
 
-       of_property_for_each_string(np, "renesas,pins", prop, pin) {
+       of_property_for_each_string(np, pmx->pins_prop_name, prop, pin) {
                ret = sh_pfc_map_add_config(&maps[idx], pin,
                                            PIN_MAP_TYPE_CONFIGS_PIN,
                                            configs, num_configs);
@@ -246,7 +271,7 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev,
        index = 0;
 
        for_each_child_of_node(np, child) {
-               ret = sh_pfc_dt_subnode_to_map(dev, child, map, num_maps,
+               ret = sh_pfc_dt_subnode_to_map(pctldev, child, map, num_maps,
                                               &index);
                if (ret < 0)
                        goto done;
@@ -254,7 +279,8 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev,
 
        /* If no mapping has been found in child nodes try the config node. */
        if (*num_maps == 0) {
-               ret = sh_pfc_dt_subnode_to_map(dev, np, map, num_maps, &index);
+               ret = sh_pfc_dt_subnode_to_map(pctldev, np, map, num_maps,
+                                              &index);
                if (ret < 0)
                        goto done;
        }
@@ -465,6 +491,9 @@ static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin,
        case PIN_CONFIG_BIAS_PULL_DOWN:
                return pin->configs & SH_PFC_PIN_CFG_PULL_DOWN;
 
+       case PIN_CONFIG_POWER_SOURCE:
+               return pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE;
+
        default:
                return false;
        }
@@ -477,7 +506,6 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin,
        struct sh_pfc *pfc = pmx->pfc;
        enum pin_config_param param = pinconf_to_config_param(*config);
        unsigned long flags;
-       unsigned int bias;
 
        if (!sh_pfc_pinconf_validate(pfc, _pin, param))
                return -ENOTSUPP;
@@ -485,7 +513,9 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin,
        switch (param) {
        case PIN_CONFIG_BIAS_DISABLE:
        case PIN_CONFIG_BIAS_PULL_UP:
-       case PIN_CONFIG_BIAS_PULL_DOWN:
+       case PIN_CONFIG_BIAS_PULL_DOWN: {
+               unsigned int bias;
+
                if (!pfc->info->ops || !pfc->info->ops->get_bias)
                        return -ENOTSUPP;
 
@@ -498,6 +528,24 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin,
 
                *config = 0;
                break;
+       }
+
+       case PIN_CONFIG_POWER_SOURCE: {
+               int ret;
+
+               if (!pfc->info->ops || !pfc->info->ops->get_io_voltage)
+                       return -ENOTSUPP;
+
+               spin_lock_irqsave(&pfc->lock, flags);
+               ret = pfc->info->ops->get_io_voltage(pfc, _pin);
+               spin_unlock_irqrestore(&pfc->lock, flags);
+
+               if (ret < 0)
+                       return ret;
+
+               *config = ret;
+               break;
+       }
 
        default:
                return -ENOTSUPP;
@@ -534,6 +582,24 @@ static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin,
 
                        break;
 
+               case PIN_CONFIG_POWER_SOURCE: {
+                       unsigned int arg =
+                               pinconf_to_config_argument(configs[i]);
+                       int ret;
+
+                       if (!pfc->info->ops || !pfc->info->ops->set_io_voltage)
+                               return -ENOTSUPP;
+
+                       spin_lock_irqsave(&pfc->lock, flags);
+                       ret = pfc->info->ops->set_io_voltage(pfc, _pin, arg);
+                       spin_unlock_irqrestore(&pfc->lock, flags);
+
+                       if (ret)
+                               return ret;
+
+                       break;
+               }
+
                default:
                        return -ENOTSUPP;
                }
@@ -625,8 +691,8 @@ int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
        pmx->pctl_desc.npins = pfc->info->nr_pins;
 
        pmx->pctl = pinctrl_register(&pmx->pctl_desc, pfc->dev, pmx);
-       if (pmx->pctl == NULL)
-               return -EINVAL;
+       if (IS_ERR(pmx->pctl))
+               return PTR_ERR(pmx->pctl);
 
        return 0;
 }