summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/pinctrl-tegra.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/pinctrl-tegra.c')
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c221
1 files changed, 59 insertions, 162 deletions
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 2fa9bc6cd7ab..a2e93a2b5ff4 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -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);