Merge branch 'kconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild
[firefly-linux-kernel-4.4.55.git] / drivers / pinctrl / pinctrl-tegra.c
index 2fa9bc6cd7abfcf41bc9635980d0db4d2ec6b5b2..a2e93a2b5ff487aa0dad6fc8c9f2d863e6debb07 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "core.h"
 #include "pinctrl-tegra.h"
+#include "pinctrl-utils.h"
 
 struct tegra_pmx {
        struct device *dev;
@@ -90,107 +91,6 @@ static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
 }
 #endif
 
-static int reserve_map(struct device *dev, struct pinctrl_map **map,
-                      unsigned *reserved_maps, unsigned *num_maps,
-                      unsigned reserve)
-{
-       unsigned old_num = *reserved_maps;
-       unsigned new_num = *num_maps + reserve;
-       struct pinctrl_map *new_map;
-
-       if (old_num >= new_num)
-               return 0;
-
-       new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
-       if (!new_map) {
-               dev_err(dev, "krealloc(map) failed\n");
-               return -ENOMEM;
-       }
-
-       memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
-
-       *map = new_map;
-       *reserved_maps = new_num;
-
-       return 0;
-}
-
-static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
-                      unsigned *num_maps, const char *group,
-                      const char *function)
-{
-       if (WARN_ON(*num_maps == *reserved_maps))
-               return -ENOSPC;
-
-       (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
-       (*map)[*num_maps].data.mux.group = group;
-       (*map)[*num_maps].data.mux.function = function;
-       (*num_maps)++;
-
-       return 0;
-}
-
-static int add_map_configs(struct device *dev, struct pinctrl_map **map,
-                          unsigned *reserved_maps, unsigned *num_maps,
-                          const char *group, unsigned long *configs,
-                          unsigned num_configs)
-{
-       unsigned long *dup_configs;
-
-       if (WARN_ON(*num_maps == *reserved_maps))
-               return -ENOSPC;
-
-       dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
-                             GFP_KERNEL);
-       if (!dup_configs) {
-               dev_err(dev, "kmemdup(configs) failed\n");
-               return -ENOMEM;
-       }
-
-       (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
-       (*map)[*num_maps].data.configs.group_or_pin = group;
-       (*map)[*num_maps].data.configs.configs = dup_configs;
-       (*map)[*num_maps].data.configs.num_configs = num_configs;
-       (*num_maps)++;
-
-       return 0;
-}
-
-static int add_config(struct device *dev, unsigned long **configs,
-                     unsigned *num_configs, unsigned long config)
-{
-       unsigned old_num = *num_configs;
-       unsigned new_num = old_num + 1;
-       unsigned long *new_configs;
-
-       new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
-                              GFP_KERNEL);
-       if (!new_configs) {
-               dev_err(dev, "krealloc(configs) failed\n");
-               return -ENOMEM;
-       }
-
-       new_configs[old_num] = config;
-
-       *configs = new_configs;
-       *num_configs = new_num;
-
-       return 0;
-}
-
-static void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
-                                     struct pinctrl_map *map,
-                                     unsigned num_maps)
-{
-       int i;
-
-       for (i = 0; i < num_maps; i++)
-               if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
-                       kfree(map[i].data.configs.configs);
-
-       kfree(map);
-}
-
 static const struct cfg_param {
        const char *property;
        enum tegra_pinconf_param param;
@@ -212,12 +112,13 @@ static const struct cfg_param {
        {"nvidia,drive-type",           TEGRA_PINCONF_PARAM_DRIVE_TYPE},
 };
 
-static int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
+static int tegra_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
                                           struct device_node *np,
                                           struct pinctrl_map **map,
                                           unsigned *reserved_maps,
                                           unsigned *num_maps)
 {
+       struct device *dev = pctldev->dev;
        int ret, i;
        const char *function;
        u32 val;
@@ -241,7 +142,8 @@ static int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
                ret = of_property_read_u32(np, cfg_params[i].property, &val);
                if (!ret) {
                        config = TEGRA_PINCONF_PACK(cfg_params[i].param, val);
-                       ret = add_config(dev, &configs, &num_configs, config);
+                       ret = pinctrl_utils_add_config(pctldev, &configs,
+                                       &num_configs, config);
                        if (ret < 0)
                                goto exit;
                /* EINVAL=missing, which is fine since it's optional */
@@ -263,22 +165,25 @@ static int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
        }
        reserve *= ret;
 
-       ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
+       ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps,
+                                       num_maps, reserve);
        if (ret < 0)
                goto exit;
 
        of_property_for_each_string(np, "nvidia,pins", prop, group) {
                if (function) {
-                       ret = add_map_mux(map, reserved_maps, num_maps,
-                                         group, function);
+                       ret = pinctrl_utils_add_map_mux(pctldev, map,
+                                       reserved_maps, num_maps, group,
+                                       function);
                        if (ret < 0)
                                goto exit;
                }
 
                if (num_configs) {
-                       ret = add_map_configs(dev, map, reserved_maps,
-                                             num_maps, group, configs,
-                                             num_configs);
+                       ret = pinctrl_utils_add_map_configs(pctldev, map,
+                                       reserved_maps, num_maps, group,
+                                       configs, num_configs,
+                                       PIN_MAP_TYPE_CONFIGS_GROUP);
                        if (ret < 0)
                                goto exit;
                }
@@ -305,10 +210,11 @@ static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
        *num_maps = 0;
 
        for_each_child_of_node(np_config, np) {
-               ret = tegra_pinctrl_dt_subnode_to_map(pctldev->dev, np, map,
+               ret = tegra_pinctrl_dt_subnode_to_map(pctldev, np, map,
                                                      &reserved_maps, num_maps);
                if (ret < 0) {
-                       tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps);
+                       pinctrl_utils_dt_free_map(pctldev, *map,
+                               *num_maps);
                        return ret;
                }
        }
@@ -324,7 +230,7 @@ static const struct pinctrl_ops tegra_pinctrl_ops = {
        .pin_dbg_show = tegra_pinctrl_pin_dbg_show,
 #endif
        .dt_node_to_map = tegra_pinctrl_dt_node_to_map,
-       .dt_free_map = tegra_pinctrl_dt_free_map,
+       .dt_free_map = pinctrl_utils_dt_free_map,
 };
 
 static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
@@ -530,7 +436,8 @@ static int tegra_pinconf_get(struct pinctrl_dev *pctldev,
 }
 
 static int tegra_pinconf_set(struct pinctrl_dev *pctldev,
-                            unsigned pin, unsigned long config)
+                            unsigned pin, unsigned long *configs,
+                            unsigned num_configs)
 {
        dev_err(pctldev->dev, "pin_config_set op not supported\n");
        return -ENOTSUPP;
@@ -565,51 +472,57 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
 }
 
 static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
