diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 23:24:33 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 23:24:33 (GMT) |
commit | aa7054f5a5a9ff728ce291cb103afa19f4f849eb (patch) | |
tree | 83ddb460e2dca239f35d64a33054c100fe7f9e5d /drivers/pinctrl/pinctrl-tegra.c | |
parent | 816434ec4a674fcdb3c2221a6dffdc8f34020550 (diff) | |
parent | c9e3b2d8f75d84c7b333761471f6cef98ec4429a (diff) | |
download | linux-fsl-qoriq-aa7054f5a5a9ff728ce291cb103afa19f4f849eb.tar.xz |
Merge tag 'pinctrl-v3.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pin control changes from Linus Walleij:
"Here is the bulk of pin control changes for the v3.12 series. Most of
the relevant information is in the tag.
I merged in v3.11-rc7 last week to get rid of a largeish conflict
within the sunxi (AllWinner) driver in linux-next and fix up the
non-trivial merge the right way. That driver had a rather large fix
adding locking late in the release cycle.
Overall the bulk changes this time is cleanups and refactorings and
not much new features, which is nice.
- Refactorings for generic pin config handling in the core.
- Factor out a set of device tree utilities for use in all drivers,
to parse and allocate maps from the device tree.
- Some fixes to the core such as more nitpicky locking.
- Pushed down config array iteration into the drivers.
This patch is necessary for drivers that want to iterate over
configs and pile up a stack of alterations to the same register(s),
or if the driver wants to take a local spinlock when committing the
configuration.
- A new driver for the Texas Instruments Palmas PMIC by Laxman
Dewangan. This is used on the Tegra systems.
- A major cleanup and modernization of the PFC (Super Hitachi and ARM
SHmobile) pin controller and subdrivers.
- Support for the A20 and A31 sunxi (AllWinner) SoCs.
- A huge pile of fixes and cleanups: Axel Lin, Jingoo Han Dan
Carpenter, Julia Lawall and Sachin Kamat did an excellent job here"
* tag 'pinctrl-v3.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (124 commits)
pinctrl: sunxi: Fix off-by-one for valid offset range checking
pinctrl: sunxi: drop lock on error path
pinctrl: pinconf-generic: Remove ti prefix in dev_err messages
pinctrl: rockchip: Implement .request() and .free() callbacks
pinctrl: at91: fix get_pullup/down function return
pinctrl: sh-pfc: remove unnecessary platform_set_drvdata()
pinctrl: Add s5pv210 support to pinctrl-exynos
pinctrl: utils: include export.h to avoid warnings
pinctrl: s3c24xx: off by one in s3c24xx_eint_init()
pinctrl: mvebu: testing the wrong variable
pinctrl: abx500: fix bitwise AND test
pinctrl: mvebu: Convert to use devm_ioremap_resource
pinctrl: Pass all configs to driver on pin_config_set()
pinctrl: tz1090-pdc: Convert to devm_ioremap_resource
pinctrl: tz1090: Convert to devm_ioremap_resource
pinctrl: tegra: Convert to devm_ioremap_resource
pinctrl: rockchip: Simplify pin_to_bank equation
pinctrl: spear: Convert to devm_ioremap_resource
pinctrl: rockchip: Remove of_match_ptr macro for DT only driver
pinctrl: palmas: PINCTRL_PALMAS needs to select PINMUX
...
Diffstat (limited to 'drivers/pinctrl/pinctrl-tegra.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-tegra.c | 221 |
1 files changed, 59 insertions, 162 deletions
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index 2fa9bc6..a2e93a2 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, ®, &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, ®, &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); |