diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 16:24:33 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 16:24:33 -0700 |
commit | aa7054f5a5a9ff728ce291cb103afa19f4f849eb (patch) | |
tree | 83ddb460e2dca239f35d64a33054c100fe7f9e5d /drivers | |
parent | 816434ec4a674fcdb3c2221a6dffdc8f34020550 (diff) | |
parent | c9e3b2d8f75d84c7b333761471f6cef98ec4429a (diff) |
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')
63 files changed, 9030 insertions, 5707 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 5a8ad5139312..b6e864e8c9e8 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -61,7 +61,7 @@ config PINCTRL_AT91 config PINCTRL_BAYTRAIL bool "Intel Baytrail GPIO pin control" depends on GPIOLIB && ACPI && X86 - select IRQ_DOMAIN + select IRQ_DOMAIN help driver for memory mapped GPIO functionality on Intel Baytrail platforms. Supports 3 banks with 102, 28 and 44 gpios. @@ -252,7 +252,7 @@ config PINCTRL_SAMSUNG config PINCTRL_EXYNOS bool "Pinctrl driver data for Samsung EXYNOS SoCs other than 5440" - depends on OF && GPIOLIB && ARCH_EXYNOS + depends on OF && GPIOLIB && (ARCH_EXYNOS || ARCH_S5PV210) select PINCTRL_SAMSUNG config PINCTRL_EXYNOS5440 @@ -261,6 +261,17 @@ config PINCTRL_EXYNOS5440 select PINMUX select PINCONF +config PINCTRL_PALMAS + bool "Pinctrl driver for the PALMAS Series MFD devices" + depends on OF && MFD_PALMAS + select PINMUX + select GENERIC_PINCONF + help + Palmas device supports the configuration of pins for different + functionality. This driver supports the pinmux, push-pull and + open drain configuration for the Palmas series devices like + TPS65913, TPS80036 etc. + config PINCTRL_S3C24XX bool "Samsung S3C24XX SoC pinctrl driver" depends on ARCH_S3C24XX diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index d64563bf6fb4..496d9bf9e1b9 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -2,7 +2,7 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG -obj-$(CONFIG_PINCTRL) += core.o +obj-$(CONFIG_PINCTRL) += core.o pinctrl-utils.o obj-$(CONFIG_PINMUX) += pinmux.o obj-$(CONFIG_PINCONF) += pinconf.o ifeq ($(CONFIG_OF),y) @@ -32,6 +32,7 @@ obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o obj-$(CONFIG_PINCTRL_DB8540) += pinctrl-nomadik-db8540.o +obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_SIRF) += sirf/ diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 2a00239661b3..92f86ab30a13 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -153,9 +153,7 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name) pin = pctldev->desc->pins[i].number; desc = pin_desc_get(pctldev, pin); /* Pin space may be sparse */ - if (desc == NULL) - continue; - if (desc->name && !strcmp(name, desc->name)) + if (desc && !strcmp(name, desc->name)) return pin; } @@ -357,14 +355,17 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio) /* Loop over the pin controllers */ list_for_each_entry(pctldev, &pinctrldev_list, node) { /* Loop over the ranges */ + mutex_lock(&pctldev->mutex); list_for_each_entry(range, &pctldev->gpio_ranges, node) { /* Check if any gpio range overlapped with gpio chip */ if (range->base + range->npins - 1 < chip->base || range->base > chip->base + chip->ngpio - 1) continue; + mutex_unlock(&pctldev->mutex); mutex_unlock(&pinctrldev_list_mutex); return true; } + mutex_unlock(&pctldev->mutex); } mutex_unlock(&pinctrldev_list_mutex); @@ -392,6 +393,8 @@ static int pinctrl_get_device_gpio_range(unsigned gpio, { struct pinctrl_dev *pctldev = NULL; + mutex_lock(&pinctrldev_list_mutex); + /* Loop over the pin controllers */ list_for_each_entry(pctldev, &pinctrldev_list, node) { struct pinctrl_gpio_range *range; @@ -400,10 +403,13 @@ static int pinctrl_get_device_gpio_range(unsigned gpio, if (range != NULL) { *outdev = pctldev; *outrange = range; + mutex_unlock(&pinctrldev_list_mutex); return 0; } } + mutex_unlock(&pinctrldev_list_mutex); + return -EPROBE_DEFER; } @@ -556,11 +562,15 @@ int pinctrl_request_gpio(unsigned gpio) return ret; } + mutex_lock(&pctldev->mutex); + /* Convert to the pin controllers number space */ pin = gpio_to_pin(range, gpio); ret = pinmux_request_gpio(pctldev, range, pin, gpio); + mutex_unlock(&pctldev->mutex); + return ret; } EXPORT_SYMBOL_GPL(pinctrl_request_gpio); @@ -1228,23 +1238,36 @@ EXPORT_SYMBOL_GPL(pinctrl_force_default); #ifdef CONFIG_PM /** - * pinctrl_pm_select_default_state() - select default pinctrl state for PM + * pinctrl_pm_select_state() - select pinctrl state for PM * @dev: device to select default state for + * @state: state to set */ -int pinctrl_pm_select_default_state(struct device *dev) +static int pinctrl_pm_select_state(struct device *dev, + struct pinctrl_state *state) { struct dev_pin_info *pins = dev->pins; int ret; - if (!pins) - return 0; - if (IS_ERR(pins->default_state)) - return 0; /* No default state */ - ret = pinctrl_select_state(pins->p, pins->default_state); + if (IS_ERR(state)) + return 0; /* No such state */ + ret = pinctrl_select_state(pins->p, state); if (ret) - dev_err(dev, "failed to activate default pinctrl state\n"); + dev_err(dev, "failed to activate pinctrl state %s\n", + state->name); return ret; } + +/** + * pinctrl_pm_select_default_state() - select default pinctrl state for PM + * @dev: device to select default state for + */ +int pinctrl_pm_select_default_state(struct device *dev) +{ + if (!dev->pins) + return 0; + + return pinctrl_pm_select_state(dev, dev->pins->default_state); +} EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state); /** @@ -1253,17 +1276,10 @@ EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state); */ int pinctrl_pm_select_sleep_state(struct device *dev) { - struct dev_pin_info *pins = dev->pins; - int ret; - - if (!pins) + if (!dev->pins) return 0; - if (IS_ERR(pins->sleep_state)) - return 0; /* No sleep state */ - ret = pinctrl_select_state(pins->p, pins->sleep_state); - if (ret) - dev_err(dev, "failed to activate pinctrl sleep state\n"); - return ret; + + return pinctrl_pm_select_state(dev, dev->pins->sleep_state); } EXPORT_SYMBOL_GPL(pinctrl_pm_select_sleep_state); @@ -1273,17 +1289,10 @@ EXPORT_SYMBOL_GPL(pinctrl_pm_select_sleep_state); */ int pinctrl_pm_select_idle_state(struct device *dev) { - struct dev_pin_info *pins = dev->pins; - int ret; - - if (!pins) + if (!dev->pins) return 0; - if (IS_ERR(pins->idle_state)) - return 0; /* No idle state */ - ret = pinctrl_select_state(pins->p, pins->idle_state); - if (ret) - dev_err(dev, "failed to activate pinctrl idle state\n"); - return ret; + + return pinctrl_pm_select_state(dev, dev->pins->idle_state); } EXPORT_SYMBOL_GPL(pinctrl_pm_select_idle_state); #endif diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c index bb7ddb1bc89f..0fd1ad31fbf9 100644 --- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -191,18 +191,27 @@ static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev, } static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev, - unsigned gid, unsigned long config) + unsigned gid, unsigned long *configs, + unsigned num_configs) { struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; + int i, ret; if (!grp->ctrl) return -EINVAL; - if (grp->ctrl->mpp_set) - return grp->ctrl->mpp_set(grp->ctrl, config); + for (i = 0; i < num_configs; i++) { + if (grp->ctrl->mpp_set) + ret = grp->ctrl->mpp_set(grp->ctrl, configs[i]); + else + ret = mvebu_common_mpp_set(pctl, grp, configs[i]); - return mvebu_common_mpp_set(pctl, grp, config); + if (ret) + return ret; + } /* for each config */ + + return 0; } static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, @@ -303,6 +312,7 @@ static int mvebu_pinmux_enable(struct pinctrl_dev *pctldev, unsigned fid, struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; struct mvebu_mpp_ctrl_setting *setting; int ret; + unsigned long config; setting = mvebu_pinctrl_find_setting_by_name(pctl, grp, func->name); @@ -313,7 +323,8 @@ static int mvebu_pinmux_enable(struct pinctrl_dev *pctldev, unsigned fid, return -EINVAL; } - ret = mvebu_pinconf_group_set(pctldev, grp->gid, setting->val); + config = setting->val; + ret = mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1); if (ret) { dev_err(pctl->dev, "cannot set group %s to %s\n", func->groups[gid], func->name); @@ -329,6 +340,7 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct mvebu_pinctrl_group *grp; struct mvebu_mpp_ctrl_setting *setting; + unsigned long config; grp = mvebu_pinctrl_find_group_by_pid(pctl, offset); if (!grp) @@ -341,7 +353,9 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, if (!setting) return -ENOTSUPP; - return mvebu_pinconf_group_set(pctldev, grp->gid, setting->val); + config = setting->val; + + return mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1); } static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, @@ -430,7 +444,7 @@ static int mvebu_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, } *map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL); - if (map == NULL) { + if (*map == NULL) { dev_err(pctl->dev, "cannot allocate pinctrl_map memory for %s\n", np->name); @@ -579,7 +593,7 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev, int mvebu_pinctrl_probe(struct platform_device *pdev) { struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev); - struct device_node *np = pdev->dev.of_node; + struct resource *res; struct mvebu_pinctrl *pctl; void __iomem *base; struct pinctrl_pin_desc *pdesc; @@ -591,11 +605,10 @@ int mvebu_pinctrl_probe(struct platform_device *pdev) return -EINVAL; } - base = of_iomap(np, 0); - if (!base) { - dev_err(&pdev->dev, "unable to get base address\n"); - return -ENODEV; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl), GFP_KERNEL); diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 8594f033ac21..55a0ebe830ac 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -24,6 +24,7 @@ #include <linux/of.h> #include "core.h" #include "pinconf.h" +#include "pinctrl-utils.h" #ifdef CONFIG_DEBUG_FS @@ -236,4 +237,99 @@ out: kfree(cfg); return ret; } + +int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, struct pinctrl_map **map, + unsigned *reserved_maps, unsigned *num_maps, + enum pinctrl_map_type type) +{ + int ret; + const char *function; + struct device *dev = pctldev->dev; + unsigned long *configs = NULL; + unsigned num_configs = 0; + unsigned reserve; + struct property *prop; + const char *group; + + ret = of_property_read_string(np, "function", &function); + if (ret < 0) { + /* EINVAL=missing, which is fine since it's optional */ + if (ret != -EINVAL) + dev_err(dev, "could not parse property function\n"); + function = NULL; + } + + ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); + if (ret < 0) { + dev_err(dev, "could not parse node property\n"); + return ret; + } + + reserve = 0; + if (function != NULL) + reserve++; + if (num_configs) + reserve++; + ret = of_property_count_strings(np, "pins"); + if (ret < 0) { + dev_err(dev, "could not parse property pins\n"); + goto exit; + } + reserve *= ret; + + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, + num_maps, reserve); + if (ret < 0) + goto exit; + + of_property_for_each_string(np, "pins", prop, group) { + if (function) { + ret = pinctrl_utils_add_map_mux(pctldev, map, + reserved_maps, num_maps, group, + function); + if (ret < 0) + goto exit; + } + + if (num_configs) { + ret = pinctrl_utils_add_map_configs(pctldev, map, + reserved_maps, num_maps, group, configs, + num_configs, type); + if (ret < 0) + goto exit; + } + } + ret = 0; + +exit: + kfree(configs); + return ret; +} +EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map); + +int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, struct pinctrl_map **map, + unsigned *num_maps, enum pinctrl_map_type type) +{ + unsigned reserved_maps; + struct device_node *np; + int ret; + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + for_each_child_of_node(np_config, np) { + ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, num_maps, type); + if (ret < 0) { + pinctrl_utils_dt_free_map(pctldev, *map, *num_maps); + return ret; + } + } + return 0; +} +EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map); + #endif diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index e875f21a5908..a138965c01cb 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -158,7 +158,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; if (!ops) { dev_err(pctldev->dev, "missing confops\n"); @@ -171,17 +171,15 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) 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, - 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; - } + ret = ops->pin_config_set(pctldev, + setting->data.configs.group_or_pin, + setting->data.configs.configs, + setting->data.configs.num_configs); + if (ret < 0) { + dev_err(pctldev->dev, + "pin_config_set op failed for pin %d\n", + setting->data.configs.group_or_pin); + return ret; } break; case PIN_MAP_TYPE_CONFIGS_GROUP: @@ -190,17 +188,15 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) "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, - setting->data.configs.group_or_pin, - setting->data.configs.configs[i]); - 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; - } + ret = ops->pin_config_group_set(pctldev, + setting->data.configs.group_or_pin, + 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\n", + setting->data.configs.group_or_pin); + return ret; } break; default: @@ -428,12 +424,11 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) { struct pinctrl_maps *maps_node; const struct pinctrl_map *map; - struct pinctrl_dev *pctldev = NULL; + const struct pinctrl_map *found = NULL; + struct pinctrl_dev *pctldev; const struct pinconf_ops *confops = NULL; - const struct pinctrl_map_configs *configs; struct dbg_cfg *dbg = &pinconf_dbg_conf; int i, j; - bool found = false; unsigned long config; mutex_lock(&pinctrl_maps_mutex); @@ -450,14 +445,8 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) for (j = 0; j < map->data.configs.num_configs; j++) { if (!strcmp(map->data.configs.group_or_pin, dbg->pin_name)) { - /* - * We found the right pin / state, read the - * config and he pctldev for later use - */ - configs = &map->data.configs; - pctldev = get_pinctrl_dev_from_devname - (map->ctrl_dev_name); - found = true; + /* We found the right pin / state */ + found = map; break; } } @@ -473,7 +462,8 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) goto exit; } - config = *(configs->configs); + pctldev = get_pinctrl_dev_from_devname(found->ctr |