-                                  unsigned group, unsigned long config)
+                                  unsigned group, unsigned long *configs,
+                                  unsigned num_configs)
 {
        struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-       enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config);
-       u16 arg = TEGRA_PINCONF_UNPACK_ARG(config);
+       enum tegra_pinconf_param param;
+       u16 arg;
        const struct tegra_pingroup *g;
-       int ret;
+       int ret, i;
        s8 bank, bit, width;
        s16 reg;
        u32 val, mask;
 
        g = &pmx->soc->groups[group];
 
-       ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
-                               &width);
-       if (ret < 0)
-               return ret;
+       for (i = 0; i < num_configs; i++) {
+               param = TEGRA_PINCONF_UNPACK_PARAM(configs[i]);
+               arg = TEGRA_PINCONF_UNPACK_ARG(configs[i]);
 
-       val = pmx_readl(pmx, bank, reg);
+               ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
+                                       &width);
+               if (ret < 0)
+                       return ret;
 
-       /* LOCK can't be cleared */
-       if (param == TEGRA_PINCONF_PARAM_LOCK) {
-               if ((val & BIT(bit)) && !arg) {
-                       dev_err(pctldev->dev, "LOCK bit cannot be cleared\n");
-                       return -EINVAL;
+               val = pmx_readl(pmx, bank, reg);
+
+               /* LOCK can't be cleared */
+               if (param == TEGRA_PINCONF_PARAM_LOCK) {
+                       if ((val & BIT(bit)) && !arg) {
+                               dev_err(pctldev->dev, "LOCK bit cannot be cleared\n");
+                               return -EINVAL;
+                       }
                }
-       }
 
-       /* Special-case Boolean values; allow any non-zero as true */
-       if (width == 1)
-               arg = !!arg;
+               /* Special-case Boolean values; allow any non-zero as true */
+               if (width == 1)
+                       arg = !!arg;
 
-       /* Range-check user-supplied value */
-       mask = (1 << width) - 1;
-       if (arg & ~mask) {
-               dev_err(pctldev->dev,
-                       "config %lx: %x too big for %d bit register\n",
-                       config, arg, width);
-               return -EINVAL;
-       }
+               /* Range-check user-supplied value */
+               mask = (1 << width) - 1;
+               if (arg & ~mask) {
+                       dev_err(pctldev->dev,
+                               "config %lx: %x too big for %d bit register\n",
+                               configs[i], arg, width);
+                       return -EINVAL;
+               }
 
-       /* Update register */
-       val &= ~(mask << bit);
-       val |= arg << bit;
-       pmx_writel(pmx, val, bank, reg);
+               /* Update register */
+               val &= ~(mask << bit);
+               val |= arg << bit;
+               pmx_writel(pmx, val, bank, reg);
+       } /* for each config */
 
        return 0;
 }
@@ -737,25 +650,9 @@ int tegra_pinctrl_probe(struct platform_device *pdev,
 
        for (i = 0; i < pmx->nbanks; i++) {
                res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-               if (!res) {
-                       dev_err(&pdev->dev, "Missing MEM resource\n");
-                       return -ENODEV;
-               }
-
-               if (!devm_request_mem_region(&pdev->dev, res->start,
-                                           resource_size(res),
-                                           dev_name(&pdev->dev))) {
-                       dev_err(&pdev->dev,
-                               "Couldn't request MEM resource %d\n", i);
-                       return -ENODEV;
-               }
-
-               pmx->regs[i] = devm_ioremap(&pdev->dev, res->start,
-                                           resource_size(res));
-               if (!pmx->regs[i]) {
-                       dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i);
-                       return -ENODEV;
-               }
+               pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(pmx->regs[i]))
+                       return PTR_ERR(pmx->regs[i]);
        }
 
        pmx->pctl = pinctrl_register(&tegra_pinctrl_desc, &pdev->dev, pmx);