From 1a78958dc212f3698fdc543857af80155cb30f7f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 20:51:54 +0200 Subject: [PATCH 01/23] pinctrl: reserve pins when states are activated This switches the way that pins are reserved for multiplexing: We used to do this when the map was parsed, at the creation of the settings inside the pinctrl handle, in pinmux_map_to_setting(). However this does not work for us, because we want to use the same set of pins with different devices at different times: the current code assumes that the pin groups in a pinmux state will only be used with one single device, albeit different groups can be active at different times. For example if a single I2C driver block is used to drive two different busses located on two pin groups A and B, then the pins for all possible states of a function are reserved when fetching the pinctrl handle: the I2C bus can choose either set A or set B by a mux state at runtime, but all pins in both group A and B (the superset) are effectively reserved for that I2C function and mapped to the device. Another device can never get in and use the pins in group A, even if the device/function is using group B at the moment. Instead: let use reserve the pins when the state is activated and drop them when the state is disabled, i.e. when we move to another state. This way different devices/functions can use the same pins at different times. We know that this is an odd way of doing things, but we really need to switch e.g. an SD-card slot to become a tracing output sink at runtime: we plug in a special "tracing card" then mux the pins that used to be an SD slot around to the tracing unit and push out tracing data there instead of SD-card traffic. As a side effect pinmux_free_setting() is unused but the stubs are kept for future additions of code. Cc: Patrice Chotard Cc: Loic Pallardy Acked-by: Stephen Warren Tested-by: Jean Nicolas Graux Signed-off-by: Linus Walleij --- Documentation/pinctrl.txt | 4 ++- drivers/pinctrl/core.c | 2 ++ drivers/pinctrl/core.h | 2 ++ drivers/pinctrl/pinmux.c | 67 +++++++++++++-------------------------- 4 files changed, 29 insertions(+), 46 deletions(-) diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index 3b4ee5328868..a1cd2f9428d7 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -1193,4 +1193,6 @@ foo_switch() ... } -The above has to be done from process context. +The above has to be done from process context. The reservation of the pins +will be done when the state is activated, so in effect one specific pin +can be used by different functions at different times on a running system. diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 2e39c04fc16b..cec6072cd7c1 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -563,6 +563,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map) return -EPROBE_DEFER; } + setting->dev_name = map->dev_name; + switch (map->type) { case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_map_to_setting(map, setting); diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 1f40ff68a8c4..12f5694f3d5d 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -105,12 +105,14 @@ struct pinctrl_setting_configs { * @type: the type of setting * @pctldev: pin control device handling to be programmed. Not used for * PIN_MAP_TYPE_DUMMY_STATE. + * @dev_name: the name of the device using this state * @data: Data specific to the setting type */ struct pinctrl_setting { struct list_head node; enum pinctrl_map_type type; struct pinctrl_dev *pctldev; + const char *dev_name; union { struct pinctrl_setting_mux mux; struct pinctrl_setting_configs configs; diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 9301a7a95eff..0ef01ee2835f 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -314,14 +314,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinmux_ops *pmxops = pctldev->desc->pmxops; - const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; char const * const *groups; unsigned num_groups; int ret; const char *group; int i; - const unsigned *pins; - unsigned num_pins; if (!pmxops) { dev_err(pctldev->dev, "does not support mux function\n"); @@ -376,53 +373,12 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, } setting->data.mux.group = ret; - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins, - &num_pins); - if (ret) { - dev_err(pctldev->dev, - "could not get pins for device %s group selector %d\n", - pinctrl_dev_get_name(pctldev), setting->data.mux.group); - return -ENODEV; - } - - /* Try to allocate all pins in this group, one by one */ - for (i = 0; i < num_pins; i++) { - ret = pin_request(pctldev, pins[i], map->dev_name, NULL); - if (ret) { - dev_err(pctldev->dev, - "could not request pin %d on device %s\n", - pins[i], pinctrl_dev_get_name(pctldev)); - /* On error release all taken pins */ - i--; /* this pin just failed */ - for (; i >= 0; i--) - pin_free(pctldev, pins[i], NULL); - return -ENODEV; - } - } - return 0; } void pinmux_free_setting(struct pinctrl_setting const *setting) { - struct pinctrl_dev *pctldev = setting->pctldev; - const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; - const unsigned *pins; - unsigned num_pins; - int ret; - int i; - - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, - &pins, &num_pins); - if (ret) { - dev_err(pctldev->dev, - "could not get pins for device %s group selector %d\n", - pinctrl_dev_get_name(pctldev), setting->data.mux.group); - return; - } - - for (i = 0; i < num_pins; i++) - pin_free(pctldev, pins[i], NULL); + /* This function is currently unused */ } int pinmux_enable_setting(struct pinctrl_setting const *setting) @@ -446,6 +402,22 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting) num_pins = 0; } + /* Try to allocate all pins in this group, one by one */ + for (i = 0; i < num_pins; i++) { + ret = pin_request(pctldev, pins[i], setting->dev_name, NULL); + if (ret) { + dev_err(pctldev->dev, + "could not request pin %d on device %s\n", + pins[i], pinctrl_dev_get_name(pctldev)); + /* On error release all taken pins */ + i--; /* this pin just failed */ + for (; i >= 0; i--) + pin_free(pctldev, pins[i], NULL); + return -ENODEV; + } + } + + /* Now that we have acquired the pins, encode the mux setting */ for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc == NULL) { @@ -482,6 +454,7 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) num_pins = 0; } + /* Flag the descs that no setting is active */ for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc == NULL) { @@ -493,6 +466,10 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) desc->mux_setting = NULL; } + /* And release the pins */ + for (i = 0; i < num_pins; i++) + pin_free(pctldev, pins[i], NULL); + if (ops->disable) ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group); } From 55d2e40d4acf9081daee5a95d0eb474511408968 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 24 Oct 2012 23:38:56 +0200 Subject: [PATCH 02/23] pinctrl: mvebu: allow plat-orion architectures to use pinctrl-mvebu The mach-kirkwood and mach-dove architectures have not yet been integrated into the mach-mvebu directory, which should ultimately contain the support for all Marvell SoCs from the Engineering Business Unit. However, before this can happen, we need to let mach-kirkwood and mach-dove use the pinctrl-mvebu driver, which supports the kirkwood and dove SoC families. In order to do that, we make this driver available as soon as PLAT_ORION is selected, instead of using ARCH_MVEBU as a condition. In the long term, PLAT_ORION should disappear and be fully replaced by ARCH_MVEBU, but the plan is to make the migration step by step, by first having the existing mach-* directories for Marvell SoCs converge on several infrastructures, including the pinctrl one. Also, like the spear pinctrl driver, we put all pinctrl-mvebu Kconfig options under a if, in order to avoid having certain options (PINCTRL_DOVE, PINCTRL_KIRKWOOD, etc.) selecting an option (PINCTLR_MVEBU) which itself has a dependency (on ARCH_MVEBU). In this a construct, the dependency is in fact ignored due to the selects. Signed-off-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d96caefd914a..2cc8fd929d90 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -188,9 +188,10 @@ config PINCTRL_EXYNOS4 depends on OF && GPIOLIB select PINCTRL_SAMSUNG +if PLAT_ORION + config PINCTRL_MVEBU bool - depends on ARCH_MVEBU select PINMUX select PINCONF @@ -210,6 +211,8 @@ config PINCTRL_ARMADA_XP bool select PINCTRL_MVEBU +endif + source "drivers/pinctrl/spear/Kconfig" config PINCTRL_XWAY From de1d76258f438414633cb92cb1a195ba3835972c Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 24 Oct 2012 23:38:57 +0200 Subject: [PATCH 03/23] pinctrl: mvebu: remove useless include Including the core.h header for the pinctrl subsystem is not necessary, and it is actually causing problems when moving the pinctrl-mvebu drivers into a separate subdirectory. Signed-off-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-mvebu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-mvebu.c b/drivers/pinctrl/pinctrl-mvebu.c index 8e6266c6249a..6c44b7e8964c 100644 --- a/drivers/pinctrl/pinctrl-mvebu.c +++ b/drivers/pinctrl/pinctrl-mvebu.c @@ -24,7 +24,6 @@ #include #include -#include "core.h" #include "pinctrl-mvebu.h" #define MPPS_PER_REG 8 From 06763c741b0a19160482c9b34e5bbc3e50dba79a Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 24 Oct 2012 23:38:58 +0200 Subject: [PATCH 04/23] pinctrl: mvebu: move to its own directory Like the spear platform, the mvebu platform has multiple files: one core file, and then one file per SoC family. More files will be added later, as support for mach-orion5x and mach-mv78xx0 SoCs is added to pinctrl-mvebu. For those reasons, having a separate subdirectory, drivers/pinctrl/mvebu/ makes sense, and it had already been suggested by Linus Wallej when the driver was originally submitted. Signed-off-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 25 +------------------ drivers/pinctrl/Makefile | 6 +---- drivers/pinctrl/mvebu/Kconfig | 24 ++++++++++++++++++ drivers/pinctrl/mvebu/Makefile | 5 ++++ .../pinctrl/{ => mvebu}/pinctrl-armada-370.c | 0 .../pinctrl/{ => mvebu}/pinctrl-armada-xp.c | 0 drivers/pinctrl/{ => mvebu}/pinctrl-dove.c | 0 .../pinctrl/{ => mvebu}/pinctrl-kirkwood.c | 0 drivers/pinctrl/{ => mvebu}/pinctrl-mvebu.c | 0 drivers/pinctrl/{ => mvebu}/pinctrl-mvebu.h | 0 10 files changed, 31 insertions(+), 29 deletions(-) create mode 100644 drivers/pinctrl/mvebu/Kconfig create mode 100644 drivers/pinctrl/mvebu/Makefile rename drivers/pinctrl/{ => mvebu}/pinctrl-armada-370.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-armada-xp.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-dove.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-kirkwood.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-mvebu.c (100%) rename drivers/pinctrl/{ => mvebu}/pinctrl-mvebu.h (100%) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 2cc8fd929d90..011133772d2a 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -188,30 +188,7 @@ config PINCTRL_EXYNOS4 depends on OF && GPIOLIB select PINCTRL_SAMSUNG -if PLAT_ORION - -config PINCTRL_MVEBU - bool - select PINMUX - select PINCONF - -config PINCTRL_DOVE - bool - select PINCTRL_MVEBU - -config PINCTRL_KIRKWOOD - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_370 - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_XP - bool - select PINCTRL_MVEBU - -endif +source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/spear/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f395ba5cec25..3cb6a0a668a8 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -36,12 +36,8 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o -obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o -obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o -obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o -obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o -obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o +obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig new file mode 100644 index 000000000000..366fa541ee91 --- /dev/null +++ b/drivers/pinctrl/mvebu/Kconfig @@ -0,0 +1,24 @@ +if PLAT_ORION + +config PINCTRL_MVEBU + bool + select PINMUX + select PINCONF + +config PINCTRL_DOVE + bool + select PINCTRL_MVEBU + +config PINCTRL_KIRKWOOD + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_370 + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_XP + bool + select PINCTRL_MVEBU + +endif diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile new file mode 100644 index 000000000000..37c253297af0 --- /dev/null +++ b/drivers/pinctrl/mvebu/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o +obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o +obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o +obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o +obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o diff --git a/drivers/pinctrl/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c similarity index 100% rename from drivers/pinctrl/pinctrl-armada-370.c rename to drivers/pinctrl/mvebu/pinctrl-armada-370.c diff --git a/drivers/pinctrl/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c similarity index 100% rename from drivers/pinctrl/pinctrl-armada-xp.c rename to drivers/pinctrl/mvebu/pinctrl-armada-xp.c diff --git a/drivers/pinctrl/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c similarity index 100% rename from drivers/pinctrl/pinctrl-dove.c rename to drivers/pinctrl/mvebu/pinctrl-dove.c diff --git a/drivers/pinctrl/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c similarity index 100% rename from drivers/pinctrl/pinctrl-kirkwood.c rename to drivers/pinctrl/mvebu/pinctrl-kirkwood.c diff --git a/drivers/pinctrl/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c similarity index 100% rename from drivers/pinctrl/pinctrl-mvebu.c rename to drivers/pinctrl/mvebu/pinctrl-mvebu.c diff --git a/drivers/pinctrl/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h similarity index 100% rename from drivers/pinctrl/pinctrl-mvebu.h rename to drivers/pinctrl/mvebu/pinctrl-mvebu.h From d3e26f2fe993b5dbc8b4b2275d77f9ad3e08c81a Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 27 Sep 2012 17:56:30 +0800 Subject: [PATCH 05/23] pinctrl: sirf: enable the driver support new SiRFmarco SoC The driver supports old up SiRFprimaII SoCs, this patch makes it support the new SiRFmarco as well. SiRFmarco, as a SMP SoC, adds new SIRFSOC_GPIO_PAD_EN_CLR registers, to disable GPIO pad, we should write 1 to the corresponding bit in the new CLEAR register instead of writing 0 to SIRFSOC_GPIO_PAD_EN. Signed-off-by: Barry Song Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 4 +-- drivers/pinctrl/pinctrl-sirf.c | 48 ++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 011133772d2a..5f2f9dc43e3b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -143,8 +143,8 @@ config PINCTRL_SINGLE This selects the device tree based generic pinctrl driver. config PINCTRL_SIRF - bool "CSR SiRFprimaII pin controller driver" - depends on ARCH_PRIMA2 + bool "CSR SiRFprimaII/SiRFmarco pin controller driver" + depends on ARCH_SIRF select PINMUX config PINCTRL_TEGRA diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 9ecacf3d0a75..16ec7d4d81ee 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -32,10 +32,10 @@ #define SIRFSOC_NUM_PADS 622 #define SIRFSOC_RSC_PIN_MUX 0x4 -#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) +#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) +#define SIRFSOC_GPIO_PAD_EN_CLR(g) ((g)*0x100 + 0x90) #define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4) #define SIRFSOC_GPIO_DSP_EN0 (0x80) -#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) #define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C) #define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1 @@ -60,6 +60,7 @@ struct sirfsoc_gpio_bank { int id; int parent_irq; spinlock_t lock; + bool is_marco; /* for marco, some registers are different with prima2 */ }; static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS]; @@ -191,6 +192,7 @@ struct sirfsoc_pmx { struct pinctrl_dev *pmx; void __iomem *gpio_virtbase; void __iomem *rsc_virtbase; + bool is_marco; }; /* SIRFSOC_GPIO_PAD_EN set */ @@ -1088,12 +1090,21 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector for (i = 0; i < mux->muxmask_counts; i++) { u32 muxval; - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); - if (enable) - muxval = muxval & ~mask[i].mask; - else - muxval = muxval | mask[i].mask; - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + if (!spmx->is_marco) { + muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + if (enable) + muxval = muxval & ~mask[i].mask; + else + muxval = muxval | mask[i].mask; + writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + } else { + if (enable) + writel(mask[i].mask, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group)); + else + writel(mask[i].mask, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + } } if (mux->funcmask && enable) { @@ -1158,9 +1169,14 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, spmx = pinctrl_dev_get_drvdata(pmxdev); - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); - muxval = muxval | (1 << (offset - range->pin_base)); - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + if (!spmx->is_marco) { + muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + muxval = muxval | (1 << (offset - range->pin_base)); + writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + } else { + writel(1 << (offset - range->pin_base), spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(group)); + } return 0; } @@ -1218,6 +1234,7 @@ static void __iomem *sirfsoc_rsc_of_iomap(void) { const struct of_device_id rsc_ids[] = { { .compatible = "sirf,prima2-rsc" }, + { .compatible = "sirf,marco-rsc" }, {} }; struct device_node *np; @@ -1259,6 +1276,9 @@ static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev) goto out_no_rsc_remap; } + if (of_device_is_compatible(np, "sirf,marco-pinctrl")) + spmx->is_marco = 1; + /* Now register the pin controller and all pins it handles */ spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx); if (!spmx->pmx) { @@ -1287,6 +1307,7 @@ out_no_gpio_remap: static const struct of_device_id pinmux_ids[] __devinitconst = { { .compatible = "sirf,prima2-pinctrl" }, + { .compatible = "sirf,marco-pinctrl" }, {} }; @@ -1648,6 +1669,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) struct sirfsoc_gpio_bank *bank; void *regs; struct platform_device *pdev; + bool is_marco = false; pdev = of_find_device_by_node(np); if (!pdev) @@ -1657,6 +1679,9 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) if (!regs) return -ENOMEM; + if (of_device_is_compatible(np, "sirf,marco-pinctrl")) + is_marco = 1; + for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { bank = &sgpio_bank[i]; spin_lock_init(&bank->lock); @@ -1673,6 +1698,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) bank->chip.gc.of_node = np; bank->chip.regs = regs; bank->id = i; + bank->is_marco = is_marco; bank->parent_irq = platform_get_irq(pdev, i); if (bank->parent_irq < 0) { err = bank->parent_irq; From afa538c2bf00cf6cd28fc6b5fcea1a75894228a0 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 2 Nov 2012 21:46:13 +0800 Subject: [PATCH 06/23] pinctrl: exynos: Add terminating entry for of_device_id table The of_device_id table is supposed to be zero-terminated. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-exynos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 21362f48d370..6ff665209a4c 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -36,6 +36,7 @@ /* list of external wakeup controllers supported */ static const struct of_device_id exynos_wkup_irq_ids[] = { { .compatible = "samsung,exynos4210-wakeup-eint", }, + { } }; static void exynos_gpio_irq_unmask(struct irq_data *irqd) From 7e10ee68f8ccc62e0934ff02f39ce541f3879844 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 27 Oct 2012 15:21:35 +0530 Subject: [PATCH 07/23] Revert "pinctrl: remove pinctrl_remove_gpio_range" This reverts earlier commit which removed pinctrl_remove_gpio_range(), because at that time there weren't any more users of that routine. It was removed as the removal of ranges was done in unregister of pinctrl. But as we are now registering stuff from gpiolib, we may remove and insert a gpio module multiple times. So, we need this routine again. Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 14 ++++++++++++++ include/linux/pinctrl/pinctrl.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index cec6072cd7c1..b1086dcde15d 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -345,6 +345,20 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges); +/** + * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller + * @pctldev: pin controller device to remove the range from + * @range: the GPIO range to remove + */ +void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range) +{ + mutex_lock(&pinctrl_mutex); + list_del(&range->node); + mutex_unlock(&pinctrl_mutex); +} +EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range); + /** * pinctrl_get_group_selector() - returns the group selector for a group * @pctldev: the pin controller handling the group diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index 7d087f03e91e..eda04674633d 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -134,6 +134,8 @@ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev, extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *ranges, unsigned nranges); +extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range); extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev); extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev); #else From f23f1516b6757c326cc638bed8c402c77e2a596e Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Sat, 27 Oct 2012 15:21:36 +0530 Subject: [PATCH 08/23] gpiolib: provide provision to register pin ranges pinctrl subsystem needs gpio chip base to prepare set of gpio pin ranges, which a given pinctrl driver can handle. This is important to handle pinctrl gpio request calls in order to program a given pin properly for gpio operation. As gpio base is allocated dynamically during gpiochip registration, presently there exists no clean way to pass this information to the pinctrl subsystem. After few discussions from [1], it was concluded that may be gpio controller reporting the pin range it supports, is a better way than pinctrl subsystem directly registering it. [1] http://comments.gmane.org/gmane.linux.ports.arm.kernel/184816 Cc: Grant Likely Signed-off-by: Viresh Kumar Signed-off-by: Shiraz Hashim [Edited documentation a bit] Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio.txt | 36 ++++++++++++ Documentation/gpio.txt | 42 ++++++++++++++ Documentation/pinctrl.txt | 3 + drivers/gpio/gpiolib-of.c | 56 +++++++++++++++++++ drivers/gpio/gpiolib.c | 43 ++++++++++++++ drivers/pinctrl/core.c | 13 +++++ drivers/pinctrl/devicetree.c | 13 +++++ include/asm-generic/gpio.h | 25 +++++++++ include/linux/gpio.h | 3 + include/linux/pinctrl/pinctrl.h | 17 ++++++ 10 files changed, 251 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt index 4e16ba4feab0..a33628759d36 100644 --- a/Documentation/devicetree/bindings/gpio/gpio.txt +++ b/Documentation/devicetree/bindings/gpio/gpio.txt @@ -75,4 +75,40 @@ Example of two SOC GPIO banks defined as gpio-controller nodes: gpio-controller; }; +2.1) gpio-controller and pinctrl subsystem +------------------------------------------ +gpio-controller on a SOC might be tightly coupled with the pinctrl +subsystem, in the sense that the pins can be used by other functions +together with optional gpio feature. + +While the pin allocation is totally managed by the pin ctrl subsystem, +gpio (under gpiolib) is still maintained by gpio drivers. It may happen +that different pin ranges in a SoC is managed by different gpio drivers. + +This makes it logical to let gpio drivers announce their pin ranges to +the pin ctrl subsystem and call 'pinctrl_request_gpio' in order to +request the corresponding pin before any gpio usage. + +For this, the gpio controller can use a pinctrl phandle and pins to +announce the pinrange to the pin ctrl subsystem. For example, + + qe_pio_e: gpio-controller@1460 { + #gpio-cells = <2>; + compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank"; + reg = <0x1460 0x18>; + gpio-controller; + gpio-ranges = <&pinctrl1 20 10>, <&pinctrl2 50 20>; + + } + +where, + &pinctrl1 and &pinctrl2 is the phandle to the pinctrl DT node. + + Next values specify the base pin and number of pins for the range + handled by 'qe_pio_e' gpio. In the given example from base pin 20 to + pin 29 under pinctrl1 and pin 50 to pin 69 under pinctrl2 is handled + by this gpio controller. + +The pinctrl node must have "#gpio-range-cells" property to show number of +arguments to pass with phandle from gpio controllers node. diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index e08a883de36e..77a1d11af723 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -439,6 +439,48 @@ slower clock delays the rising edge of SCK, and the I2C master adjusts its signaling rate accordingly. +GPIO controllers and the pinctrl subsystem +------------------------------------------ + +A GPIO controller on a SOC might be tightly coupled with the pinctrl +subsystem, in the sense that the pins can be used by other functions +together with an optional gpio feature. We have already covered the +case where e.g. a GPIO controller need to reserve a pin or set the +direction of a pin by calling any of: + +pinctrl_request_gpio() +pinctrl_free_gpio() +pinctrl_gpio_direction_input() +pinctrl_gpio_direction_output() + +But how does the pin control subsystem cross-correlate the GPIO +numbers (which are a global business) to a certain pin on a certain +pin controller? + +This is done by registering "ranges" of pins, which are essentially +cross-reference tables. These are described in +Documentation/pinctrl.txt + +While the pin allocation is totally managed by the pinctrl subsystem, +gpio (under gpiolib) is still maintained by gpio drivers. It may happen +that different pin ranges in a SoC is managed by different gpio drivers. + +This makes it logical to let gpio drivers announce their pin ranges to +the pin ctrl subsystem before it will call 'pinctrl_request_gpio' in order +to request the corresponding pin to be prepared by the pinctrl subsystem +before any gpio usage. + +For this, the gpio controller can register its pin range with pinctrl +subsystem. There are two ways of doing it currently: with or without DT. + +For with DT support refer to Documentation/devicetree/bindings/gpio/gpio.txt. + +For non-DT support, user can call gpiochip_add_pin_range() with appropriate +parameters to register a range of gpio pins with a pinctrl driver. For this +exact name string of pinctrl device has to be passed as one of the +argument to this routine. + + What do these conventions omit? =============================== One of the biggest things these conventions omit is pin multiplexing, since diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt index a1cd2f9428d7..da40efbef6ec 100644 --- a/Documentation/pinctrl.txt +++ b/Documentation/pinctrl.txt @@ -364,6 +364,9 @@ will get an pin number into its handled number range. Further it is also passed the range ID value, so that the pin controller knows which range it should deal with. +Calling pinctrl_add_gpio_range from pinctrl driver is DEPRECATED. Please see +section 2.1 of Documentation/devicetree/bindings/gpio/gpio.txt on how to bind +pinctrl and gpio drivers. PINMUX interfaces ================= diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index f1a45997aea8..a5b90c8e9844 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -19,6 +19,7 @@ #include #include #include +#include #include /* Private data structure for of_gpiochip_find_and_xlate */ @@ -216,6 +217,58 @@ err0: } EXPORT_SYMBOL(of_mm_gpiochip_add); +#ifdef CONFIG_PINCTRL +void of_gpiochip_add_pin_range(struct gpio_chip *chip) +{ + struct device_node *np = chip->of_node; + struct gpio_pin_range *pin_range; + struct of_phandle_args pinspec; + int index = 0, ret; + + if (!np) + return; + + do { + ret = of_parse_phandle_with_args(np, "gpio-ranges", + "#gpio-range-cells", index, &pinspec); + if (ret) + break; + + pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), + GFP_KERNEL); + if (!pin_range) { + pr_err("%s: GPIO chip: failed to allocate pin ranges\n", + chip->label); + break; + } + + pin_range->range.name = chip->label; + pin_range->range.base = chip->base; + pin_range->range.pin_base = pinspec.args[0]; + pin_range->range.npins = pinspec.args[1]; + pin_range->pctldev = of_pinctrl_add_gpio_range(pinspec.np, + &pin_range->range); + + list_add_tail(&pin_range->node, &chip->pin_ranges); + + } while (index++); +} + +void of_gpiochip_remove_pin_range(struct gpio_chip *chip) +{ + struct gpio_pin_range *pin_range, *tmp; + + list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) { + list_del(&pin_range->node); + pinctrl_remove_gpio_range(pin_range->pctldev, + &pin_range->range); + } +} +#else +void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} +void of_gpiochip_remove_pin_range(struct gpio_chip *chip) {} +#endif + void of_gpiochip_add(struct gpio_chip *chip) { if ((!chip->of_node) && (chip->dev)) @@ -229,11 +282,14 @@ void of_gpiochip_add(struct gpio_chip *chip) chip->of_xlate = of_gpio_simple_xlate; } + of_gpiochip_add_pin_range(chip); of_node_get(chip->of_node); } void of_gpiochip_remove(struct gpio_chip *chip) { + of_gpiochip_remove_pin_range(chip); + if (chip->of_node) of_node_put(chip->of_node); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1c8d9e3380e1..f0b07bbfcc9a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1083,6 +1083,10 @@ int gpiochip_add(struct gpio_chip *chip) } } +#ifdef CONFIG_PINCTRL + INIT_LIST_HEAD(&chip->pin_ranges); +#endif + of_gpiochip_add(chip); unlock: @@ -1180,6 +1184,45 @@ struct gpio_chip *gpiochip_find(void *data, } EXPORT_SYMBOL_GPL(gpiochip_find); +#ifdef CONFIG_PINCTRL +void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) +{ + struct gpio_pin_range *pin_range; + + pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), GFP_KERNEL); + if (!pin_range) { + pr_err("%s: GPIO chip: failed to allocate pin ranges\n", + chip->label); + return; + } + + pin_range->range.name = chip->label; + pin_range->range.base = chip->base; + pin_range->range.pin_base = pin_base; + pin_range->range.npins = npins; + pin_range->pctldev = find_pinctrl_and_add_gpio_range(pinctl_name, + &pin_range->range); + + list_add_tail(&pin_range->node, &chip->pin_ranges); +} + +void gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ + struct gpio_pin_range *pin_range, *tmp; + + list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) { + list_del(&pin_range->node); + pinctrl_remove_gpio_range(pin_range->pctldev, + &pin_range->range); + } +} +#else +void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) {} +void gpiochip_remove_pin_ranges(struct gpio_chip *chip) {} +#endif + /* These "optional" allocation calls help prevent drivers from stomping * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index b1086dcde15d..71db586b2afd 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -345,6 +345,19 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges); +struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname, + struct pinctrl_gpio_range *range) +{ + struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname); + + if (!pctldev) + return NULL; + + pinctrl_add_gpio_range(pctldev, range); + return pctldev; +} +EXPORT_SYMBOL_GPL(find_pinctrl_and_add_gpio_range); + /** * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller * @pctldev: pin controller device to remove the range from diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index fcb1de45473c..6728ec71cb65 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -106,6 +106,19 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np) return NULL; } +struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, + struct pinctrl_gpio_range *range) +{ + struct pinctrl_dev *pctldev; + + pctldev = find_pinctrl_by_of_node(np); + if (!pctldev) + return NULL; + + pinctrl_add_gpio_range(pctldev, range); + return pctldev; +} + static int dt_to_map_one_config(struct pinctrl *p, const char *statename, struct device_node *np_config) { diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a9432fc6b8ba..92e5c432421c 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef CONFIG_GPIOLIB @@ -47,6 +48,21 @@ struct seq_file; struct module; struct device_node; +#ifdef CONFIG_PINCTRL +/** + * struct gpio_pin_range - pin range controlled by a gpio chip + * @head: list for maintaining set of pin ranges, used internally + * @pctldev: pinctrl device which handles corresponding pins + * @range: actual range of pins controlled by a gpio controller + */ + +struct gpio_pin_range { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_gpio_range range; +}; +#endif + /** * struct gpio_chip - abstract a GPIO controller * @label: for diagnostics @@ -134,6 +150,15 @@ struct gpio_chip { int (*of_xlate)(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags); #endif +#ifdef CONFIG_PINCTRL + /* + * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally + * describe the actual pin range which they serve in an SoC. This + * information would be used by pinctrl subsystem to configure + * corresponding pins for gpio usage. + */ + struct list_head pin_ranges; +#endif }; extern const char *gpiochip_is_requested(struct gpio_chip *chip, diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 2e31e8b3a190..a28445992b7f 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -231,6 +231,9 @@ static inline int irq_to_gpio(unsigned irq) return -EINVAL; } +void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins); +void gpiochip_remove_pin_ranges(struct gpio_chip *chip); #endif #endif /* __LINUX_GPIO_H */ diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index eda04674633d..434e5a94e131 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -136,6 +136,23 @@ extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, unsigned nranges); extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range); + +extern struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname, + struct pinctrl_gpio_range *range); + +#ifdef CONFIG_OF +extern struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, + struct pinctrl_gpio_range *range); +#else +static inline +struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, + struct pinctrl_gpio_range *range) +{ + return NULL; +} + +#endif /* CONFIG_OF */ + extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev); extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev); #else From 604bb7da77803cc01366c85fd5bcbc88b6dbe33a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 27 Oct 2012 15:21:37 +0530 Subject: [PATCH 09/23] pinctrl: SPEAr: Add plgpio driver Most of SPEAr SoCs, which support pinctrl, can configure & use pads as gpio. This patch adds plgpio driver for configuring these pads as gpio. Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/pinctrl/spear/Kconfig | 7 + drivers/pinctrl/spear/Makefile | 1 + drivers/pinctrl/spear/pinctrl-plgpio.c | 746 +++++++++++++++++++++++++ 3 files changed, 754 insertions(+) create mode 100644 drivers/pinctrl/spear/pinctrl-plgpio.c diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig index 91558791e766..6f9a1e8bf575 100644 --- a/drivers/pinctrl/spear/Kconfig +++ b/drivers/pinctrl/spear/Kconfig @@ -41,4 +41,11 @@ config PINCTRL_SPEAR1340 depends on MACH_SPEAR1340 select PINCTRL_SPEAR +config PINCTRL_SPEAR_PLGPIO + bool "SPEAr SoC PLGPIO Controller" + depends on GPIOLIB && PINCTRL_SPEAR + help + Say yes here to support PLGPIO controller on ST Microelectronics SPEAr + SoCs. + endif diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile index b28a7ba22443..0e400ebeb8ff 100644 --- a/drivers/pinctrl/spear/Makefile +++ b/drivers/pinctrl/spear/Makefile @@ -1,5 +1,6 @@ # SPEAr pinmux support +obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO) += pinctrl-plgpio.o obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c new file mode 100644 index 000000000000..1044ad3f3c86 --- /dev/null +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -0,0 +1,746 @@ +/* + * SPEAr platform PLGPIO driver + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_GPIO_PER_REG 32 +#define PIN_OFFSET(pin) (pin % MAX_GPIO_PER_REG) +#define REG_OFFSET(base, reg, pin) (base + reg + (pin / MAX_GPIO_PER_REG) \ + * sizeof(int *)) + +/* + * plgpio pins in all machines are not one to one mapped, bitwise with registers + * bits. These set of macros define register masks for which below functions + * (pin_to_offset and offset_to_pin) are required to be called. + */ +#define PTO_ENB_REG 0x001 +#define PTO_WDATA_REG 0x002 +#define PTO_DIR_REG 0x004 +#define PTO_IE_REG 0x008 +#define PTO_RDATA_REG 0x010 +#define PTO_MIS_REG 0x020 + +struct plgpio_regs { + u32 enb; /* enable register */ + u32 wdata; /* write data register */ + u32 dir; /* direction set register */ + u32 rdata; /* read data register */ + u32 ie; /* interrupt enable register */ + u32 mis; /* mask interrupt status register */ + u32 eit; /* edge interrupt type */ +}; + +/* + * struct plgpio: plgpio driver specific structure + * + * lock: lock for guarding gpio registers + * base: base address of plgpio block + * irq_base: irq number of plgpio0 + * chip: gpio framework specific chip information structure + * p2o: function ptr for pin to offset conversion. This is required only for + * machines where mapping b/w pin and offset is not 1-to-1. + * o2p: function ptr for offset to pin conversion. This is required only for + * machines where mapping b/w pin and offset is not 1-to-1. + * p2o_regs: mask of registers for which p2o and o2p are applicable + * regs: register offsets + * csave_regs: context save registers for standby/sleep/hibernate cases + */ +struct plgpio { + spinlock_t lock; + void __iomem *base; + struct clk *clk; + unsigned irq_base; + struct irq_domain *irq_domain; + struct gpio_chip chip; + int (*p2o)(int pin); /* pin_to_offset */ + int (*o2p)(int offset); /* offset_to_pin */ + u32 p2o_regs; + struct plgpio_regs regs; +#ifdef CONFIG_PM + struct plgpio_regs *csave_regs; +#endif +}; + +/* register manipulation inline functions */ +static inline u32 is_plgpio_set(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + return !!(val & (1 << offset)); +} + +static inline void plgpio_reg_set(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + writel_relaxed(val | (1 << offset), reg_off); +} + +static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + writel_relaxed(val & ~(1 << offset), reg_off); +} + +/* gpio framework specific routines */ +static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_DIR_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return -EINVAL; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.dir); + spin_unlock_irqrestore(&plgpio->lock, flags); + + return 0; +} + +static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + unsigned long flags; + unsigned dir_offset = offset, wdata_offset = offset, tmp; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & (PTO_DIR_REG | PTO_WDATA_REG))) { + tmp = plgpio->p2o(offset); + if (tmp == -1) + return -EINVAL; + + if (plgpio->p2o_regs & PTO_DIR_REG) + dir_offset = tmp; + if (plgpio->p2o_regs & PTO_WDATA_REG) + wdata_offset = tmp; + } + + spin_lock_irqsave(&plgpio->lock, flags); + if (value) + plgpio_reg_set(plgpio->base, wdata_offset, + plgpio->regs.wdata); + else + plgpio_reg_reset(plgpio->base, wdata_offset, + plgpio->regs.wdata); + + plgpio_reg_reset(plgpio->base, dir_offset, plgpio->regs.dir); + spin_unlock_irqrestore(&plgpio->lock, flags); + + return 0; +} + +static int plgpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (offset >= chip->ngpio) + return -EINVAL; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_RDATA_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return -EINVAL; + } + + return is_plgpio_set(plgpio->base, offset, plgpio->regs.rdata); +} + +static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (offset >= chip->ngpio) + return; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_WDATA_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + if (value) + plgpio_reg_set(plgpio->base, offset, plgpio->regs.wdata); + else + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.wdata); +} + +static int plgpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + int gpio = chip->base + offset; + unsigned long flags; + int ret = 0; + + if (offset >= chip->ngpio) + return -EINVAL; + + ret = pinctrl_request_gpio(gpio); + if (ret) + return ret; + + if (!IS_ERR(plgpio->clk)) { + ret = clk_prepare_enable(plgpio->clk); + if (ret) + goto err0; + } + + if (plgpio->regs.enb == -1) + return 0; + + /* + * put gpio in IN mode before enabling it. This make enabling gpio safe + */ + ret = plgpio_direction_input(chip, offset); + if (ret) + goto err1; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) { + ret = -EINVAL; + goto err1; + } + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.enb); + spin_unlock_irqrestore(&plgpio->lock, flags); + return 0; + +err1: + clk_disable_unprepare(plgpio->clk); +err0: + pinctrl_free_gpio(gpio); + return ret; +} + +static void plgpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + int gpio = chip->base + offset; + unsigned long flags; + + if (offset >= chip->ngpio) + return; + + if (plgpio->regs.enb == -1) + goto disable_clk; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.enb); + spin_unlock_irqrestore(&plgpio->lock, flags); + +disable_clk: + if (!IS_ERR(plgpio->clk)) + clk_disable_unprepare(plgpio->clk); + + pinctrl_free_gpio(gpio); +} + +static int plgpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (plgpio->irq_base < 0) + return -EINVAL; + + return irq_find_mapping(plgpio->irq_domain, offset); +} + +/* PLGPIO IRQ */ +static void plgpio_irq_disable(struct irq_data *d) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.ie); + spin_unlock_irqrestore(&plgpio->lock, flags); +} + +static void plgpio_irq_enable(struct irq_data *d) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.ie); + spin_unlock_irqrestore(&plgpio->lock, flags); +} + +static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + void __iomem *reg_off; + unsigned int supported_type = 0, val; + + if (offset >= plgpio->chip.ngpio) + return -EINVAL; + + if (plgpio->regs.eit == -1) + supported_type = IRQ_TYPE_LEVEL_HIGH; + else + supported_type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + + if (!(trigger & supported_type)) + return -EINVAL; + + if (plgpio->regs.eit == -1) + return 0; + + reg_off = REG_OFFSET(plgpio->base, plgpio->regs.eit, offset); + val = readl_relaxed(reg_off); + + offset = PIN_OFFSET(offset); + if (trigger & IRQ_TYPE_EDGE_RISING) + writel_relaxed(val | (1 << offset), reg_off); + else + writel_relaxed(val & ~(1 << offset), reg_off); + + return 0; +} + +static struct irq_chip plgpio_irqchip = { + .name = "PLGPIO", + .irq_enable = plgpio_irq_enable, + .irq_disable = plgpio_irq_disable, + .irq_set_type = plgpio_irq_set_type, +}; + +static void plgpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct plgpio *plgpio = irq_get_handler_data(irq); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + int regs_count, count, pin, offset, i = 0; + unsigned long pending; + + count = plgpio->chip.ngpio; + regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG); + + chained_irq_enter(irqchip, desc); + /* check all plgpio MIS registers for a possible interrupt */ + for (; i < regs_count; i++) { + pending = readl_relaxed(plgpio->base + plgpio->regs.mis + + i * sizeof(int *)); + if (!pending) + continue; + + /* clear interrupts */ + writel_relaxed(~pending, plgpio->base + plgpio->regs.mis + + i * sizeof(int *)); + /* + * clear extra bits in last register having gpios < MAX/REG + * ex: Suppose there are max 102 plgpios. then last register + * must have only (102 - MAX_GPIO_PER_REG * 3) = 6 relevant bits + * so, we must not take other 28 bits into consideration for + * checking interrupt. so clear those bits. + */ + count = count - i * MAX_GPIO_PER_REG; + if (count < MAX_GPIO_PER_REG) + pending &= (1 << count) - 1; + + for_each_set_bit(offset, &pending, MAX_GPIO_PER_REG) { + /* get correct pin for "offset" */ + if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) { + pin = plgpio->o2p(offset); + if (pin == -1) + continue; + } else + pin = offset; + + /* get correct irq line number */ + pin = i * MAX_GPIO_PER_REG + pin; + generic_handle_irq(plgpio_to_irq(&plgpio->chip, pin)); + } + } + chained_irq_exit(irqchip, desc); +} + +/* + * pin to offset and offset to pin converter functions + * + * In spear310 there is inconsistency among bit positions in plgpio regiseters, + * for different plgpio pins. For example: for pin 27, bit offset is 23, pin + * 28-33 are not supported, pin 95 has offset bit 95, bit 100 has offset bit 1 + */ +static int spear310_p2o(int pin) +{ + int offset = pin; + + if (pin <= 27) + offset += 4; + else if (pin <= 33) + offset = -1; + else if (pin <= 97) + offset -= 2; + else if (pin <= 101) + offset = 101 - pin; + else + offset = -1; + + return offset; +} + +int spear310_o2p(int offset) +{ + if (offset <= 3) + return 101 - offset; + else if (offset <= 31) + return offset - 4; + else + return offset + 2; +} + +static int __devinit plgpio_probe_dt(struct platform_device *pdev, + struct plgpio *plgpio) +{ + struct device_node *np = pdev->dev.of_node; + int ret = -EINVAL; + u32 val; + + if (of_machine_is_compatible("st,spear310")) { + plgpio->p2o = spear310_p2o; + plgpio->o2p = spear310_o2p; + plgpio->p2o_regs = PTO_WDATA_REG | PTO_DIR_REG | PTO_IE_REG | + PTO_RDATA_REG | PTO_MIS_REG; + } + + if (!of_property_read_u32(np, "st-plgpio,ngpio", &val)) { + plgpio->chip.ngpio = val; + } else { + dev_err(&pdev->dev, "DT: Invalid ngpio field\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,enb-reg", &val)) + plgpio->regs.enb = val; + else + plgpio->regs.enb = -1; + + if (!of_property_read_u32(np, "st-plgpio,wdata-reg", &val)) { + plgpio->regs.wdata = val; + } else { + dev_err(&pdev->dev, "DT: Invalid wdata reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,dir-reg", &val)) { + plgpio->regs.dir = val; + } else { + dev_err(&pdev->dev, "DT: Invalid dir reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,ie-reg", &val)) { + plgpio->regs.ie = val; + } else { + dev_err(&pdev->dev, "DT: Invalid ie reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,rdata-reg", &val)) { + plgpio->regs.rdata = val; + } else { + dev_err(&pdev->dev, "DT: Invalid rdata reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,mis-reg", &val)) { + plgpio->regs.mis = val; + } else { + dev_err(&pdev->dev, "DT: Invalid mis reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,eit-reg", &val)) + plgpio->regs.eit = val; + else + plgpio->regs.eit = -1; + + return 0; + +end: + return ret; +} +static int __devinit plgpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct plgpio *plgpio; + struct resource *res; + int ret, irq, i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n"); + return -EBUSY; + } + + plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL); + if (!plgpio) { + dev_err(&pdev->dev, "memory allocation fail\n"); + return -ENOMEM; + } + + plgpio->base = devm_request_and_ioremap(&pdev->dev, res); + if (!plgpio->base) { + dev_err(&pdev->dev, "request and ioremap fail\n"); + return -ENOMEM; + } + + ret = plgpio_probe_dt(pdev, plgpio); + if (ret) { + dev_err(&pdev->dev, "DT probe failed\n"); + return ret; + } + + plgpio->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(plgpio->clk)) + dev_warn(&pdev->dev, "clk_get() failed, work without it\n"); + +#ifdef CONFIG_PM + plgpio->csave_regs = devm_kzalloc(&pdev->dev, + sizeof(*plgpio->csave_regs) * + DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG), + GFP_KERNEL); + if (!plgpio->csave_regs) { + dev_err(&pdev->dev, "csave registers memory allocation fail\n"); + return -ENOMEM; + } +#endif + + platform_set_drvdata(pdev, plgpio); + spin_lock_init(&plgpio->lock); + + plgpio->irq_base = -1; + plgpio->chip.base = -1; + plgpio->chip.request = plgpio_request; + plgpio->chip.free = plgpio_free; + plgpio->chip.direction_input = plgpio_direction_input; + plgpio->chip.direction_output = plgpio_direction_output; + plgpio->chip.get = plgpio_get_value; + plgpio->chip.set = plgpio_set_value; + plgpio->chip.to_irq = plgpio_to_irq; + plgpio->chip.label = dev_name(&pdev->dev); + plgpio->chip.dev = &pdev->dev; + plgpio->chip.owner = THIS_MODULE; + + ret = gpiochip_add(&plgpio->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpio chip\n"); + return ret; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_info(&pdev->dev, "irqs not supported\n"); + return 0; + } + + plgpio->irq_base = irq_alloc_descs(-1, 0, plgpio->chip.ngpio, 0); + if (IS_ERR_VALUE(plgpio->irq_base)) { + /* we would not support irq for gpio */ + dev_warn(&pdev->dev, "couldn't allocate irq base\n"); + return 0; + } + + plgpio->irq_domain = irq_domain_add_legacy(np, plgpio->chip.ngpio, + plgpio->irq_base, 0, &irq_domain_simple_ops, NULL); + if (WARN_ON(!plgpio->irq_domain)) { + dev_err(&pdev->dev, "irq domain init failed\n"); + irq_free_descs(plgpio->irq_base, plgpio->chip.ngpio); + ret = -ENXIO; + goto remove_gpiochip; + } + + irq_set_chained_handler(irq, plgpio_irq_handler); + for (i = 0; i < plgpio->chip.ngpio; i++) { + irq_set_chip_and_handler(i + plgpio->irq_base, &plgpio_irqchip, + handle_simple_irq); + set_irq_flags(i + plgpio->irq_base, IRQF_VALID); + irq_set_chip_data(i + plgpio->irq_base, plgpio); + } + + irq_set_handler_data(irq, plgpio); + dev_info(&pdev->dev, "PLGPIO registered with IRQs\n"); + + return 0; + +remove_gpiochip: + dev_info(&pdev->dev, "Remove gpiochip\n"); + if (gpiochip_remove(&plgpio->chip)) + dev_err(&pdev->dev, "unable to remove gpiochip\n"); + + return ret; +} + +#ifdef CONFIG_PM +static int plgpio_suspend(struct device *dev) +{ + struct plgpio *plgpio = dev_get_drvdata(dev); + int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); + void __iomem *off; + + for (i = 0; i < reg_count; i++) { + off = plgpio->base + i * sizeof(int *); + + if (plgpio->regs.enb != -1) + plgpio->csave_regs[i].enb = + readl_relaxed(plgpio->regs.enb + off); + if (plgpio->regs.eit != -1) + plgpio->csave_regs[i].eit = + readl_relaxed(plgpio->regs.eit + off); + plgpio->csave_regs[i].wdata = readl_relaxed(plgpio->regs.wdata + + off); + plgpio->csave_regs[i].dir = readl_relaxed(plgpio->regs.dir + + off); + plgpio->csave_regs[i].ie = readl_relaxed(plgpio->regs.ie + off); + } + + return 0; +} + +/* + * This is used to correct the values in end registers. End registers contain + * extra bits that might be used for other purpose in platform. So, we shouldn't + * overwrite these bits. This macro, reads given register again, preserves other + * bit values (non-plgpio bits), and retain captured value (plgpio bits). + */ +#define plgpio_prepare_reg(__reg, _off, _mask, _tmp) \ +{ \ + _tmp = readl_relaxed(plgpio->regs.__reg + _off); \ + _tmp &= ~_mask; \ + plgpio->csave_regs[i].__reg = \ + _tmp | (plgpio->csave_regs[i].__reg & _mask); \ +} + +static int plgpio_resume(struct device *dev) +{ + struct plgpio *plgpio = dev_get_drvdata(dev); + int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); + void __iomem *off; + u32 mask, tmp; + + for (i = 0; i < reg_count; i++) { + off = plgpio->base + i * sizeof(int *); + + if (i == reg_count - 1) { + mask = (1 << (plgpio->chip.ngpio - i * + MAX_GPIO_PER_REG)) - 1; + + if (plgpio->regs.enb != -1) + plgpio_prepare_reg(enb, off, mask, tmp); + + if (plgpio->regs.eit != -1) + plgpio_prepare_reg(eit, off, mask, tmp); + + plgpio_prepare_reg(wdata, off, mask, tmp); + plgpio_prepare_reg(dir, off, mask, tmp); + plgpio_prepare_reg(ie, off, mask, tmp); + } + + writel_relaxed(plgpio->csave_regs[i].wdata, plgpio->regs.wdata + + off); + writel_relaxed(plgpio->csave_regs[i].dir, plgpio->regs.dir + + off); + + if (plgpio->regs.eit != -1) + writel_relaxed(plgpio->csave_regs[i].eit, + plgpio->regs.eit + off); + + writel_relaxed(plgpio->csave_regs[i].ie, plgpio->regs.ie + off); + + if (plgpio->regs.enb != -1) + writel_relaxed(plgpio->csave_regs[i].enb, + plgpio->regs.enb + off); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(plgpio_dev_pm_ops, plgpio_suspend, plgpio_resume); + +static const struct of_device_id plgpio_of_match[] = { + { .compatible = "st,spear-plgpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, plgpio_of_match); + +static struct platform_driver plgpio_driver = { + .probe = plgpio_probe, + .driver = { + .owner = THIS_MODULE, + .name = "spear-plgpio", + .pm = &plgpio_dev_pm_ops, + .of_match_table = of_match_ptr(plgpio_of_match), + }, +}; + +static int __init plgpio_init(void) +{ + return platform_driver_register(&plgpio_driver); +} +subsys_initcall(plgpio_init); + +MODULE_AUTHOR("Viresh Kumar "); +MODULE_DESCRIPTION("ST Microlectronics SPEAr PLGPIO driver"); +MODULE_LICENSE("GPL"); From d4a31ee8997b2fbd82837182363cf8fa84abf347 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 13:16:46 +0200 Subject: [PATCH 10/23] ARM: U300: bump IRQs to offset 32 The U300 IRQs were bumped once to offset to 1 (in order to avoid using IRQ 0 which is now NO_IRQ). This was OK as we were still passing the number of irqs in the .nr_irqs field of the machine, with descriptors allocated at boot time. However .nr_irqs should be 0, leading the system to reserve the first 16 IRQs. Then the VIC driver will complain that IRQs 1 thru 15 are pre-allocated, so to avoid this and use free descriptors, move all IRQs up to offset 32. This will all be done away with as we migrate to device tree, so it is an interim solution. Acked-by: Olof Johansson Signed-off-by: Linus Walleij --- arch/arm/mach-u300/core.c | 2 +- arch/arm/mach-u300/include/mach/irqs.h | 116 ++++++++++++------------- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index b8efac4daed8..603c08ec8786 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -1804,7 +1804,7 @@ MACHINE_START(U300, "Ericsson AB U335 S335/B335 Prototype Board") /* Maintainer: Linus Walleij */ .atag_offset = 0x100, .map_io = u300_map_io, - .nr_irqs = NR_IRQS_U300, + .nr_irqs = 0, .init_irq = u300_init_irq, .handle_irq = vic_handle_irq, .timer = &u300_timer, diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h index e27425a63fa1..e85ec3868d04 100644 --- a/arch/arm/mach-u300/include/mach/irqs.h +++ b/arch/arm/mach-u300/include/mach/irqs.h @@ -12,70 +12,70 @@ #ifndef __MACH_IRQS_H #define __MACH_IRQS_H -#define IRQ_U300_INTCON0_START 1 -#define IRQ_U300_INTCON1_START 33 +#define IRQ_U300_INTCON0_START 32 +#define IRQ_U300_INTCON1_START 64 /* These are on INTCON0 - 30 lines */ -#define IRQ_U300_IRQ0_EXT 1 -#define IRQ_U300_IRQ1_EXT 2 -#define IRQ_U300_DMA 3 -#define IRQ_U300_VIDEO_ENC_0 4 -#define IRQ_U300_VIDEO_ENC_1 5 -#define IRQ_U300_AAIF_RX 6 -#define IRQ_U300_AAIF_TX 7 -#define IRQ_U300_AAIF_VGPIO 8 -#define IRQ_U300_AAIF_WAKEUP 9 -#define IRQ_U300_PCM_I2S0_FRAME 10 -#define IRQ_U300_PCM_I2S0_FIFO 11 -#define IRQ_U300_PCM_I2S1_FRAME 12 -#define IRQ_U300_PCM_I2S1_FIFO 13 -#define IRQ_U300_XGAM_GAMCON 14 -#define IRQ_U300_XGAM_CDI 15 -#define IRQ_U300_XGAM_CDICON 16 -#define IRQ_U300_XGAM_PDI 18 -#define IRQ_U300_XGAM_PDICON 19 -#define IRQ_U300_XGAM_GAMEACC 20 -#define IRQ_U300_XGAM_MCIDCT 21 -#define IRQ_U300_APEX 22 -#define IRQ_U300_UART0 23 -#define IRQ_U300_SPI 24 -#define IRQ_U300_TIMER_APP_OS 25 -#define IRQ_U300_TIMER_APP_DD 26 -#define IRQ_U300_TIMER_APP_GP1 27 -#define IRQ_U300_TIMER_APP_GP2 28 -#define IRQ_U300_TIMER_OS 29 -#define IRQ_U300_TIMER_MS 30 -#define IRQ_U300_KEYPAD_KEYBF 31 -#define IRQ_U300_KEYPAD_KEYBR 32 +#define IRQ_U300_IRQ0_EXT 32 +#define IRQ_U300_IRQ1_EXT 33 +#define IRQ_U300_DMA 34 +#define IRQ_U300_VIDEO_ENC_0 35 +#define IRQ_U300_VIDEO_ENC_1 36 +#define IRQ_U300_AAIF_RX 37 +#define IRQ_U300_AAIF_TX 38 +#define IRQ_U300_AAIF_VGPIO 39 +#define IRQ_U300_AAIF_WAKEUP 40 +#define IRQ_U300_PCM_I2S0_FRAME 41 +#define IRQ_U300_PCM_I2S0_FIFO 42 +#define IRQ_U300_PCM_I2S1_FRAME 43 +#define IRQ_U300_PCM_I2S1_FIFO 44 +#define IRQ_U300_XGAM_GAMCON 45 +#define IRQ_U300_XGAM_CDI 46 +#define IRQ_U300_XGAM_CDICON 47 +#define IRQ_U300_XGAM_PDI 49 +#define IRQ_U300_XGAM_PDICON 50 +#define IRQ_U300_XGAM_GAMEACC 51 +#define IRQ_U300_XGAM_MCIDCT 52 +#define IRQ_U300_APEX 53 +#define IRQ_U300_UART0 54 +#define IRQ_U300_SPI 55 +#define IRQ_U300_TIMER_APP_OS 56 +#define IRQ_U300_TIMER_APP_DD 57 +#define IRQ_U300_TIMER_APP_GP1 58 +#define IRQ_U300_TIMER_APP_GP2 59 +#define IRQ_U300_TIMER_OS 60 +#define IRQ_U300_TIMER_MS 61 +#define IRQ_U300_KEYPAD_KEYBF 62 +#define IRQ_U300_KEYPAD_KEYBR 63 /* These are on INTCON1 - 32 lines */ -#define IRQ_U300_GPIO_PORT0 33 -#define IRQ_U300_GPIO_PORT1 34 -#define IRQ_U300_GPIO_PORT2 35 +#define IRQ_U300_GPIO_PORT0 64 +#define IRQ_U300_GPIO_PORT1 65 +#define IRQ_U300_GPIO_PORT2 66 /* These are for DB3150, DB3200 and DB3350 */ -#define IRQ_U300_WDOG 36 -#define IRQ_U300_EVHIST 37 -#define IRQ_U300_MSPRO 38 -#define IRQ_U300_MMCSD_MCIINTR0 39 -#define IRQ_U300_MMCSD_MCIINTR1 40 -#define IRQ_U300_I2C0 41 -#define IRQ_U300_I2C1 42 -#define IRQ_U300_RTC 43 -#define IRQ_U300_NFIF 44 -#define IRQ_U300_NFIF2 45 +#define IRQ_U300_WDOG 67 +#define IRQ_U300_EVHIST 68 +#define IRQ_U300_MSPRO 69 +#define IRQ_U300_MMCSD_MCIINTR0 70 +#define IRQ_U300_MMCSD_MCIINTR1 71 +#define IRQ_U300_I2C0 72 +#define IRQ_U300_I2C1 73 +#define IRQ_U300_RTC 74 +#define IRQ_U300_NFIF 75 +#define IRQ_U300_NFIF2 76 /* The DB3350-specific interrupt lines */ -#define IRQ_U300_ISP_F0 46 -#define IRQ_U300_ISP_F1 47 -#define IRQ_U300_ISP_F2 48 -#define IRQ_U300_ISP_F3 49 -#define IRQ_U300_ISP_F4 50 -#define IRQ_U300_GPIO_PORT3 51 -#define IRQ_U300_SYSCON_PLL_LOCK 52 -#define IRQ_U300_UART1 53 -#define IRQ_U300_GPIO_PORT4 54 -#define IRQ_U300_GPIO_PORT5 55 -#define IRQ_U300_GPIO_PORT6 56 -#define U300_VIC_IRQS_END 57 +#define IRQ_U300_ISP_F0 77 +#define IRQ_U300_ISP_F1 78 +#define IRQ_U300_ISP_F2 79 +#define IRQ_U300_ISP_F3 80 +#define IRQ_U300_ISP_F4 81 +#define IRQ_U300_GPIO_PORT3 82 +#define IRQ_U300_SYSCON_PLL_LOCK 83 +#define IRQ_U300_UART1 84 +#define IRQ_U300_GPIO_PORT4 85 +#define IRQ_U300_GPIO_PORT5 86 +#define IRQ_U300_GPIO_PORT6 87 +#define U300_VIC_IRQS_END 88 /* Maximum 8*7 GPIO lines */ #ifdef CONFIG_PINCTRL_COH901 From a6c45b99a658521291cfb66ecf035cc58b38f206 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 18:31:20 +0200 Subject: [PATCH 11/23] pinctrl/coh901: use irqdomain, allocate irqdescs This switches the COH 901 pinctrl driver to allocate its GPIO IRQs dynamically, and start to use a linear irqdomain to map from the hardware IRQs. This way we can cut away the complex allocation of IRQ numbers from the file. Signed-off-by: Linus Walleij --- arch/arm/mach-u300/core.c | 1 - arch/arm/mach-u300/include/mach/irqs.h | 10 ---- drivers/pinctrl/pinctrl-coh901.c | 60 +++++++++++++++----- include/linux/platform_data/pinctrl-coh901.h | 2 - 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c index 603c08ec8786..ce2de0d6f2eb 100644 --- a/arch/arm/mach-u300/core.c +++ b/arch/arm/mach-u300/core.c @@ -1445,7 +1445,6 @@ static struct platform_device pinctrl_device = { static struct u300_gpio_platform u300_gpio_plat = { .ports = 7, .gpio_base = 0, - .gpio_irq_base = IRQ_U300_GPIO_BASE, .pinctrl_device = &pinctrl_device, }; diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h index e85ec3868d04..21d5e76a6cd3 100644 --- a/arch/arm/mach-u300/include/mach/irqs.h +++ b/arch/arm/mach-u300/include/mach/irqs.h @@ -77,14 +77,4 @@ #define IRQ_U300_GPIO_PORT6 87 #define U300_VIC_IRQS_END 88 -/* Maximum 8*7 GPIO lines */ -#ifdef CONFIG_PINCTRL_COH901 -#define IRQ_U300_GPIO_BASE (U300_VIC_IRQS_END) -#define IRQ_U300_GPIO_END (IRQ_U300_GPIO_BASE + 56) -#else -#define IRQ_U300_GPIO_END (U300_VIC_IRQS_END) -#endif - -#define NR_IRQS_U300 (IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START) - #endif diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index b446c9641212..152efae3df8f 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -67,7 +68,6 @@ struct u300_gpio { struct resource *memres; void __iomem *base; struct device *dev; - int irq_base; u32 stride; /* Register offsets */ u32 pcr; @@ -83,6 +83,7 @@ struct u300_gpio_port { struct list_head node; struct u300_gpio *gpio; char name[8]; + struct irq_domain *domain; int irq; int number; u8 toggle_edge_mode; @@ -314,10 +315,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct u300_gpio *gpio = to_u300_gpio(chip); - int retirq = gpio->irq_base + offset; + int portno = offset >> 3; + struct u300_gpio_port *port = NULL; + struct list_head *p; + int retirq; - dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset, - retirq); + list_for_each(p, &gpio->port_list) { + port = list_entry(p, struct u300_gpio_port, node); + if (port->number == portno) + break; + } + if (port == NULL) { + dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n", + offset); + return -EINVAL; + } + + /* + * The local hwirqs on the port are the lower three bits, there + * are exactly 8 IRQs per port since they are 8-bit + */ + retirq = irq_find_mapping(port->domain, (offset & 0x7)); + + dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n", + offset, retirq, port->number); return retirq; } @@ -467,7 +488,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; if ((trigger & IRQF_TRIGGER_RISING) && @@ -503,10 +524,12 @@ static void u300_gpio_irq_enable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; + dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", + d->hwirq, port->name, offset); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -517,7 +540,7 @@ static void u300_gpio_irq_disable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; @@ -555,8 +578,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) int irqoffset; for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { - int pin_irq = gpio->irq_base + (port->number << 3) - + irqoffset; + int pin_irq = irq_find_mapping(port->domain, irqoffset); int offset = pinoffset + irqoffset; dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n", @@ -631,6 +653,8 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio) list_for_each_safe(p, n, &gpio->port_list) { port = list_entry(p, struct u300_gpio_port, node); list_del(&port->node); + if (port->domain) + irq_domain_remove(port->domain); kfree(port); } } @@ -653,7 +677,6 @@ static int __init u300_gpio_probe(struct platform_device *pdev) gpio->chip = u300_gpio_chip; gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; - gpio->irq_base = plat->gpio_irq_base; gpio->chip.dev = &pdev->dev; gpio->chip.base = plat->gpio_base; gpio->dev = &pdev->dev; @@ -732,18 +755,26 @@ static int __init u300_gpio_probe(struct platform_device *pdev) port->irq = platform_get_irq_byname(pdev, port->name); - dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq, + dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq, port->name); + port->domain = irq_domain_add_linear(pdev->dev.of_node, + U300_GPIO_PINS_PER_PORT, + &irq_domain_simple_ops, + port); + if (!port->domain) + goto err_no_domain; + irq_set_chained_handler(port->irq, u300_gpio_irq_handler); irq_set_handler_data(port->irq, port); /* For each GPIO pin set the unique IRQ handler */ for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { - int irqno = gpio->irq_base + (portno << 3) + i; + int irqno = irq_create_mapping(port->domain, i); - dev_dbg(gpio->dev, "handler for IRQ %d on %s\n", - irqno, port->name); + dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n", + gpio->chip.base + (port->number << 3) + i, + port->name, irqno); irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, handle_simple_irq); set_irq_flags(irqno, IRQF_VALID); @@ -776,6 +807,7 @@ static int __init u300_gpio_probe(struct platform_device *pdev) err_no_pinctrl: err = gpiochip_remove(&gpio->chip); err_no_chip: +err_no_domain: err_no_port: u300_gpio_free_ports(gpio); iounmap(gpio->base); diff --git a/include/linux/platform_data/pinctrl-coh901.h b/include/linux/platform_data/pinctrl-coh901.h index 30dea251b835..27a23b318cef 100644 --- a/include/linux/platform_data/pinctrl-coh901.h +++ b/include/linux/platform_data/pinctrl-coh901.h @@ -13,13 +13,11 @@ * struct u300_gpio_platform - U300 GPIO platform data * @ports: number of GPIO block ports * @gpio_base: first GPIO number for this block (use a free range) - * @gpio_irq_base: first GPIO IRQ number for this block (use a free range) * @pinctrl_device: pin control device to spawn as child */ struct u300_gpio_platform { u8 ports; int gpio_base; - int gpio_irq_base; struct platform_device *pinctrl_device; }; From 585583f54f577d7fd93247101b9f61c8bbbd21f1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 18:49:05 +0200 Subject: [PATCH 12/23] pinctrl/coh901: convert to use managed resources This switches the COH 901 pin controller to use managed resources (devm_*) for memory remaps, clocks, etc. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-coh901.c | 62 ++++++++++---------------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 152efae3df8f..5c7daf9169e8 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -65,7 +65,6 @@ struct u300_gpio { struct gpio_chip chip; struct list_head port_list; struct clk *clk; - struct resource *memres; void __iomem *base; struct device *dev; u32 stride; @@ -663,17 +662,16 @@ static int __init u300_gpio_probe(struct platform_device *pdev) { struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); struct u300_gpio *gpio; + struct resource *memres; int err = 0; int portno; u32 val; u32 ifr; int i; - gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL); - if (gpio == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + gpio = devm_kzalloc(&pdev->dev, sizeof(struct u300_gpio), GFP_KERNEL); + if (gpio == NULL) return -ENOMEM; - } gpio->chip = u300_gpio_chip; gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; @@ -681,37 +679,29 @@ static int __init u300_gpio_probe(struct platform_device *pdev) gpio->chip.base = plat->gpio_base; gpio->dev = &pdev->dev; - /* Get GPIO clock */ - gpio->clk = clk_get(gpio->dev, NULL); + memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!memres) { + dev_err(gpio->dev, "could not get GPIO memory resource\n"); + return -ENODEV; + } + + gpio->base = devm_request_and_ioremap(&pdev->dev, memres); + if (!gpio->base) { + dev_err(gpio->dev, "could not get remap memory\n"); + return -ENOMEM; + } + + gpio->clk = devm_clk_get(gpio->dev, NULL); if (IS_ERR(gpio->clk)) { err = PTR_ERR(gpio->clk); dev_err(gpio->dev, "could not get GPIO clock\n"); - goto err_no_clk; + return err; } + err = clk_prepare_enable(gpio->clk); if (err) { dev_err(gpio->dev, "could not enable GPIO clock\n"); - goto err_no_clk_enable; - } - - gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!gpio->memres) { - dev_err(gpio->dev, "could not get GPIO memory resource\n"); - err = -ENODEV; - goto err_no_resource; - } - - if (!request_mem_region(gpio->memres->start, - resource_size(gpio->memres), - "GPIO Controller")) { - err = -ENODEV; - goto err_no_ioregion; - } - - gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres)); - if (!gpio->base) { - err = -ENOMEM; - goto err_no_ioremap; + return err; } dev_info(gpio->dev, @@ -810,16 +800,7 @@ err_no_chip: err_no_domain: err_no_port: u300_gpio_free_ports(gpio); - iounmap(gpio->base); -err_no_ioremap: - release_mem_region(gpio->memres->start, resource_size(gpio->memres)); -err_no_ioregion: -err_no_resource: clk_disable_unprepare(gpio->clk); -err_no_clk_enable: - clk_put(gpio->clk); -err_no_clk: - kfree(gpio); dev_info(&pdev->dev, "module ERROR:%d\n", err); return err; } @@ -838,13 +819,8 @@ static int __exit u300_gpio_remove(struct platform_device *pdev) return err; } u300_gpio_free_ports(gpio); - iounmap(gpio->base); - release_mem_region(gpio->memres->start, - resource_size(gpio->memres)); clk_disable_unprepare(gpio->clk); - clk_put(gpio->clk); platform_set_drvdata(pdev, NULL); - kfree(gpio); return 0; } From b36bdc5911effe819e415b144388853bf07a543b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Oct 2012 19:17:56 +0200 Subject: [PATCH 13/23] pinctrl/u300: use managed resources This converts the U300 pin controller to use managed resources (devm_*) for it's memory region. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-u300.c | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 309f5b9a70ec..2e9825e304af 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -663,8 +663,6 @@ static const struct pinctrl_pin_desc u300_pads[] = { struct u300_pmx { struct device *dev; struct pinctrl_dev *pctl; - u32 phybase; - u32 physize; void __iomem *virtbase; }; @@ -1110,7 +1108,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) struct u300_pmx *upmx; struct resource *res; struct gpio_chip *gpio_chip = dev_get_platdata(&pdev->dev); - int ret; int i; /* Create state holders etc for this driver */ @@ -1123,26 +1120,15 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; - upmx->phybase = res->start; - upmx->physize = resource_size(res); - if (request_mem_region(upmx->phybase, upmx->physize, - DRIVER_NAME) == NULL) { - ret = -ENOMEM; - goto out_no_memregion; - } - - upmx->virtbase = ioremap(upmx->phybase, upmx->physize); - if (!upmx->virtbase) { - ret = -ENOMEM; - goto out_no_remap; - } + upmx->virtbase = devm_request_and_ioremap(&pdev->dev, res); + if (!upmx->virtbase) + return -ENOMEM; upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx); if (!upmx->pctl) { dev_err(&pdev->dev, "could not register U300 pinmux driver\n"); - ret = -EINVAL; - goto out_no_pmx; + return -EINVAL; } /* We will handle a range of GPIO pins */ @@ -1156,14 +1142,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) dev_info(&pdev->dev, "initialized U300 pin control driver\n"); return 0; - -out_no_pmx: - iounmap(upmx->virtbase); -out_no_remap: - platform_set_drvdata(pdev, NULL); -out_no_memregion: - release_mem_region(upmx->phybase, upmx->physize); - return ret; } static int __devexit u300_pmx_remove(struct platform_device *pdev) @@ -1171,8 +1149,6 @@ static int __devexit u300_pmx_remove(struct platform_device *pdev) struct u300_pmx *upmx = platform_get_drvdata(pdev); pinctrl_unregister(upmx->pctl); - iounmap(upmx->virtbase); - release_mem_region(upmx->phybase, upmx->physize); platform_set_drvdata(pdev, NULL); return 0; From e1b29abef69e34a42169cd65d7249b18574c94e8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 5 Nov 2012 21:42:16 +0800 Subject: [PATCH 14/23] pinctrl: u300: Staticize non-exported symbols Staticize u300_pin_config_get() and u300_pin_config_set() functions. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-u300.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 2e9825e304af..d756cce588fd 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -1052,9 +1052,8 @@ static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin) return NULL; } -int u300_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *config) +static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *config) { struct pinctrl_gpio_range *range = u300_match_gpio_range(pin); @@ -1067,9 +1066,8 @@ int u300_pin_config_get(struct pinctrl_dev *pctldev, config); } -int u300_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long config) +static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long config) { struct pinctrl_gpio_range *range = u300_match_gpio_range(pin); int ret; From 33dfc41461b77e2b38673ec1b5622b1d9340324d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 5 Nov 2012 21:44:28 +0800 Subject: [PATCH 15/23] pinctrl: sirf: Staticize non-exported symbol Staticize sirfsoc_gpio_irq_map() function. Signed-off-by: Axel Lin Acked-by: Barry Song Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-sirf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 16ec7d4d81ee..a3905e58d1b3 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -1642,8 +1642,8 @@ static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset, spin_unlock_irqrestore(&bank->lock, flags); } -int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) +static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct sirfsoc_gpio_bank *bank = d->host_data; From 165adc9c1734a3f3bdbc6dc7c7a29bbefb424006 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 14:49:39 +0100 Subject: [PATCH 16/23] gpiolib: fix up function prototypes etc Commit 69e1601bca88809dc118abd1becb02c15a02ec71 "gpiolib: provide provision to register pin ranges" Got most of it's function prototypes wrong, so fix this up by: - Moving the void declarations into static inlines in (previously the actual prototypes were declared here...) - Declare the gpiochip_add_pin_range() and gpiochip_remove_pin_ranges() functions in together with the pin range struct declaration itself. - Actually only implement these very functions in gpiolib.c if CONFIG_PINCTRL is set. - Additionally export the symbols since modules will need to be able to do this. Reviewed-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 10 +++++----- include/asm-generic/gpio.h | 6 ++++++ include/linux/gpio.h | 24 ++++++++++++++++++------ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f0b07bbfcc9a..1e1a7cabc57e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1185,6 +1185,7 @@ struct gpio_chip *gpiochip_find(void *data, EXPORT_SYMBOL_GPL(gpiochip_find); #ifdef CONFIG_PINCTRL + void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, unsigned int pin_base, unsigned int npins) { @@ -1206,6 +1207,7 @@ void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, list_add_tail(&pin_range->node, &chip->pin_ranges); } +EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); void gpiochip_remove_pin_ranges(struct gpio_chip *chip) { @@ -1217,11 +1219,9 @@ void gpiochip_remove_pin_ranges(struct gpio_chip *chip) &pin_range->range); } } -#else -void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins) {} -void gpiochip_remove_pin_ranges(struct gpio_chip *chip) {} -#endif +EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); + +#endif /* CONFIG_PINCTRL */ /* These "optional" allocation calls help prevent drivers from stomping * on each other, and help provide better diagnostics in debugfs. diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 92e5c432421c..2e60de4265ac 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -49,6 +49,7 @@ struct module; struct device_node; #ifdef CONFIG_PINCTRL + /** * struct gpio_pin_range - pin range controlled by a gpio chip * @head: list for maintaining set of pin ranges, used internally @@ -61,6 +62,11 @@ struct gpio_pin_range { struct pinctrl_dev *pctldev; struct pinctrl_gpio_range range; }; + +void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins); +void gpiochip_remove_pin_ranges(struct gpio_chip *chip); + #endif /** diff --git a/include/linux/gpio.h b/include/linux/gpio.h index a28445992b7f..21d28b930dc7 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -72,9 +72,9 @@ static inline int irq_to_gpio(unsigned int irq) return -EINVAL; } -#endif +#endif /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */ -#else +#else /* ! CONFIG_GENERIC_GPIO */ #include #include @@ -231,9 +231,21 @@ static inline int irq_to_gpio(unsigned irq) return -EINVAL; } -void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins); -void gpiochip_remove_pin_ranges(struct gpio_chip *chip); -#endif +#ifdef CONFIG_PINCTRL + +static inline void +gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) +{ +} + +static inline void +gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ +} + +#endif /* CONFIG_PINCTRL */ + +#endif /* ! CONFIG_GENERIC_GPIO */ #endif /* __LINUX_GPIO_H */ From 167c1af9443757bb9d27ceff8ba4304302cb0651 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 14:58:55 +0100 Subject: [PATCH 17/23] gpiolib-of: staticize the pin range calls Commit 69e1601bca88809dc118abd1becb02c15a02ec71 "gpiolib: provide provision to register pin ranges" Declared the of_gpiochip_[add|remove]_pin_range() global while they should be static as they are only ever used in this file. Let's convert them to static. Reviewed-by: Stephen Warren Reviewed-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index a5b90c8e9844..220caa5978f7 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -218,7 +218,7 @@ err0: EXPORT_SYMBOL(of_mm_gpiochip_add); #ifdef CONFIG_PINCTRL -void of_gpiochip_add_pin_range(struct gpio_chip *chip) +static void of_gpiochip_add_pin_range(struct gpio_chip *chip) { struct device_node *np = chip->of_node; struct gpio_pin_range *pin_range; @@ -254,7 +254,7 @@ void of_gpiochip_add_pin_range(struct gpio_chip *chip) } while (index++); } -void of_gpiochip_remove_pin_range(struct gpio_chip *chip) +static void of_gpiochip_remove_pin_range(struct gpio_chip *chip) { struct gpio_pin_range *pin_range, *tmp; @@ -265,8 +265,8 @@ void of_gpiochip_remove_pin_range(struct gpio_chip *chip) } } #else -void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} -void of_gpiochip_remove_pin_range(struct gpio_chip *chip) {} +static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} +static void of_gpiochip_remove_pin_range(struct gpio_chip *chip) {} #endif void of_gpiochip_add(struct gpio_chip *chip) From e93fa3f24353e45b189bae656ba000d0533777a3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 15:03:47 +0100 Subject: [PATCH 18/23] gpiolib: remove duplicate pin range code Commit 69e1601bca88809dc118abd1becb02c15a02ec71 "gpiolib: provide provision to register pin ranges" Introduced both of_gpiochip_remove_pin_range() and gpiochip_remove_pin_ranges(). But the contents are exactly the same so remove the OF one and rely on the range deletion in the core. Reviewed-by: Stephen Warren Reviewed-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 220caa5978f7..67403e47e4dc 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -254,19 +254,8 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) } while (index++); } -static void of_gpiochip_remove_pin_range(struct gpio_chip *chip) -{ - struct gpio_pin_range *pin_range, *tmp; - - list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) { - list_del(&pin_range->node); - pinctrl_remove_gpio_range(pin_range->pctldev, - &pin_range->range); - } -} #else static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} -static void of_gpiochip_remove_pin_range(struct gpio_chip *chip) {} #endif void of_gpiochip_add(struct gpio_chip *chip) @@ -288,7 +277,7 @@ void of_gpiochip_add(struct gpio_chip *chip) void of_gpiochip_remove(struct gpio_chip *chip) { - of_gpiochip_remove_pin_range(chip); + gpiochip_remove_pin_ranges(chip); if (chip->of_node) of_node_put(chip->of_node); From 9ef0d6f7628bdcb5cc3c11623930f2527a3881a0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 15:15:44 +0100 Subject: [PATCH 19/23] gpiolib: call pin removal in chip removal function This makes us call gpiochio_remove_pin_ranges() in the gpiochip_remove() function, so we get rid of ranges when freeing the chip. Reviewed-by: Stephen Warren Reviewed-by: Viresh Kumar Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1e1a7cabc57e..bcf9b9914fb7 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1127,6 +1127,7 @@ int gpiochip_remove(struct gpio_chip *chip) spin_lock_irqsave(&gpio_lock, flags); + gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); for (id = chip->base; id < chip->base + chip->ngpio; id++) { From 1e63d7b9363f0c57d00991f9f2e0af374dfc591a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 16:03:35 +0100 Subject: [PATCH 20/23] gpiolib: separation of pin concerns The fact that of_gpiochip_add_pin_range() and gpiochip_add_pin_range() share too much code is fragile and will invariably mean that bugs need to be fixed in two places instead of one. So separate the concerns of gpiolib.c and gpiolib-of.c and have the latter call the former as back-end. This is necessary also when going forward with other device descriptions such as ACPI. This is done by: - Adding a return code to gpiochip_add_pin_range() so we can reliably check whether this succeeds. - Get rid of the custom of_pinctrl_add_gpio_range() from pinctrl. Instead create of_pinctrl_get() to just retrive the pin controller per se from an OF node. This composite function was just begging to be deleted, it was way to purpose-specific. - Use pinctrl_dev_get_name() to get the name of the retrieved pin controller and use that to call back into the generic gpiochip_add_pin_range(). Now the pin range is only allocated and tied to a pin controller from the core implementation in gpiolib.c. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 23 +++++++++-------------- drivers/gpio/gpiolib.c | 8 +++++--- drivers/pinctrl/devicetree.c | 4 +--- include/asm-generic/gpio.h | 4 ++-- include/linux/gpio.h | 2 +- include/linux/pinctrl/pinctrl.h | 7 ++----- 6 files changed, 20 insertions(+), 28 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 67403e47e4dc..a40cd84c5c10 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -221,8 +221,8 @@ EXPORT_SYMBOL(of_mm_gpiochip_add); static void of_gpiochip_add_pin_range(struct gpio_chip *chip) { struct device_node *np = chip->of_node; - struct gpio_pin_range *pin_range; struct of_phandle_args pinspec; + struct pinctrl_dev *pctldev; int index = 0, ret; if (!np) @@ -234,22 +234,17 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) if (ret) break; - pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), - GFP_KERNEL); - if (!pin_range) { - pr_err("%s: GPIO chip: failed to allocate pin ranges\n", - chip->label); + pctldev = of_pinctrl_get(pinspec.np); + if (!pctldev) break; - } - pin_range->range.name = chip->label; - pin_range->range.base = chip->base; - pin_range->range.pin_base = pinspec.args[0]; - pin_range->range.npins = pinspec.args[1]; - pin_range->pctldev = of_pinctrl_add_gpio_range(pinspec.np, - &pin_range->range); + ret = gpiochip_add_pin_range(chip, + pinctrl_dev_get_name(pctldev), + pinspec.args[0], + pinspec.args[1]); - list_add_tail(&pin_range->node, &chip->pin_ranges); + if (ret) + break; } while (index++); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bcf9b9914fb7..c5f650095faa 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1187,8 +1187,8 @@ EXPORT_SYMBOL_GPL(gpiochip_find); #ifdef CONFIG_PINCTRL -void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins) +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) { struct gpio_pin_range *pin_range; @@ -1196,7 +1196,7 @@ void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, if (!pin_range) { pr_err("%s: GPIO chip: failed to allocate pin ranges\n", chip->label); - return; + return -ENOMEM; } pin_range->range.name = chip->label; @@ -1207,6 +1207,8 @@ void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, &pin_range->range); list_add_tail(&pin_range->node, &chip->pin_ranges); + + return 0; } EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 6728ec71cb65..fe2d1af7cfa0 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -106,8 +106,7 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np) return NULL; } -struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, - struct pinctrl_gpio_range *range) +struct pinctrl_dev *of_pinctrl_get(struct device_node *np) { struct pinctrl_dev *pctldev; @@ -115,7 +114,6 @@ struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, if (!pctldev) return NULL; - pinctrl_add_gpio_range(pctldev, range); return pctldev; } diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 2e60de4265ac..50d995e7e44a 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -63,8 +63,8 @@ struct gpio_pin_range { struct pinctrl_gpio_range range; }; -void gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins); +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins); void gpiochip_remove_pin_ranges(struct gpio_chip *chip); #endif diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 21d28b930dc7..81bbfe5b5de6 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -233,7 +233,7 @@ static inline int irq_to_gpio(unsigned irq) #ifdef CONFIG_PINCTRL -static inline void +static inline int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, unsigned int pin_base, unsigned int npins) { diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index 434e5a94e131..4a58428bc793 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -141,16 +141,13 @@ extern struct pinctrl_dev *find_pinctrl_and_add_gpio_range(const char *devname, struct pinctrl_gpio_range *range); #ifdef CONFIG_OF -extern struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, - struct pinctrl_gpio_range *range); +extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np); #else static inline -struct pinctrl_dev *of_pinctrl_add_gpio_range(struct device_node *np, - struct pinctrl_gpio_range *range) +struct pinctrl_dev *of_pinctrl_get(struct device_node *np) { return NULL; } - #endif /* CONFIG_OF */ extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev); From 50309a9c2e576ac4ad29e30f5854acb87bdc2ac4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Nov 2012 17:16:39 +0100 Subject: [PATCH 21/23] gpiolib: iron out include ladder mistakes The <*/gpio.h> includes are updated again: now we need to account for the problem introduced by commit: 595679a8038584df7b9398bf34f61db3c038bfea "gpiolib: fix up function prototypes etc" Actually we need static inlines in include/asm-generic/gpio.h as well since we may have GPIOLIB but not PINCTRL. Make sure to move all the CONFIG_PINCTRL business to the end of the file so we are sure we have declared struct gpio_chip. And we need to keep the static inlines in but here for the !CONFIG_GENERIC_GPIO case, and then we may as well throw in a few warnings like the other prototypes there, if someone would have the bad taste of compiling without GENERIC_GPIO even. Signed-off-by: Linus Walleij --- include/asm-generic/gpio.h | 56 ++++++++++++++++++++++++-------------- include/linux/gpio.h | 7 ++--- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 50d995e7e44a..2b84fc32fae2 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -48,27 +48,6 @@ struct seq_file; struct module; struct device_node; -#ifdef CONFIG_PINCTRL - -/** - * struct gpio_pin_range - pin range controlled by a gpio chip - * @head: list for maintaining set of pin ranges, used internally - * @pctldev: pinctrl device which handles corresponding pins - * @range: actual range of pins controlled by a gpio controller - */ - -struct gpio_pin_range { - struct list_head node; - struct pinctrl_dev *pctldev; - struct pinctrl_gpio_range range; -}; - -int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, - unsigned int pin_base, unsigned int npins); -void gpiochip_remove_pin_ranges(struct gpio_chip *chip); - -#endif - /** * struct gpio_chip - abstract a GPIO controller * @label: for diagnostics @@ -288,4 +267,39 @@ static inline void gpio_unexport(unsigned gpio) } #endif /* CONFIG_GPIO_SYSFS */ +#ifdef CONFIG_PINCTRL + +/** + * struct gpio_pin_range - pin range controlled by a gpio chip + * @head: list for maintaining set of pin ranges, used internally + * @pctldev: pinctrl device which handles corresponding pins + * @range: actual range of pins controlled by a gpio controller + */ + +struct gpio_pin_range { + struct list_head node; + struct pinctrl_dev *pctldev; + struct pinctrl_gpio_range range; +}; + +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins); +void gpiochip_remove_pin_ranges(struct gpio_chip *chip); + +#else + +static inline int +gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int pin_base, unsigned int npins) +{ + return 0; +} + +static inline void +gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ +} + +#endif /* CONFIG_PINCTRL */ + #endif /* _ASM_GENERIC_GPIO_H */ diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 81bbfe5b5de6..7ba2762abbc9 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -231,21 +231,20 @@ static inline int irq_to_gpio(unsigned irq) return -EINVAL; } -#ifdef CONFIG_PINCTRL - static inline int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, unsigned int pin_base, unsigned int npins) { + WARN_ON(1); + return -EINVAL; } static inline void gpiochip_remove_pin_ranges(struct gpio_chip *chip) { + WARN_ON(1); } -#endif /* CONFIG_PINCTRL */ - #endif /* ! CONFIG_GENERIC_GPIO */ #endif /* __LINUX_GPIO_H */ From f4f8e5635f398645d614dff5a07598651faf3ead Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 27 Oct 2012 15:21:38 +0530 Subject: [PATCH 22/23] pinctrl: SPEAr: Add gpio ranges support Most of SPEAr SoCs, which support pinctrl, can configure & use pads as gpio. This patch gpio enable support for SPEAr pinctrl drivers. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Linus Walleij --- drivers/pinctrl/spear/Kconfig | 4 + drivers/pinctrl/spear/pinctrl-spear.c | 107 +++++++-- drivers/pinctrl/spear/pinctrl-spear.h | 46 ++++ drivers/pinctrl/spear/pinctrl-spear1310.c | 264 ++++++++++++++++++++++ drivers/pinctrl/spear/pinctrl-spear300.c | 2 + drivers/pinctrl/spear/pinctrl-spear310.c | 2 + drivers/pinctrl/spear/pinctrl-spear320.c | 2 + drivers/pinctrl/spear/pinctrl-spear3xx.c | 37 +++ 8 files changed, 447 insertions(+), 17 deletions(-) diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig index 6f9a1e8bf575..04d93e602674 100644 --- a/drivers/pinctrl/spear/Kconfig +++ b/drivers/pinctrl/spear/Kconfig @@ -25,21 +25,25 @@ config PINCTRL_SPEAR310 bool "ST Microelectronics SPEAr310 SoC pin controller driver" depends on MACH_SPEAR310 select PINCTRL_SPEAR3XX + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR320 bool "ST Microelectronics SPEAr320 SoC pin controller driver" depends on MACH_SPEAR320 select PINCTRL_SPEAR3XX + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR1310 bool "ST Microelectronics SPEAr1310 SoC pin controller driver" depends on MACH_SPEAR1310 select PINCTRL_SPEAR + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR1340 bool "ST Microelectronics SPEAr1340 SoC pin controller driver" depends on MACH_SPEAR1340 select PINCTRL_SPEAR + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR_PLGPIO bool "SPEAr SoC PLGPIO Controller" diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index b1fd6ee33c6c..cbca6dc66eb7 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,28 @@ static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg) writel_relaxed(val, pmx->vbase + reg); } +static void muxregs_endisable(struct spear_pmx *pmx, + struct spear_muxreg *muxregs, u8 count, bool enable) +{ + struct spear_muxreg *muxreg; + u32 val, temp, j; + + for (j = 0; j < count; j++) { + muxreg = &muxregs[j]; + + val = pmx_readl(pmx, muxreg->reg); + val &= ~muxreg->mask; + + if (enable) + temp = muxreg->val; + else + temp = ~muxreg->val; + + val |= muxreg->mask & temp; + pmx_writel(pmx, val, muxreg->reg); + } +} + static int set_mode(struct spear_pmx *pmx, int mode) { struct spear_pmx_mode *pmx_mode = NULL; @@ -70,6 +93,17 @@ static int set_mode(struct spear_pmx *pmx, int mode) return 0; } +void __devinit +pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup, + unsigned count, u16 reg) +{ + int i = 0, j = 0; + + for (; i < count; i++) + for (; j < gpio_pingroup[i].nmuxregs; j++) + gpio_pingroup[i].muxregs[j].reg = reg; +} + void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg) { struct spear_pingroup *pgroup; @@ -216,9 +250,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct spear_pingroup *pgroup; const struct spear_modemux *modemux; - struct spear_muxreg *muxreg; - u32 val, temp; - int i, j; + int i; bool found = false; pgroup = pmx->machdata->groups[group]; @@ -233,20 +265,8 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, } found = true; - for (j = 0; j < modemux->nmuxregs; j++) { - muxreg = &modemux->muxregs[j]; - - val = pmx_readl(pmx, muxreg->reg); - val &= ~muxreg->mask; - - if (enable) - temp = muxreg->val; - else - temp = ~muxreg->val; - - val |= muxreg->mask & temp; - pmx_writel(pmx, val, muxreg->reg); - } + muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs, + enable); } if (!found) { @@ -270,12 +290,65 @@ static void spear_pinctrl_disable(struct pinctrl_dev *pctldev, spear_pinctrl_endisable(pctldev, function, group, false); } +/* gpio with pinmux */ +static struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx, + unsigned pin) +{ + struct spear_gpio_pingroup *gpio_pingroup; + int i = 0, j; + + if (!pmx->machdata->gpio_pingroups) + return NULL; + + for (; i < pmx->machdata->ngpio_pingroups; i++) { + gpio_pingroup = &pmx->machdata->gpio_pingroups[i]; + + for (j = 0; j < gpio_pingroup->npins; j++) { + if (gpio_pingroup->pins[j] == pin) + return gpio_pingroup; + } + } + + return ERR_PTR(-EINVAL); +} + +static int gpio_request_endisable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool enable) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + struct spear_gpio_pingroup *gpio_pingroup; + + gpio_pingroup = get_gpio_pingroup(pmx, offset); + if (IS_ERR(gpio_pingroup)) + return PTR_ERR(gpio_pingroup); + + if (gpio_pingroup) + muxregs_endisable(pmx, gpio_pingroup->muxregs, + gpio_pingroup->nmuxregs, enable); + + return 0; +} + +static int gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + return gpio_request_endisable(pctldev, range, offset, true); +} + +static void gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + gpio_request_endisable(pctldev, range, offset, false); +} + static struct pinmux_ops spear_pinmux_ops = { .get_functions_count = spear_pinctrl_get_funcs_count, .get_function_name = spear_pinctrl_get_func_name, .get_function_groups = spear_pinctrl_get_func_groups, .enable = spear_pinctrl_enable, .disable = spear_pinctrl_disable, + .gpio_request_enable = gpio_request_enable, + .gpio_disable_free = gpio_disable_free, }; static struct pinctrl_desc spear_pinctrl_desc = { diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h index d950eb78d939..94f142c10c19 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.h +++ b/drivers/pinctrl/spear/pinctrl-spear.h @@ -12,6 +12,7 @@ #ifndef __PINMUX_SPEAR_H__ #define __PINMUX_SPEAR_H__ +#include #include #include @@ -46,6 +47,44 @@ struct spear_muxreg { u32 val; }; +struct spear_gpio_pingroup { + const unsigned *pins; + unsigned npins; + struct spear_muxreg *muxregs; + u8 nmuxregs; +}; + +/* ste: set to enable */ +#define DEFINE_MUXREG(__pins, __muxreg, __mask, __ste) \ +static struct spear_muxreg __pins##_muxregs[] = { \ + { \ + .reg = __muxreg, \ + .mask = __mask, \ + .val = __ste ? __mask : 0, \ + }, \ +} + +#define DEFINE_2_MUXREG(__pins, __muxreg1, __muxreg2, __mask, __ste1, __ste2) \ +static struct spear_muxreg __pins##_muxregs[] = { \ + { \ + .reg = __muxreg1, \ + .mask = __mask, \ + .val = __ste1 ? __mask : 0, \ + }, { \ + .reg = __muxreg2, \ + .mask = __mask, \ + .val = __ste2 ? __mask : 0, \ + }, \ +} + +#define GPIO_PINGROUP(__pins) \ + { \ + .pins = __pins, \ + .npins = ARRAY_SIZE(__pins), \ + .muxregs = __pins##_muxregs, \ + .nmuxregs = ARRAY_SIZE(__pins##_muxregs), \ + } + /** * struct spear_modemux - SPEAr mode mux configuration * @modes: mode ids supported by this group of muxregs @@ -100,6 +139,8 @@ struct spear_function { * @nfunctions: The numbmer of entries in @functions. * @groups: An array describing all pin groups the pin SoC supports. * @ngroups: The numbmer of entries in @groups. + * @gpio_pingroups: gpio pingroups + * @ngpio_pingroups: gpio pingroups count * * @modes_supported: Does SoC support modes * @mode: mode configured from probe @@ -113,6 +154,8 @@ struct spear_pinctrl_machdata { unsigned nfunctions; struct spear_pingroup **groups; unsigned ngroups; + struct spear_gpio_pingroup *gpio_pingroups; + unsigned ngpio_pingroups; bool modes_supported; u16 mode; @@ -136,6 +179,9 @@ struct spear_pmx { /* exported routines */ void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg); +void __devinit +pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup, + unsigned count, u16 reg); int __devinit spear_pinctrl_probe(struct platform_device *pdev, struct spear_pinctrl_machdata *machdata); int __devexit spear_pinctrl_remove(struct platform_device *pdev); diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c index 0436fc7895d6..30134f727455 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1310.c +++ b/drivers/pinctrl/spear/pinctrl-spear1310.c @@ -2418,6 +2418,268 @@ static struct spear_function *spear1310_functions[] = { &gpt64_function, }; +static const unsigned pin18[] = { 18, }; +static const unsigned pin19[] = { 19, }; +static const unsigned pin20[] = { 20, }; +static const unsigned pin21[] = { 21, }; +static const unsigned pin22[] = { 22, }; +static const unsigned pin23[] = { 23, }; +static const unsigned pin54[] = { 54, }; +static const unsigned pin55[] = { 55, }; +static const unsigned pin56[] = { 56, }; +static const unsigned pin57[] = { 57, }; +static const unsigned pin58[] = { 58, }; +static const unsigned pin59[] = { 59, }; +static const unsigned pin60[] = { 60, }; +static const unsigned pin61[] = { 61, }; +static const unsigned pin62[] = { 62, }; +static const unsigned pin63[] = { 63, }; +static const unsigned pin143[] = { 143, }; +static const unsigned pin144[] = { 144, }; +static const unsigned pin145[] = { 145, }; +static const unsigned pin146[] = { 146, }; +static const unsigned pin147[] = { 147, }; +static const unsigned pin148[] = { 148, }; +static const unsigned pin149[] = { 149, }; +static const unsigned pin150[] = { 150, }; +static const unsigned pin151[] = { 151, }; +static const unsigned pin152[] = { 152, }; +static const unsigned pin205[] = { 205, }; +static const unsigned pin206[] = { 206, }; +static const unsigned pin211[] = { 211, }; +static const unsigned pin212[] = { 212, }; +static const unsigned pin213[] = { 213, }; +static const unsigned pin214[] = { 214, }; +static const unsigned pin215[] = { 215, }; +static const unsigned pin216[] = { 216, }; +static const unsigned pin217[] = { 217, }; +static const unsigned pin218[] = { 218, }; +static const unsigned pin219[] = { 219, }; +static const unsigned pin220[] = { 220, }; +static const unsigned pin221[] = { 221, }; +static const unsigned pin222[] = { 222, }; +static const unsigned pin223[] = { 223, }; +static const unsigned pin224[] = { 224, }; +static const unsigned pin225[] = { 225, }; +static const unsigned pin226[] = { 226, }; +static const unsigned pin227[] = { 227, }; +static const unsigned pin228[] = { 228, }; +static const unsigned pin229[] = { 229, }; +static const unsigned pin230[] = { 230, }; +static const unsigned pin231[] = { 231, }; +static const unsigned pin232[] = { 232, }; +static const unsigned pin233[] = { 233, }; +static const unsigned pin234[] = { 234, }; +static const unsigned pin235[] = { 235, }; +static const unsigned pin236[] = { 236, }; +static const unsigned pin237[] = { 237, }; +static const unsigned pin238[] = { 238, }; +static const unsigned pin239[] = { 239, }; +static const unsigned pin240[] = { 240, }; +static const unsigned pin241[] = { 241, }; +static const unsigned pin242[] = { 242, }; +static const unsigned pin243[] = { 243, }; +static const unsigned pin244[] = { 244, }; +static const unsigned pin245[] = { 245, }; + +static const unsigned pin_grp0[] = { 173, 174, }; +static const unsigned pin_grp1[] = { 175, 185, 188, 197, 198, }; +static const unsigned pin_grp2[] = { 176, 177, 178, 179, 184, 186, 187, 189, + 190, 191, 192, }; +static const unsigned pin_grp3[] = { 180, 181, 182, 183, 193, 194, 195, 196, }; +static const unsigned pin_grp4[] = { 199, 200, }; +static const unsigned pin_grp5[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, }; +static const unsigned pin_grp6[] = { 86, 87, 88, 89, 90, 91, 92, 93, }; +static const unsigned pin_grp7[] = { 98, 99, }; +static const unsigned pin_grp8[] = { 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, }; + +/* Define muxreg arrays */ +DEFINE_2_MUXREG(i2c0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2C0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SSP0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_cs0_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_cs1_2_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS1_2_MASK, 0, 1); +DEFINE_2_MUXREG(i2s0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2S0_MASK, 0, 1); +DEFINE_2_MUXREG(i2s1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_I2S1_MASK, 0, 1); +DEFINE_2_MUXREG(clcd_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_CLCD1_MASK, 0, 1); +DEFINE_2_MUXREG(clcd_high_res_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_CLCD2_MASK, 0, 1); +DEFINE_2_MUXREG(pin18, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO15_MASK, 0, 1); +DEFINE_2_MUXREG(pin19, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO14_MASK, 0, 1); +DEFINE_2_MUXREG(pin20, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO13_MASK, 0, 1); +DEFINE_2_MUXREG(pin21, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO12_MASK, 0, 1); +DEFINE_2_MUXREG(pin22, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO11_MASK, 0, 1); +DEFINE_2_MUXREG(pin23, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO10_MASK, 0, 1); +DEFINE_2_MUXREG(pin143, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO00_MASK, 0, 1); +DEFINE_2_MUXREG(pin144, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO01_MASK, 0, 1); +DEFINE_2_MUXREG(pin145, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO02_MASK, 0, 1); +DEFINE_2_MUXREG(pin146, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO03_MASK, 0, 1); +DEFINE_2_MUXREG(pin147, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO04_MASK, 0, 1); +DEFINE_2_MUXREG(pin148, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO05_MASK, 0, 1); +DEFINE_2_MUXREG(pin149, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO06_MASK, 0, 1); +DEFINE_2_MUXREG(pin150, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO07_MASK, 0, 1); +DEFINE_2_MUXREG(pin151, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO08_MASK, 0, 1); +DEFINE_2_MUXREG(pin152, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO09_MASK, 0, 1); +DEFINE_2_MUXREG(smi_2_chips_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SMI_MASK, 0, 1); +DEFINE_2_MUXREG(pin54, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS3_MASK, 0, 1); +DEFINE_2_MUXREG(pin55, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS2_MASK, 0, 1); +DEFINE_2_MUXREG(pin56, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFRSTPWDWN3_MASK, 0, 1); +DEFINE_2_MUXREG(pin57, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN2_MASK, 0, 1); +DEFINE_2_MUXREG(pin58, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN1_MASK, 0, 1); +DEFINE_2_MUXREG(pin59, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN0_MASK, 0, 1); +DEFINE_2_MUXREG(pin60, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFWPRT3_MASK, 0, 1); +DEFINE_2_MUXREG(pin61, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFCE3_MASK, 0, 1); +DEFINE_2_MUXREG(pin62, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD25_MASK, 0, 1); +DEFINE_2_MUXREG(pin63, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD24_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp0, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp1, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp2, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_RXCLK_RDV_TXEN_D03_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp3, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIID47_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp4, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MDC_MDIO_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp5, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD23_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp6, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MCI_DATA8_15_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp7, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFCE2_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp8, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND8_MASK, 0, 1); +DEFINE_2_MUXREG(nand_16bit_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND16BIT_1_MASK, 0, 1); +DEFINE_2_MUXREG(pin205, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL1_MASK | PMX_NFCE1_MASK, 0, 1); +DEFINE_2_MUXREG(pin206, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL0_MASK | PMX_NFCE2_MASK, 0, 1); +DEFINE_2_MUXREG(pin211, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW1_MASK | PMX_NFWPRT1_MASK, 0, 1); +DEFINE_2_MUXREG(pin212, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW0_MASK | PMX_NFWPRT2_MASK, 0, 1); +DEFINE_2_MUXREG(pin213, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA0_MASK, 0, 1); +DEFINE_2_MUXREG(pin214, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA1_MASK, 0, 1); +DEFINE_2_MUXREG(pin215, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA2_MASK, 0, 1); +DEFINE_2_MUXREG(pin216, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA3_MASK, 0, 1); +DEFINE_2_MUXREG(pin217, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA4_MASK, 0, 1); +DEFINE_2_MUXREG(pin218, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA5_MASK, 0, 1); +DEFINE_2_MUXREG(pin219, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA6_MASK, 0, 1); +DEFINE_2_MUXREG(pin220, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA7_MASK, 0, 1); +DEFINE_2_MUXREG(pin221, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA1SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin222, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA2SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin223, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA3SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin224, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR0ALE_MASK, 0, 1); +DEFINE_2_MUXREG(pin225, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR1CLECLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin226, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR2_MASK, 0, 1); +DEFINE_2_MUXREG(pin227, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICECF_MASK, 0, 1); +DEFINE_2_MUXREG(pin228, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICEXD_MASK, 0, 1); +DEFINE_2_MUXREG(pin229, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICESDMMC_MASK, 0, 1); +DEFINE_2_MUXREG(pin230, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF1_MASK, 0, 1); +DEFINE_2_MUXREG(pin231, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF2_MASK, 0, 1); +DEFINE_2_MUXREG(pin232, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDXD_MASK, 0, 1); +DEFINE_2_MUXREG(pin233, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDSDMMC_MASK, 0, 1); +DEFINE_2_MUXREG(pin234, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATADIR_MASK, 0, 1); +DEFINE_2_MUXREG(pin235, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMARQWP_MASK, 0, 1); +DEFINE_2_MUXREG(pin236, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDRE_MASK, 0, 1); +DEFINE_2_MUXREG(pin237, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIOWRWE_MASK, 0, 1); +DEFINE_2_MUXREG(pin238, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIRESETCF_MASK, 0, 1); +DEFINE_2_MUXREG(pin239, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS0CE_MASK, 0, 1); +DEFINE_2_MUXREG(pin240, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICFINTR_MASK, 0, 1); +DEFINE_2_MUXREG(pin241, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDY_MASK, 0, 1); +DEFINE_2_MUXREG(pin242, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS1_MASK, 0, 1); +DEFINE_2_MUXREG(pin243, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMAACK_MASK, 0, 1); +DEFINE_2_MUXREG(pin244, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCISDCMD_MASK, 0, 1); +DEFINE_2_MUXREG(pin245, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCILEDS_MASK, 0, 1); +DEFINE_2_MUXREG(keyboard_rowcol6_8_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROWCOL68_MASK, 0, 1); +DEFINE_2_MUXREG(uart0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_UART0_MASK, 0, 1); +DEFINE_2_MUXREG(uart0_modem_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_UART0_MODEM_MASK, 0, 1); +DEFINE_2_MUXREG(gpt0_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR0_MASK, 0, 1); +DEFINE_2_MUXREG(gpt0_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR1_MASK, 0, 1); +DEFINE_2_MUXREG(gpt1_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR0_MASK, 0, 1); +DEFINE_2_MUXREG(gpt1_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR1_MASK, 0, 1); +DEFINE_2_MUXREG(touch_xy_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_TOUCH_XY_MASK, 0, 1); + +static struct spear_gpio_pingroup spear1310_gpio_pingroup[] = { + GPIO_PINGROUP(i2c0_pins), + GPIO_PINGROUP(ssp0_pins), + GPIO_PINGROUP(ssp0_cs0_pins), + GPIO_PINGROUP(ssp0_cs1_2_pins), + GPIO_PINGROUP(i2s0_pins), + GPIO_PINGROUP(i2s1_pins), + GPIO_PINGROUP(clcd_pins), + GPIO_PINGROUP(clcd_high_res_pins), + GPIO_PINGROUP(pin18), + GPIO_PINGROUP(pin19), + GPIO_PINGROUP(pin20), + GPIO_PINGROUP(pin21), + GPIO_PINGROUP(pin22), + GPIO_PINGROUP(pin23), + GPIO_PINGROUP(pin143), + GPIO_PINGROUP(pin144), + GPIO_PINGROUP(pin145), + GPIO_PINGROUP(pin146), + GPIO_PINGROUP(pin147), + GPIO_PINGROUP(pin148), + GPIO_PINGROUP(pin149), + GPIO_PINGROUP(pin150), + GPIO_PINGROUP(pin151), + GPIO_PINGROUP(pin152), + GPIO_PINGROUP(smi_2_chips_pins), + GPIO_PINGROUP(pin54), + GPIO_PINGROUP(pin55), + GPIO_PINGROUP(pin56), + GPIO_PINGROUP(pin57), + GPIO_PINGROUP(pin58), + GPIO_PINGROUP(pin59), + GPIO_PINGROUP(pin60), + GPIO_PINGROUP(pin61), + GPIO_PINGROUP(pin62), + GPIO_PINGROUP(pin63), + GPIO_PINGROUP(pin_grp0), + GPIO_PINGROUP(pin_grp1), + GPIO_PINGROUP(pin_grp2), + GPIO_PINGROUP(pin_grp3), + GPIO_PINGROUP(pin_grp4), + GPIO_PINGROUP(pin_grp5), + GPIO_PINGROUP(pin_grp6), + GPIO_PINGROUP(pin_grp7), + GPIO_PINGROUP(pin_grp8), + GPIO_PINGROUP(nand_16bit_pins), + GPIO_PINGROUP(pin205), + GPIO_PINGROUP(pin206), + GPIO_PINGROUP(pin211), + GPIO_PINGROUP(pin212), + GPIO_PINGROUP(pin213), + GPIO_PINGROUP(pin214), + GPIO_PINGROUP(pin215), + GPIO_PINGROUP(pin216), + GPIO_PINGROUP(pin217), + GPIO_PINGROUP(pin218), + GPIO_PINGROUP(pin219), + GPIO_PINGROUP(pin220), + GPIO_PINGROUP(pin221), + GPIO_PINGROUP(pin222), + GPIO_PINGROUP(pin223), + GPIO_PINGROUP(pin224), + GPIO_PINGROUP(pin225), + GPIO_PINGROUP(pin226), + GPIO_PINGROUP(pin227), + GPIO_PINGROUP(pin228), + GPIO_PINGROUP(pin229), + GPIO_PINGROUP(pin230), + GPIO_PINGROUP(pin231), + GPIO_PINGROUP(pin232), + GPIO_PINGROUP(pin233), + GPIO_PINGROUP(pin234), + GPIO_PINGROUP(pin235), + GPIO_PINGROUP(pin236), + GPIO_PINGROUP(pin237), + GPIO_PINGROUP(pin238), + GPIO_PINGROUP(pin239), + GPIO_PINGROUP(pin240), + GPIO_PINGROUP(pin241), + GPIO_PINGROUP(pin242), + GPIO_PINGROUP(pin243), + GPIO_PINGROUP(pin244), + GPIO_PINGROUP(pin245), + GPIO_PINGROUP(keyboard_rowcol6_8_pins), + GPIO_PINGROUP(uart0_pins), + GPIO_PINGROUP(uart0_modem_pins), + GPIO_PINGROUP(gpt0_tmr0_pins), + GPIO_PINGROUP(gpt0_tmr1_pins), + GPIO_PINGROUP(gpt1_tmr0_pins), + GPIO_PINGROUP(gpt1_tmr1_pins), + GPIO_PINGROUP(touch_xy_pins), +}; + static struct spear_pinctrl_machdata spear1310_machdata = { .pins = spear1310_pins, .npins = ARRAY_SIZE(spear1310_pins), @@ -2425,6 +2687,8 @@ static struct spear_pinctrl_machdata spear1310_machdata = { .ngroups = ARRAY_SIZE(spear1310_pingroups), .functions = spear1310_functions, .nfunctions = ARRAY_SIZE(spear1310_functions), + .gpio_pingroups = spear1310_gpio_pingroup, + .ngpio_pingroups = ARRAY_SIZE(spear1310_gpio_pingroup), .modes_supported = false, }; diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c index 4dfc2849b172..9a491007f42d 100644 --- a/drivers/pinctrl/spear/pinctrl-spear300.c +++ b/drivers/pinctrl/spear/pinctrl-spear300.c @@ -661,6 +661,8 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups); spear3xx_machdata.functions = spear300_functions; spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions); + spear3xx_machdata.gpio_pingroups = NULL; + spear3xx_machdata.ngpio_pingroups = 0; spear3xx_machdata.modes_supported = true; spear3xx_machdata.pmx_modes = spear300_pmx_modes; diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c index 96883693fb7e..4d5dfe9c760a 100644 --- a/drivers/pinctrl/spear/pinctrl-spear310.c +++ b/drivers/pinctrl/spear/pinctrl-spear310.c @@ -388,6 +388,8 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions); pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups, + spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG); spear3xx_machdata.modes_supported = false; diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c index ca47b0e50780..c996e26e3b6c 100644 --- a/drivers/pinctrl/spear/pinctrl-spear320.c +++ b/drivers/pinctrl/spear/pinctrl-spear320.c @@ -3431,6 +3431,8 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes); pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups, + spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG); ret = spear_pinctrl_probe(pdev, &spear3xx_machdata); if (ret) diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c index 0242378f7cb8..12ee21af766b 100644 --- a/drivers/pinctrl/spear/pinctrl-spear3xx.c +++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c @@ -481,7 +481,44 @@ struct spear_function spear3xx_timer_2_3_function = { .ngroups = ARRAY_SIZE(timer_2_3_grps), }; +/* Define muxreg arrays */ +DEFINE_MUXREG(firda_pins, 0, PMX_FIRDA_MASK, 0); +DEFINE_MUXREG(i2c_pins, 0, PMX_I2C_MASK, 0); +DEFINE_MUXREG(ssp_cs_pins, 0, PMX_SSP_CS_MASK, 0); +DEFINE_MUXREG(ssp_pins, 0, PMX_SSP_MASK, 0); +DEFINE_MUXREG(mii_pins, 0, PMX_MII_MASK, 0); +DEFINE_MUXREG(gpio0_pin0_pins, 0, PMX_GPIO_PIN0_MASK, 0); +DEFINE_MUXREG(gpio0_pin1_pins, 0, PMX_GPIO_PIN1_MASK, 0); +DEFINE_MUXREG(gpio0_pin2_pins, 0, PMX_GPIO_PIN2_MASK, 0); +DEFINE_MUXREG(gpio0_pin3_pins, 0, PMX_GPIO_PIN3_MASK, 0); +DEFINE_MUXREG(gpio0_pin4_pins, 0, PMX_GPIO_PIN4_MASK, 0); +DEFINE_MUXREG(gpio0_pin5_pins, 0, PMX_GPIO_PIN5_MASK, 0); +DEFINE_MUXREG(uart0_ext_pins, 0, PMX_UART0_MODEM_MASK, 0); +DEFINE_MUXREG(uart0_pins, 0, PMX_UART0_MASK, 0); +DEFINE_MUXREG(timer_0_1_pins, 0, PMX_TIMER_0_1_MASK, 0); +DEFINE_MUXREG(timer_2_3_pins, 0, PMX_TIMER_2_3_MASK, 0); + +static struct spear_gpio_pingroup spear3xx_gpio_pingroup[] = { + GPIO_PINGROUP(firda_pins), + GPIO_PINGROUP(i2c_pins), + GPIO_PINGROUP(ssp_cs_pins), + GPIO_PINGROUP(ssp_pins), + GPIO_PINGROUP(mii_pins), + GPIO_PINGROUP(gpio0_pin0_pins), + GPIO_PINGROUP(gpio0_pin1_pins), + GPIO_PINGROUP(gpio0_pin2_pins), + GPIO_PINGROUP(gpio0_pin3_pins), + GPIO_PINGROUP(gpio0_pin4_pins), + GPIO_PINGROUP(gpio0_pin5_pins), + GPIO_PINGROUP(uart0_ext_pins), + GPIO_PINGROUP(uart0_pins), + GPIO_PINGROUP(timer_0_1_pins), + GPIO_PINGROUP(timer_2_3_pins), +}; + struct spear_pinctrl_machdata spear3xx_machdata = { .pins = spear3xx_pins, .npins = ARRAY_SIZE(spear3xx_pins), + .gpio_pingroups = spear3xx_gpio_pingroup, + .ngpio_pingroups = ARRAY_SIZE(spear3xx_gpio_pingroup), }; From 4ddb1c295752252f61670e35c791bf16e58bbce6 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 27 Oct 2012 15:21:39 +0530 Subject: [PATCH 23/23] ARM: SPEAr: Add plgpio node in device tree dtsi files This patch adds plgpio nodes in SPEAr DT files. Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij --- arch/arm/boot/dts/spear1310-evb.dts | 4 ++++ arch/arm/boot/dts/spear1310.dtsi | 27 +++++++++++++++++++++++++++ arch/arm/boot/dts/spear1340-evb.dts | 4 ++++ arch/arm/boot/dts/spear1340.dtsi | 26 ++++++++++++++++++++++++++ arch/arm/boot/dts/spear310.dtsi | 22 +++++++++++++++++++++- arch/arm/boot/dts/spear320-evb.dts | 4 ++++ arch/arm/boot/dts/spear320.dtsi | 23 ++++++++++++++++++++++- 7 files changed, 108 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts index dd4358bc26e2..2e4c5727468e 100644 --- a/arch/arm/boot/dts/spear1310-evb.dts +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -181,6 +181,10 @@ status = "okay"; }; + gpio@d8400000 { + status = "okay"; + }; + i2c0: i2c@e0280000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi index 419ea7413d23..7cd25eb4f8e0 100644 --- a/arch/arm/boot/dts/spear1310.dtsi +++ b/arch/arm/boot/dts/spear1310.dtsi @@ -70,6 +70,12 @@ status = "disabled"; }; + pinmux: pinmux@e0700000 { + compatible = "st,spear1310-pinmux"; + reg = <0xe0700000 0x1000>; + #gpio-range-cells = <2>; + }; + spi1: spi@5d400000 { compatible = "arm,pl022", "arm,primecell"; reg = <0x5d400000 0x1000>; @@ -179,6 +185,27 @@ thermal@e07008c4 { st,thermal-flags = <0x7000>; }; + + gpiopinctrl: gpio@d8400000 { + compatible = "st,spear-plgpio"; + reg = <0xd8400000 0x1000>; + interrupts = <0 100 0x4>; + #interrupt-cells = <1>; + interrupt-controller; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinmux 0 246>; + status = "disabled"; + + st-plgpio,ngpio = <246>; + st-plgpio,enb-reg = <0xd0>; + st-plgpio,wdata-reg = <0x90>; + st-plgpio,dir-reg = <0xb0>; + st-plgpio,ie-reg = <0x30>; + st-plgpio,rdata-reg = <0x70>; + st-plgpio,mis-reg = <0x10>; + st-plgpio,eit-reg = <0x50>; + }; }; }; }; diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts index c9a54e06fb68..045f7123ffac 100644 --- a/arch/arm/boot/dts/spear1340-evb.dts +++ b/arch/arm/boot/dts/spear1340-evb.dts @@ -193,6 +193,10 @@ status = "okay"; }; + gpio@e2800000 { + status = "okay"; + }; + i2c0: i2c@e0280000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi index d71fe2a68f09..6c09eb0a1b2b 100644 --- a/arch/arm/boot/dts/spear1340.dtsi +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -24,6 +24,12 @@ status = "disabled"; }; + pinmux: pinmux@e0700000 { + compatible = "st,spear1340-pinmux"; + reg = <0xe0700000 0x1000>; + #gpio-range-cells = <2>; + }; + spi1: spi@5d400000 { compatible = "arm,pl022", "arm,primecell"; reg = <0x5d400000 0x1000>; @@ -51,6 +57,26 @@ thermal@e07008c4 { st,thermal-flags = <0x2a00>; }; + + gpiopinctrl: gpio@e2800000 { + compatible = "st,spear-plgpio"; + reg = <0xe2800000 0x1000>; + interrupts = <0 107 0x4>; + #interrupt-cells = <1>; + interrupt-controller; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinmux 0 252>; + status = "disabled"; + + st-plgpio,ngpio = <250>; + st-plgpio,wdata-reg = <0x40>; + st-plgpio,dir-reg = <0x00>; + st-plgpio,ie-reg = <0x80>; + st-plgpio,rdata-reg = <0x20>; + st-plgpio,mis-reg = <0xa0>; + st-plgpio,eit-reg = <0x60>; + }; }; }; }; diff --git a/arch/arm/boot/dts/spear310.dtsi b/arch/arm/boot/dts/spear310.dtsi index 62fc4fb3e5f9..930303e48df9 100644 --- a/arch/arm/boot/dts/spear310.dtsi +++ b/arch/arm/boot/dts/spear310.dtsi @@ -22,9 +22,10 @@ 0xb0000000 0xb0000000 0x10000000 0xd0000000 0xd0000000 0x30000000>; - pinmux@b4000000 { + pinmux: pinmux@b4000000 { compatible = "st,spear310-pinmux"; reg = <0xb4000000 0x1000>; + #gpio-range-cells = <2>; }; fsmc: flash@44000000 { @@ -75,6 +76,25 @@ reg = <0xb2200000 0x1000>; status = "disabled"; }; + + gpiopinctrl: gpio@b4000000 { + compatible = "st,spear-plgpio"; + reg = <0xb4000000 0x1000>; + #interrupt-cells = <1>; + interrupt-controller; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinmux 0 102>; + status = "disabled"; + + st-plgpio,ngpio = <102>; + st-plgpio,enb-reg = <0x10>; + st-plgpio,wdata-reg = <0x20>; + st-plgpio,dir-reg = <0x30>; + st-plgpio,ie-reg = <0x50>; + st-plgpio,rdata-reg = <0x40>; + st-plgpio,mis-reg = <0x60>; + }; }; }; }; diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts index 082328bd64ab..ad4bfc68ee05 100644 --- a/arch/arm/boot/dts/spear320-evb.dts +++ b/arch/arm/boot/dts/spear320-evb.dts @@ -164,6 +164,10 @@ status = "okay"; }; + gpio@b3000000 { + status = "okay"; + }; + i2c0: i2c@d0180000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi index 1f49d69595a0..67d7ada71275 100644 --- a/arch/arm/boot/dts/spear320.dtsi +++ b/arch/arm/boot/dts/spear320.dtsi @@ -21,9 +21,10 @@ ranges = <0x40000000 0x40000000 0x80000000 0xd0000000 0xd0000000 0x30000000>; - pinmux@b3000000 { + pinmux: pinmux@b3000000 { compatible = "st,spear320-pinmux"; reg = <0xb3000000 0x1000>; + #gpio-range-cells = <2>; }; clcd@90000000 { @@ -90,6 +91,26 @@ reg = <0xa4000000 0x1000>; status = "disabled"; }; + + gpiopinctrl: gpio@b3000000 { + compatible = "st,spear-plgpio"; + reg = <0xb3000000 0x1000>; + #interrupt-cells = <1>; + interrupt-controller; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinmux 0 102>; + status = "disabled"; + + st-plgpio,ngpio = <102>; + st-plgpio,enb-reg = <0x24>; + st-plgpio,wdata-reg = <0x34>; + st-plgpio,dir-reg = <0x44>; + st-plgpio,ie-reg = <0x64>; + st-plgpio,rdata-reg = <0x54>; + st-plgpio,mis-reg = <0x84>; + st-plgpio,eit-reg = <0x94>; + }; }; }; };