From 7279d9917560bbd0d82813d6bf00490a82c06783 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Mon, 4 Jun 2018 06:58:14 -0700 Subject: gpio: Fix wrong rounding in gpio-menz127 men_z127_debounce() tries to round up and down, but uses functions which are only suitable when the divider is a power of two, which is not the case. Use the appropriate ones. Found by static check. Compile tested. Fixes: f436bc2726c64 ("gpio: add driver for MEN 16Z127 GPIO controller") Signed-off-by: Nadav Amit Signed-off-by: Linus Walleij --- drivers/gpio/gpio-menz127.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c index e1037582e34d..b2635326546e 100644 --- a/drivers/gpio/gpio-menz127.c +++ b/drivers/gpio/gpio-menz127.c @@ -56,9 +56,9 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio, rnd = fls(debounce) - 1; if (rnd && (debounce & BIT(rnd - 1))) - debounce = round_up(debounce, MEN_Z127_DB_MIN_US); + debounce = roundup(debounce, MEN_Z127_DB_MIN_US); else - debounce = round_down(debounce, MEN_Z127_DB_MIN_US); + debounce = rounddown(debounce, MEN_Z127_DB_MIN_US); if (debounce > MEN_Z127_DB_MAX_US) debounce = MEN_Z127_DB_MAX_US; -- cgit v1.2.3 From 29d43c22e480b150e00f1ac28a6653efca31cce4 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 1 Jun 2018 23:13:47 +0300 Subject: gpio-rcar: document R8A77980 bindings Renesas R-Car V3H (R8A77980) SoC also has the R-Car gen3 compatible GPIO controllers, so document the SoC specific bindings. Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index 378f1322211e..cd5ccdc5e66f 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -17,6 +17,7 @@ Required Properties: - "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller. - "renesas,gpio-r8a77965": for R8A77965 (R-Car M3-N) compatible GPIO controller. - "renesas,gpio-r8a77970": for R8A77970 (R-Car V3M) compatible GPIO controller. + - "renesas,gpio-r8a77980": for R8A77980 (R-Car V3H) compatible GPIO controller. - "renesas,gpio-r8a77990": for R8A77990 (R-Car E3) compatible GPIO controller. - "renesas,gpio-r8a77995": for R8A77995 (R-Car D3) compatible GPIO controller. - "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller. -- cgit v1.2.3 From c1d013a70f557e0d6db29398c955b2ec87db1ff8 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 13 Jun 2018 09:10:36 +0530 Subject: gpio: davinci: Shuffle IRQ resource fetching from DT to beginning of probe This is needed in case of PROBE_DEFER if IRQ resource is not yet ready. Signed-off-by: Keerthy Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 035a454eca43..423d37c95e6b 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -55,7 +55,7 @@ static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) return g; } -static int davinci_gpio_irq_setup(struct platform_device *pdev); +static int davinci_gpio_irq_setup(struct platform_device *pdev, int bank_irq); /*--------------------------------------------------------------------------*/ @@ -167,7 +167,7 @@ of_err: static int davinci_gpio_probe(struct platform_device *pdev) { static int ctrl_num, bank_base; - int gpio, bank, ret = 0; + int gpio, bank, bank_irq, ret = 0; unsigned ngpio, nbank; struct davinci_gpio_controller *chips; struct davinci_gpio_platform_data *pdata; @@ -209,6 +209,12 @@ static int davinci_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpio_base)) return PTR_ERR(gpio_base); + bank_irq = platform_get_irq(pdev, 0); + if (bank_irq < 0) { + dev_dbg(dev, "IRQ not populated\n"); + return bank_irq; + } + snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++); chips->chip.label = devm_kstrdup(dev, label, GFP_KERNEL); if (!chips->chip.label) @@ -243,7 +249,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) goto err; platform_set_drvdata(pdev, chips); - ret = davinci_gpio_irq_setup(pdev); + ret = davinci_gpio_irq_setup(pdev, bank_irq); if (ret) goto err; @@ -452,16 +458,15 @@ static const struct of_device_id davinci_gpio_ids[]; * (dm6446) can be set appropriately for GPIOV33 pins. */ -static int davinci_gpio_irq_setup(struct platform_device *pdev) +static int davinci_gpio_irq_setup(struct platform_device *pdev, int bank_irq) { unsigned gpio, bank; int irq; int ret; struct clk *clk; u32 binten = 0; - unsigned ngpio, bank_irq; + unsigned ngpio; struct device *dev = &pdev->dev; - struct resource *res; struct davinci_gpio_controller *chips = platform_get_drvdata(pdev); struct davinci_gpio_platform_data *pdata = dev->platform_data; struct davinci_gpio_regs __iomem *g; @@ -481,18 +486,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data; ngpio = pdata->ngpio; - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "Invalid IRQ resource\n"); - return -EBUSY; - } - - bank_irq = res->start; - - if (!bank_irq) { - dev_err(dev, "Invalid IRQ resource\n"); - return -ENODEV; - } clk = devm_clk_get(dev, "gpio"); if (IS_ERR(clk)) { -- cgit v1.2.3 From eb3744a2dd01cb07ce9f556d56d6fe451f0c313a Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 13 Jun 2018 09:10:37 +0530 Subject: gpio: davinci: Do not assume continuous IRQ numbering Currently the driver assumes that the interrupts are continuous and does platform_get_irq only once and assumes the rest are continuous, instead call platform_get_irq for all the interrupts and store them in an array for later use. Signed-off-by: Keerthy Reviewed-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 63 ++++++++++++++++++++---------- include/linux/platform_data/gpio-davinci.h | 3 +- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 423d37c95e6b..a5ece8ea79bc 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -55,7 +55,7 @@ static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) return g; } -static int davinci_gpio_irq_setup(struct platform_device *pdev, int bank_irq); +static int davinci_gpio_irq_setup(struct platform_device *pdev); /*--------------------------------------------------------------------------*/ @@ -167,8 +167,8 @@ of_err: static int davinci_gpio_probe(struct platform_device *pdev) { static int ctrl_num, bank_base; - int gpio, bank, bank_irq, ret = 0; - unsigned ngpio, nbank; + int gpio, bank, i, ret = 0; + unsigned int ngpio, nbank, nirq; struct davinci_gpio_controller *chips; struct davinci_gpio_platform_data *pdata; struct device *dev = &pdev->dev; @@ -197,6 +197,16 @@ static int davinci_gpio_probe(struct platform_device *pdev) if (WARN_ON(ARCH_NR_GPIOS < ngpio)) ngpio = ARCH_NR_GPIOS; + /* + * If there are unbanked interrupts then the number of + * interrupts is equal to number of gpios else all are banked so + * number of interrupts is equal to number of banks(each with 16 gpios) + */ + if (pdata->gpio_unbanked) + nirq = pdata->gpio_unbanked; + else + nirq = DIV_ROUND_UP(ngpio, 16); + nbank = DIV_ROUND_UP(ngpio, 32); chips = devm_kcalloc(dev, nbank, sizeof(struct davinci_gpio_controller), @@ -209,10 +219,13 @@ static int davinci_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpio_base)) return PTR_ERR(gpio_base); - bank_irq = platform_get_irq(pdev, 0); - if (bank_irq < 0) { - dev_dbg(dev, "IRQ not populated\n"); - return bank_irq; + for (i = 0; i < nirq; i++) { + chips->irqs[i] = platform_get_irq(pdev, i); + if (chips->irqs[i] < 0) { + dev_info(dev, "IRQ not populated, err = %d\n", + chips->irqs[i]); + return chips->irqs[i]; + } } snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++); @@ -249,7 +262,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) goto err; platform_set_drvdata(pdev, chips); - ret = davinci_gpio_irq_setup(pdev, bank_irq); + ret = davinci_gpio_irq_setup(pdev); if (ret) goto err; @@ -383,7 +396,7 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs). */ if (offset < d->gpio_unbanked) - return d->base_irq + offset; + return d->irqs[offset]; else return -ENODEV; } @@ -392,11 +405,18 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) { struct davinci_gpio_controller *d; struct davinci_gpio_regs __iomem *g; - u32 mask; + u32 mask, i; d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data); g = (struct davinci_gpio_regs __iomem *)d->regs[0]; - mask = __gpio_mask(data->irq - d->base_irq); + for (i = 0; i < MAX_INT_PER_BANK; i++) + if (data->irq == d->irqs[i]) + break; + + if (i == MAX_INT_PER_BANK) + return -EINVAL; + + mask = __gpio_mask(i); if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) return -EINVAL; @@ -458,7 +478,7 @@ static const struct of_device_id davinci_gpio_ids[]; * (dm6446) can be set appropriately for GPIOV33 pins. */ -static int davinci_gpio_irq_setup(struct platform_device *pdev, int bank_irq) +static int davinci_gpio_irq_setup(struct platform_device *pdev) { unsigned gpio, bank; int irq; @@ -492,6 +512,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev, int bank_irq) dev_err(dev, "Error %ld getting gpio clock\n", PTR_ERR(clk)); return PTR_ERR(clk); } + ret = clk_prepare_enable(clk); if (ret) return ret; @@ -531,12 +552,11 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev, int bank_irq) if (pdata->gpio_unbanked) { /* pass "bank 0" GPIO IRQs to AINTC */ chips->chip.to_irq = gpio_to_irq_unbanked; - chips->base_irq = bank_irq; chips->gpio_unbanked = pdata->gpio_unbanked; binten = GENMASK(pdata->gpio_unbanked / 16, 0); /* AINTC handles mask/unmask; GPIO handles triggering */ - irq = bank_irq; + irq = chips->irqs[0]; irq_chip = gpio_get_irq_chip(irq); irq_chip->name = "GPIO-AINTC"; irq_chip->irq_set_type = gpio_irq_type_unbanked; @@ -547,10 +567,11 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev, int bank_irq) writel_relaxed(~0, &g->set_rising); /* set the direct IRQs up to use that irqchip */ - for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) { - irq_set_chip(irq, irq_chip); - irq_set_handler_data(irq, chips); - irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); + for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++) { + irq_set_chip(chips->irqs[gpio], irq_chip); + irq_set_handler_data(chips->irqs[gpio], chips); + irq_set_status_flags(chips->irqs[gpio], + IRQ_TYPE_EDGE_BOTH); } goto done; @@ -560,7 +581,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev, int bank_irq) * Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we * then chain through our own handler. */ - for (gpio = 0, bank = 0; gpio < ngpio; bank++, bank_irq++, gpio += 16) { + for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 16) { /* disabled by default, enabled only as needed * There are register sets for 32 GPIOs. 2 banks of 16 * GPIOs are covered by each set of registers hence divide by 2 @@ -587,8 +608,8 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev, int bank_irq) irqdata->bank_num = bank; irqdata->chip = chips; - irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler, - irqdata); + irq_set_chained_handler_and_data(chips->irqs[bank], + gpio_irq_handler, irqdata); binten |= BIT(bank); } diff --git a/include/linux/platform_data/gpio-davinci.h b/include/linux/platform_data/gpio-davinci.h index 90ae19ca828f..57a5a35e0073 100644 --- a/include/linux/platform_data/gpio-davinci.h +++ b/include/linux/platform_data/gpio-davinci.h @@ -22,6 +22,7 @@ #include #define MAX_REGS_BANKS 5 +#define MAX_INT_PER_BANK 32 struct davinci_gpio_platform_data { u32 ngpio; @@ -41,7 +42,7 @@ struct davinci_gpio_controller { spinlock_t lock; void __iomem *regs[MAX_REGS_BANKS]; int gpio_unbanked; - unsigned int base_irq; + int irqs[MAX_INT_PER_BANK]; unsigned int base; }; -- cgit v1.2.3 From f3a049e784b337e9fa08f2f9046c955cc80af535 Mon Sep 17 00:00:00 2001 From: Zhouyang Jia Date: Tue, 12 Jun 2018 11:28:52 +0800 Subject: gpio: max732x: add error handling for i2c_new_dummy When i2c_new_dummy fails, the lack of error-handling code may cause unexpected results. This patch adds error-handling code after calling i2c_new_dummy. Signed-off-by: Zhouyang Jia Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 9d8bcc69f245..f03cb0ba7726 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -653,6 +653,12 @@ static int max732x_probe(struct i2c_client *client, chip->client_group_a = client; if (nr_port > 8) { c = i2c_new_dummy(client->adapter, addr_b); + if (!c) { + dev_err(&client->dev, + "Failed to allocate I2C device\n"); + ret = -ENODEV; + goto out_failed; + } chip->client_group_b = chip->client_dummy = c; } break; @@ -660,6 +666,12 @@ static int max732x_probe(struct i2c_client *client, chip->client_group_b = client; if (nr_port > 8) { c = i2c_new_dummy(client->adapter, addr_a); + if (!c) { + dev_err(&client->dev, + "Failed to allocate I2C device\n"); + ret = -ENODEV; + goto out_failed; + } chip->client_group_a = chip->client_dummy = c; } break; -- cgit v1.2.3 From 90b39402e9f31c4aab48dc1a43d85a724065793f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 1 Jun 2018 13:21:27 +0200 Subject: gpio: Add API to explicitly name a consumer The GPIO (descriptor) API registers a "label" naming what is currently using the GPIO line. Typically this is taken from things like the device tree node, so "reset-gpios" will result in he line being labeled "reset". The technical effect is pretty much zero: the use is for debug and introspection, such as "lsgpio" and debugfs files. However sometimes the user want this cuddly feeling of listing all GPIO lines and seeing exactly what they are for and it gives a very fulfilling sense of control. Especially in the cases when the device tree node doesn't provide a good name, or anonymous GPIO lines assigned just to "gpios" in the device tree because the usage is implicit. For these cases it may be nice to be able to label the line directly and explicitly. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 13 +++++++++++++ include/linux/gpio/consumer.h | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e11a3bb03820..c6f77e806cb8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3193,6 +3193,19 @@ int gpiod_cansleep(const struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_cansleep); +/** + * gpiod_set_consumer_name() - set the consumer name for the descriptor + * @desc: gpio to set the consumer name on + * @name: the new consumer name + */ +void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name) +{ + VALIDATE_DESC_VOID(desc); + /* Just overwrite whatever the previous name was */ + desc->label = name; +} +EXPORT_SYMBOL_GPL(gpiod_set_consumer_name); + /** * gpiod_to_irq() - return the IRQ corresponding to a GPIO * @desc: gpio whose IRQ will be returned (already requested) diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 243112c7fa7d..e8aaf34dd65d 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -145,6 +145,7 @@ int gpiod_is_active_low(const struct gpio_desc *desc); int gpiod_cansleep(const struct gpio_desc *desc); int gpiod_to_irq(const struct gpio_desc *desc); +void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name); /* Convert between the old gpio_ and new gpiod_ interfaces */ struct gpio_desc *gpio_to_desc(unsigned gpio); @@ -467,6 +468,12 @@ static inline int gpiod_to_irq(const struct gpio_desc *desc) return -EINVAL; } +static inline void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} + static inline struct gpio_desc *gpio_to_desc(unsigned gpio) { return ERR_PTR(-EINVAL); -- cgit v1.2.3 From 3a358e22844d4a88d872891c77d7eee4fbca5f37 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 21 Jun 2018 20:54:42 +0200 Subject: w1: Allow compile test of GPIO consumers if !GPIOLIB The GPIO subsystem provides dummy GPIO consumer functions if GPIOLIB is not enabled. Hence drivers that depend on GPIOLIB, but use GPIO consumer functionality only, can still be compiled if GPIOLIB is not enabled. Relax the dependency on GPIOLIB if COMPILE_TEST is enabled, where appropriate. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Acked-by: Evgeniy Polyakov Signed-off-by: Linus Walleij --- drivers/w1/masters/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 1708b2300c7a..00827d2897b5 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -49,7 +49,7 @@ config W1_MASTER_DS1WM config W1_MASTER_GPIO tristate "GPIO 1-wire busmaster" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here if you want to communicate with your 1-wire devices using GPIO pins. This driver uses the GPIO API to control the wire. -- cgit v1.2.3 From 25b7256500a1738141d74da4afcd3c380141f71c Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 20 Jun 2018 15:54:02 +0300 Subject: dt-bindings: tegra186-gpio: Add information for Tegra194 The Tegra194 GPIO controller is similar to the one in Tegra186. Add relevant information to the device tree binding documentation. Signed-off-by: Mikko Perttunen Reviewed-by: Rob Herring Acked-by: Thierry Reding Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.txt b/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.txt index c82a2e221bc1..adff16c71d21 100644 --- a/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/nvidia,tegra186-gpio.txt @@ -68,6 +68,8 @@ Required properties: One of: - "nvidia,tegra186-gpio". - "nvidia,tegra186-gpio-aon". + - "nvidia,tegra194-gpio". + - "nvidia,tegra194-gpio-aon". - reg-names Array of strings. Contains a list of names for the register spaces described by the reg @@ -91,6 +93,8 @@ Required properties: depending on compatible value: - "nvidia,tegra186-gpio": 6 entries. - "nvidia,tegra186-gpio-aon": 1 entry. + - "nvidia,tegra194-gpio": 6 entries. + - "nvidia,tegra194-gpio-aon": 1 entry. - gpio-controller Boolean. Marks the device node as a GPIO controller/provider. -- cgit v1.2.3 From bac5c3b829c3f2944d258dad1adec444b9deb338 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 20 Jun 2018 15:54:03 +0300 Subject: gpio: tegra186: Add support for Tegra194 Add support for the Tegra194 GPIO bank configuration. Signed-off-by: Mikko Perttunen Acked-by: Thierry Reding Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra186.c | 74 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 7f1aa4c21e0d..9d0292c8a199 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -16,6 +16,7 @@ #include #include +#include #define TEGRA186_GPIO_ENABLE_CONFIG 0x00 #define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0) @@ -593,6 +594,73 @@ static const struct tegra_gpio_soc tegra186_aon_soc = { .name = "tegra186-gpio-aon", }; +#define TEGRA194_MAIN_GPIO_PORT(port, base, count, controller) \ + [TEGRA194_MAIN_GPIO_PORT_##port] = { \ + .name = #port, \ + .offset = base, \ + .pins = count, \ + .irq = controller, \ + } + +static const struct tegra_gpio_port tegra194_main_ports[] = { + TEGRA194_MAIN_GPIO_PORT( A, 0x1400, 8, 1), + TEGRA194_MAIN_GPIO_PORT( B, 0x4e00, 2, 4), + TEGRA194_MAIN_GPIO_PORT( C, 0x4600, 8, 4), + TEGRA194_MAIN_GPIO_PORT( D, 0x4800, 4, 4), + TEGRA194_MAIN_GPIO_PORT( E, 0x4a00, 8, 4), + TEGRA194_MAIN_GPIO_PORT( F, 0x4c00, 6, 4), + TEGRA194_MAIN_GPIO_PORT( G, 0x4000, 8, 4), + TEGRA194_MAIN_GPIO_PORT( H, 0x4200, 8, 4), + TEGRA194_MAIN_GPIO_PORT( I, 0x4400, 5, 4), + TEGRA194_MAIN_GPIO_PORT( J, 0x5200, 6, 5), + TEGRA194_MAIN_GPIO_PORT( K, 0x3000, 8, 3), + TEGRA194_MAIN_GPIO_PORT( L, 0x3200, 4, 3), + TEGRA194_MAIN_GPIO_PORT( M, 0x2600, 8, 2), + TEGRA194_MAIN_GPIO_PORT( N, 0x2800, 3, 2), + TEGRA194_MAIN_GPIO_PORT( O, 0x5000, 6, 5), + TEGRA194_MAIN_GPIO_PORT( P, 0x2a00, 8, 2), + TEGRA194_MAIN_GPIO_PORT( Q, 0x2c00, 8, 2), + TEGRA194_MAIN_GPIO_PORT( R, 0x2e00, 6, 2), + TEGRA194_MAIN_GPIO_PORT( S, 0x3600, 8, 3), + TEGRA194_MAIN_GPIO_PORT( T, 0x3800, 8, 3), + TEGRA194_MAIN_GPIO_PORT( U, 0x3a00, 1, 3), + TEGRA194_MAIN_GPIO_PORT( V, 0x1000, 8, 1), + TEGRA194_MAIN_GPIO_PORT( W, 0x1200, 2, 1), + TEGRA194_MAIN_GPIO_PORT( X, 0x2000, 8, 2), + TEGRA194_MAIN_GPIO_PORT( Y, 0x2200, 8, 2), + TEGRA194_MAIN_GPIO_PORT( Z, 0x2400, 8, 2), + TEGRA194_MAIN_GPIO_PORT(FF, 0x3400, 2, 3), + TEGRA194_MAIN_GPIO_PORT(GG, 0x0000, 2, 0) +}; + +static const struct tegra_gpio_soc tegra194_main_soc = { + .num_ports = ARRAY_SIZE(tegra194_main_ports), + .ports = tegra194_main_ports, + .name = "tegra194-gpio", +}; + +#define TEGRA194_AON_GPIO_PORT(port, base, count, controller) \ + [TEGRA194_AON_GPIO_PORT_##port] = { \ + .name = #port, \ + .offset = base, \ + .pins = count, \ + .irq = controller, \ + } + +static const struct tegra_gpio_port tegra194_aon_ports[] = { + TEGRA194_AON_GPIO_PORT(AA, 0x0600, 8, 0), + TEGRA194_AON_GPIO_PORT(BB, 0x0800, 4, 0), + TEGRA194_AON_GPIO_PORT(CC, 0x0200, 8, 0), + TEGRA194_AON_GPIO_PORT(DD, 0x0400, 3, 0), + TEGRA194_AON_GPIO_PORT(EE, 0x0000, 7, 0) +}; + +static const struct tegra_gpio_soc tegra194_aon_soc = { + .num_ports = ARRAY_SIZE(tegra194_aon_ports), + .ports = tegra194_aon_ports, + .name = "tegra194-gpio-aon", +}; + static const struct of_device_id tegra186_gpio_of_match[] = { { .compatible = "nvidia,tegra186-gpio", @@ -600,6 +668,12 @@ static const struct of_device_id tegra186_gpio_of_match[] = { }, { .compatible = "nvidia,tegra186-gpio-aon", .data = &tegra186_aon_soc + }, { + .compatible = "nvidia,tegra194-gpio", + .data = &tegra194_main_soc + }, { + .compatible = "nvidia,tegra194-gpio-aon", + .data = &tegra194_aon_soc }, { /* sentinel */ } -- cgit v1.2.3 From 5b9b2b5284f81941972105b13337c58489ea8fca Mon Sep 17 00:00:00 2001 From: Mathias Kresin Date: Thu, 28 Jun 2018 21:57:40 +0200 Subject: gpio: stp-xway: Implement get callback Add an implementation to get the current GPIO state. The callback is used by the leds-gpio driver for example, in case the current LED/GPIO state should be kept during driver load. Signed-off-by: Mathias Kresin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-stp-xway.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index c07385b71403..63c708c3f3ae 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -90,6 +90,20 @@ struct xway_stp { u8 reserved; /* mask out the hw driven bits in gpio_request */ }; +/** + * xway_stp_get() - gpio_chip->get - get gpios. + * @gc: Pointer to gpio_chip device structure. + * @gpio: GPIO signal number. + * + * Gets the shadow value. + */ +static int xway_stp_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct xway_stp *chip = gpiochip_get_data(gc); + + return (xway_stp_r32(chip->virt, XWAY_STP_CPU0) & BIT(gpio)); +} + /** * xway_stp_set() - gpio_chip->set - set gpios. * @gc: Pointer to gpio_chip device structure. @@ -215,6 +229,7 @@ static int xway_stp_probe(struct platform_device *pdev) chip->gc.parent = &pdev->dev; chip->gc.label = "stp-xway"; chip->gc.direction_output = xway_stp_dir_out; + chip->gc.get = xway_stp_get; chip->gc.set = xway_stp_set; chip->gc.request = xway_stp_request; chip->gc.base = -1; -- cgit v1.2.3 From 98aef8e777544ccf015fd588ecd69d780d672bc8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 31 May 2018 08:06:23 +0200 Subject: gpio: rc5t583: Include the right header This is a GPIO driver, include only . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rc5t583.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index 3b4dc1a9a68d..a499c633a6c5 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include struct rc5t583_gpio { -- cgit v1.2.3 From 4b1d8007987a85b9f4264905fdd6d76a3cc0b001 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 31 May 2018 08:08:13 +0200 Subject: gpio: rcar: Include the right header This is a GPIO driver, include only . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 350390c0b290..2c9a4fc92dc6 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -15,7 +15,7 @@ */ #include -#include +#include #include #include #include -- cgit v1.2.3 From 05467e54998be15a35c20e0605315fec309b6a5b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 09:46:15 +0200 Subject: gpio: rdc321x: Include the right header This is a GPIO driver, include only . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rdc321x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index cbf0f9e6465b..2938217566d3 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include -- cgit v1.2.3 From 827fb6af6664b614d70330f1ee96d0fb02da3504 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 09:48:03 +0200 Subject: gpio: sa1100: Include the right header This is a GPIO driver, include only . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sa1100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 249f433aa62d..986eb3b231ac 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include +#include #include #include #include -- cgit v1.2.3 From 4c1abc84f482706f033113665faa062852bd97da Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 09:49:25 +0200 Subject: gpio: sch: Include the right header This is a GPIO driver, include only . Cc: Denis Turischev Cc: Daniel Krueger Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 545004445846..26e9b1cd2c78 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -26,8 +26,7 @@ #include #include #include - -#include +#include #define GEN 0x00 #define GIO 0x04 -- cgit v1.2.3 From d8e764c2cc451452f07e4f35a3e83df9decf7f99 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 10:39:31 +0200 Subject: gpio: sch: Implement .get_direction() It's pretty simple to implement the .get_direction() for this chip, so let's just do it. Cc: Denis Turischev Cc: Daniel Krueger Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 26e9b1cd2c78..e9878f6ede67 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -137,6 +137,13 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num, return 0; } +static int sch_gpio_get_direction(struct gpio_chip *gc, unsigned gpio_num) +{ + struct sch_gpio *sch = gpiochip_get_data(gc); + + return sch_gpio_reg_get(sch, gpio_num, GIO); +} + static const struct gpio_chip sch_gpio_chip = { .label = "sch_gpio", .owner = THIS_MODULE, @@ -144,6 +151,7 @@ static const struct gpio_chip sch_gpio_chip = { .get = sch_gpio_get, .direction_output = sch_gpio_direction_out, .set = sch_gpio_set, + .get_direction = sch_gpio_get_direction, }; static int sch_gpio_probe(struct platform_device *pdev) -- cgit v1.2.3 From 30467c19e456ac3503164248131ec0ea57852abf Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 10:42:01 +0200 Subject: gpio: sch311x: Include the right header This is a GPIO driver, include only . Cc: Bruno Randolf Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch311x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index b96990c262a1..8bc2bf45e5da 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include -- cgit v1.2.3 From f9e03b0ef10ce5040714783a09cf12df26bcb3d7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 10:47:28 +0200 Subject: gpio: sch311x: Implement .get_direction() It's pretty simple to implement the .get_direction() for this chip, so let's just do it. Cc: Bruno Randolf Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch311x.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index 8bc2bf45e5da..ed64f7fa23b1 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -221,6 +221,18 @@ static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, return 0; } +static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = gpiochip_get_data(chip); + unsigned char data; + + spin_lock(&block->lock); + data = inb(block->runtime_reg + block->config_regs[offset]); + spin_unlock(&block->lock); + + return !!(data & SCH311X_GPIO_CONF_IN); +} + static int sch311x_gpio_probe(struct platform_device *pdev) { struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev); @@ -253,6 +265,7 @@ static int sch311x_gpio_probe(struct platform_device *pdev) block->chip.free = sch311x_gpio_free; block->chip.direction_input = sch311x_gpio_direction_in; block->chip.direction_output = sch311x_gpio_direction_out; + block->chip.get_direction = sch311x_gpio_get_direction; block->chip.get = sch311x_gpio_get; block->chip.set = sch311x_gpio_set; block->chip.ngpio = 8; -- cgit v1.2.3 From 4a2398d7211f8f750b717ce4a2b0d117385f2a4a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 10:52:07 +0200 Subject: gpio: sch311x: Use RMW to change direction Bit 0 in the config register obviously controls the direction of the GPIO so instead of hammering 0x0/0x1 into that register, use read-modify-write so that we can also alter the other bits in the register. Cc: Bruno Randolf Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch311x.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index ed64f7fa23b1..faf44178f97b 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -23,10 +23,9 @@ #define DRV_NAME "gpio-sch311x" -#define SCH311X_GPIO_CONF_OUT 0x00 -#define SCH311X_GPIO_CONF_IN 0x01 -#define SCH311X_GPIO_CONF_INVERT 0x02 -#define SCH311X_GPIO_CONF_OPEN_DRAIN 0x80 +#define SCH311X_GPIO_CONF_DIR BIT(0) +#define SCH311X_GPIO_CONF_INVERT BIT(1) +#define SCH311X_GPIO_CONF_OPEN_DRAIN BIT(7) #define SIO_CONFIG_KEY_ENTER 0x55 #define SIO_CONFIG_KEY_EXIT 0xaa @@ -196,10 +195,12 @@ static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset, static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct sch311x_gpio_block *block = gpiochip_get_data(chip); + unsigned char data; spin_lock(&block->lock); - outb(SCH311X_GPIO_CONF_IN, block->runtime_reg + - block->config_regs[offset]); + data = inb(block->runtime_reg + block->config_regs[offset]); + data |= SCH311X_GPIO_CONF_DIR; + outb(data, block->runtime_reg + block->config_regs[offset]); spin_unlock(&block->lock); return 0; @@ -209,12 +210,13 @@ static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { struct sch311x_gpio_block *block = gpiochip_get_data(chip); + unsigned char data; spin_lock(&block->lock); - outb(SCH311X_GPIO_CONF_OUT, block->runtime_reg + - block->config_regs[offset]); - + data = inb(block->runtime_reg + block->config_regs[offset]); + data &= ~SCH311X_GPIO_CONF_DIR; + outb(data, block->runtime_reg + block->config_regs[offset]); __sch311x_gpio_set(block, offset, value); spin_unlock(&block->lock); @@ -230,7 +232,7 @@ static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) data = inb(block->runtime_reg + block->config_regs[offset]); spin_unlock(&block->lock); - return !!(data & SCH311X_GPIO_CONF_IN); + return !!(data & SCH311X_GPIO_CONF_DIR); } static int sch311x_gpio_probe(struct platform_device *pdev) -- cgit v1.2.3 From 4455a82a400ba462db8abb642c670555d505bccc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 11:00:44 +0200 Subject: gpio: sch311x: Implement open drain support The chip has a bit for controlling open drain, and it is easy to implement the callback to support open drain when needed, so let's implement it. Cc: Bruno Randolf Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch311x.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index faf44178f97b..1d2af9f97a91 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -235,6 +235,34 @@ static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) return !!(data & SCH311X_GPIO_CONF_DIR); } +static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset, + unsigned long config) +{ + struct sch311x_gpio_block *block = gpiochip_get_data(chip); + enum pin_config_param param = pinconf_to_config_param(config); + unsigned char data; + + switch (param) { + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + spin_lock(&block->lock); + data = inb(block->runtime_reg + block->config_regs[offset]); + data |= SCH311X_GPIO_CONF_OPEN_DRAIN; + outb(data, block->runtime_reg + block->config_regs[offset]); + spin_unlock(&block->lock); + return 0; + case PIN_CONFIG_DRIVE_PUSH_PULL: + spin_lock(&block->lock); + data = inb(block->runtime_reg + block->config_regs[offset]); + data &= ~SCH311X_GPIO_CONF_OPEN_DRAIN; + outb(data, block->runtime_reg + block->config_regs[offset]); + spin_unlock(&block->lock); + return 0; + default: + break; + } + return -ENOTSUPP; +} + static int sch311x_gpio_probe(struct platform_device *pdev) { struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev); @@ -268,6 +296,7 @@ static int sch311x_gpio_probe(struct platform_device *pdev) block->chip.direction_input = sch311x_gpio_direction_in; block->chip.direction_output = sch311x_gpio_direction_out; block->chip.get_direction = sch311x_gpio_get_direction; + block->chip.set_config = sch311x_gpio_set_config; block->chip.get = sch311x_gpio_get; block->chip.set = sch311x_gpio_set; block->chip.ngpio = 8; -- cgit v1.2.3 From eb452a84ece6b84e22c53abdd49ff018d189ae8a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 11:03:22 +0200 Subject: gpio: sch311x: Replace unsigned char with u8 This purely syntactic change switches unsigned char to u8 in the driver. Cc: Bruno Randolf Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sch311x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index 1d2af9f97a91..5497f0a88cf0 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -162,7 +162,7 @@ static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset) static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset) { struct sch311x_gpio_block *block = gpiochip_get_data(chip); - unsigned char data; + u8 data; spin_lock(&block->lock); data = inb(block->runtime_reg + block->data_reg); @@ -174,7 +174,7 @@ static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset) static void __sch311x_gpio_set(struct sch311x_gpio_block *block, unsigned offset, int value) { - unsigned char data = inb(block->runtime_reg + block->data_reg); + u8 data = inb(block->runtime_reg + block->data_reg); if (value) data |= BIT(offset); else @@ -195,7 +195,7 @@ static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset, static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct sch311x_gpio_block *block = gpiochip_get_data(chip); - unsigned char data; + u8 data; spin_lock(&block->lock); data = inb(block->runtime_reg + block->config_regs[offset]); @@ -210,7 +210,7 @@ static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, int value) { struct sch311x_gpio_block *block = gpiochip_get_data(chip); - unsigned char data; + u8 data; spin_lock(&block->lock); @@ -226,7 +226,7 @@ static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { struct sch311x_gpio_block *block = gpiochip_get_data(chip); - unsigned char data; + u8 data; spin_lock(&block->lock); data = inb(block->runtime_reg + block->config_regs[offset]); @@ -240,7 +240,7 @@ static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset, { struct sch311x_gpio_block *block = gpiochip_get_data(chip); enum pin_config_param param = pinconf_to_config_param(config); - unsigned char data; + u8 data; switch (param) { case PIN_CONFIG_DRIVE_OPEN_DRAIN: @@ -353,7 +353,7 @@ static int __init sch311x_detect(int sio_config_port, unsigned short *addr) { int err = 0, reg; unsigned short base_addr; - unsigned char dev_id; + u8 dev_id; err = sch311x_sio_enter(sio_config_port); if (err) -- cgit v1.2.3 From 9fc18cc54add2e535c0e265a967f5e9075e22f73 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 11:07:02 +0200 Subject: gpio: spear-spics: Include the right header This is a GPIO driver, include only . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-spear-spics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c index 22267479ba68..ee3039f091f4 100644 --- a/drivers/gpio/gpio-spear-spics.c +++ b/drivers/gpio/gpio-spear-spics.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include #include -- cgit v1.2.3 From 25fc1778b9ed29e75ef8b30c7827e61b444b8bce Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 11:09:55 +0200 Subject: gpio: sta2x11: Include the right header This is a GPIO driver, include only . Cc: Bartosz Golaszewski Acked-by: Alessandro Rubini Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sta2x11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 407359da08f9..16e7f18f8f42 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From 24dcfd8437b257a187a1295eb62f3f49c72b025f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 11:13:03 +0200 Subject: gpio: sta2x11: Use BIT() macro This removes the custom implementation of the BIT() macro and inlines all calls to the helper. Cc: Bartosz Golaszewski Acked-by: Alessandro Rubini Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sta2x11.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 16e7f18f8f42..4af90968e838 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -63,11 +64,6 @@ static inline struct gsta_regs __iomem *__regs(struct gsta_gpio *chip, int nr) return chip->regs[nr / GSTA_GPIO_PER_BLOCK]; } -static inline u32 __bit(int nr) -{ - return 1U << (nr % GSTA_GPIO_PER_BLOCK); -} - /* * gpio methods */ @@ -76,7 +72,7 @@ static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) { struct gsta_gpio *chip = gpiochip_get_data(gpio); struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); if (val) writel(bit, ®s->dats); @@ -88,7 +84,7 @@ static int gsta_gpio_get(struct gpio_chip *gpio, unsigned nr) { struct gsta_gpio *chip = gpiochip_get_data(gpio); struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); return !!(readl(®s->dat) & bit); } @@ -98,7 +94,7 @@ static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, { struct gsta_gpio *chip = gpiochip_get_data(gpio); struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); writel(bit, ®s->dirs); /* Data register after direction, otherwise pullup/down is selected */ @@ -113,7 +109,7 @@ static int gsta_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { struct gsta_gpio *chip = gpiochip_get_data(gpio); struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); writel(bit, ®s->dirc); return 0; @@ -167,7 +163,7 @@ static void gsta_set_config(struct gsta_gpio *chip, int nr, unsigned cfg) { struct gsta_regs __iomem *regs = __regs(chip, nr); unsigned long flags; - u32 bit = __bit(nr); + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); u32 val; int err = 0; @@ -235,7 +231,7 @@ static void gsta_irq_disable(struct irq_data *data) struct gsta_gpio *chip = gc->private; int nr = data->irq - chip->irq_base; struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); u32 val; unsigned long flags; @@ -258,7 +254,7 @@ static void gsta_irq_enable(struct irq_data *data) struct gsta_gpio *chip = gc->private; int nr = data->irq - chip->irq_base; struct gsta_regs __iomem *regs = __regs(chip, nr); - u32 bit = __bit(nr); + u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); u32 val; int type; unsigned long flags; -- cgit v1.2.3 From aadf77c88d2f8f1ffcf75c1e985da1a5cb66c36a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 11:27:34 +0200 Subject: gpio: sta2x11: Inline regs macro I don't like the __namespace and this is simple enough to just inline at all sites. Cc: Bartosz Golaszewski Acked-by: Alessandro Rubini Signed-off-by: Linus Walleij --- drivers/gpio/gpio-sta2x11.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 4af90968e838..2283c869ad5d 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -59,11 +59,6 @@ struct gsta_gpio { unsigned irq_type[GSTA_NR_GPIO]; }; -static inline struct gsta_regs __iomem *__regs(struct gsta_gpio *chip, int nr) -{ - return chip->regs[nr / GSTA_GPIO_PER_BLOCK]; -} - /* * gpio methods */ @@ -71,7 +66,7 @@ static inline struct gsta_regs __iomem *__regs(struct gsta_gpio *chip, int nr) static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) { struct gsta_gpio *chip = gpiochip_get_data(gpio); - struct gsta_regs __iomem *regs = __regs(chip, nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); if (val) @@ -83,7 +78,7 @@ static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) static int gsta_gpio_get(struct gpio_chip *gpio, unsigned nr) { struct gsta_gpio *chip = gpiochip_get_data(gpio); - struct gsta_regs __iomem *regs = __regs(chip, nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); return !!(readl(®s->dat) & bit); @@ -93,7 +88,7 @@ static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, int val) { struct gsta_gpio *chip = gpiochip_get_data(gpio); - struct gsta_regs __iomem *regs = __regs(chip, nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); writel(bit, ®s->dirs); @@ -108,7 +103,7 @@ static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, static int gsta_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { struct gsta_gpio *chip = gpiochip_get_data(gpio); - struct gsta_regs __iomem *regs = __regs(chip, nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); writel(bit, ®s->dirc); @@ -161,7 +156,7 @@ static void gsta_gpio_setup(struct gsta_gpio *chip) /* called from probe */ */ static void gsta_set_config(struct gsta_gpio *chip, int nr, unsigned cfg) { - struct gsta_regs __iomem *regs = __regs(chip, nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; unsigned long flags; u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); u32 val; @@ -230,7 +225,7 @@ static void gsta_irq_disable(struct irq_data *data) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); struct gsta_gpio *chip = gc->private; int nr = data->irq - chip->irq_base; - struct gsta_regs __iomem *regs = __regs(chip, nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); u32 val; unsigned long flags; @@ -253,7 +248,7 @@ static void gsta_irq_enable(struct irq_data *data) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); struct gsta_gpio *chip = gc->private; int nr = data->irq - chip->irq_base; - struct gsta_regs __iomem *regs = __regs(chip, nr); + struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK]; u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK); u32 val; int type; -- cgit v1.2.3 From ecac6e602ccd8ace3b5ec01ed8f8bf0350e30b92 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 11:30:48 +0200 Subject: gpio: stmpe: Include the right header This is a GPIO driver, include only . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-stmpe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 8d6a5a7e612d..65a2315f1673 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From 97a48fcd628e5bf2a34dd23c08f646253c8767ec Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 27 Jun 2018 11:37:23 +0200 Subject: gpio: stp-xway: Include the right header This is a GPIO driver, include only . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-stp-xway.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index 63c708c3f3ae..19972084c45b 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -13,9 +13,8 @@ #include #include #include -#include +#include #include -#include #include #include -- cgit v1.2.3 From 122d00f778b370124ec38bb59b2ac7622d0c6943 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 28 Jun 2018 08:35:46 +0200 Subject: gpio: syscon: Include the right header This is a GPIO driver, include only . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-syscon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index 8b0a69c5ba88..d40cabd15e9e 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include #include -- cgit v1.2.3 From 72b38caf7b7568ebc167fdd4ec5fa1daa113d08b Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Thu, 21 Jun 2018 16:38:46 +0300 Subject: gpio: pca953x: suppress interrupts warning when not applicable Don't warn about missing interrupts support when the parent interrupt is not defined. Enabling interrupts support would not make it work anyway. Signed-off-by: Baruch Siach Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index c55ad157e820..023a32cfac42 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -708,7 +708,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, { struct i2c_client *client = chip->client; - if (irq_base != -1 && (chip->driver_data & PCA_INT)) + if (client->irq && irq_base != -1 && (chip->driver_data & PCA_INT)) dev_warn(&client->dev, "interrupt support not compiled in\n"); return 0; -- cgit v1.2.3 From 44ddf559d5792b2bffcd44febf9b7b55b03e06b4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 29 Jun 2018 14:11:16 +1000 Subject: gpio: aspeed: Rework register type accessors Use a single accessor function for all register types instead of several spread around. This will make it easier/cleaner to introduce new registers and keep the mechanism in one place. The big switch/case is optimized at compile time since the switch value is a constant. Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Joel Stanley Reviewed-by: Andrew Jeffery Signed-off-by: Linus Walleij --- drivers/gpio/gpio-aspeed.c | 118 ++++++++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 49 deletions(-) diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index b31ae16170e7..c9baeeb7f0cc 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -127,12 +127,21 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, }; -#define GPIO_BANK(x) ((x) >> 5) -#define GPIO_OFFSET(x) ((x) & 0x1f) -#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) +enum aspeed_gpio_reg { + reg_val, + reg_dir, + reg_irq_enable, + reg_irq_type0, + reg_irq_type1, + reg_irq_type2, + reg_irq_status, + reg_debounce_sel1, + reg_debounce_sel2, + reg_tolerance, +}; -#define GPIO_DATA 0x00 -#define GPIO_DIR 0x04 +#define GPIO_VAL_VALUE 0x00 +#define GPIO_VAL_DIR 0x04 #define GPIO_IRQ_ENABLE 0x00 #define GPIO_IRQ_TYPE0 0x04 @@ -143,6 +152,40 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { #define GPIO_DEBOUNCE_SEL1 0x00 #define GPIO_DEBOUNCE_SEL2 0x04 +/* This will be resolved at compile time */ +static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, + const struct aspeed_gpio_bank *bank, + const enum aspeed_gpio_reg reg) +{ + switch (reg) { + case reg_val: + return gpio->base + bank->val_regs + GPIO_VAL_VALUE; + case reg_dir: + return gpio->base + bank->val_regs + GPIO_VAL_DIR; + case reg_irq_enable: + return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE; + case reg_irq_type0: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0; + case reg_irq_type1: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1; + case reg_irq_type2: + return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; + case reg_irq_status: + return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; + case reg_debounce_sel1: + return gpio->base + bank->debounce_regs + GPIO_DEBOUNCE_SEL1; + case reg_debounce_sel2: + return gpio->base + bank->debounce_regs + GPIO_DEBOUNCE_SEL2; + case reg_tolerance: + return gpio->base + bank->tolerance_regs; + } + BUG_ON(1); +} + +#define GPIO_BANK(x) ((x) >> 5) +#define GPIO_OFFSET(x) ((x) & 0x1f) +#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) + #define _GPIO_SET_DEBOUNCE(t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o)) #define GPIO_SET_DEBOUNCE1(t, o) _GPIO_SET_DEBOUNCE(t, o, 1) #define GPIO_SET_DEBOUNCE2(t, o) _GPIO_SET_DEBOUNCE(t, o, 0) @@ -201,27 +244,12 @@ static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset) return !props || (props->output & GPIO_BIT(offset)); } -static void __iomem *bank_val_reg(struct aspeed_gpio *gpio, - const struct aspeed_gpio_bank *bank, - unsigned int reg) -{ - return gpio->base + bank->val_regs + reg; -} - -static void __iomem *bank_irq_reg(struct aspeed_gpio *gpio, - const struct aspeed_gpio_bank *bank, - unsigned int reg) -{ - return gpio->base + bank->irq_regs + reg; -} - static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); const struct aspeed_gpio_bank *bank = to_bank(offset); - return !!(ioread32(bank_val_reg(gpio, bank, GPIO_DATA)) - & GPIO_BIT(offset)); + return !!(ioread32(bank_reg(gpio, bank, reg_val)) & GPIO_BIT(offset)); } static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, @@ -232,7 +260,7 @@ static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, void __iomem *addr; u32 reg; - addr = bank_val_reg(gpio, bank, GPIO_DATA); + addr = bank_reg(gpio, bank, reg_val); reg = gpio->dcache[GPIO_BANK(offset)]; if (val) @@ -269,8 +297,8 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) spin_lock_irqsave(&gpio->lock, flags); - reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)); - iowrite32(reg & ~GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR)); + reg = ioread32(bank_reg(gpio, bank, reg_dir)); + iowrite32(reg & ~GPIO_BIT(offset), bank_reg(gpio, bank, reg_dir)); spin_unlock_irqrestore(&gpio->lock, flags); @@ -291,8 +319,8 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, spin_lock_irqsave(&gpio->lock, flags); __aspeed_gpio_set(gc, offset, val); - reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)); - iowrite32(reg | GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR)); + reg = ioread32(bank_reg(gpio, bank, reg_dir)); + iowrite32(reg | GPIO_BIT(offset), bank_reg(gpio, bank, reg_dir)); spin_unlock_irqrestore(&gpio->lock, flags); @@ -314,7 +342,7 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) spin_lock_irqsave(&gpio->lock, flags); - val = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)) & GPIO_BIT(offset); + val = ioread32(bank_reg(gpio, bank, reg_dir)) & GPIO_BIT(offset); spin_unlock_irqrestore(&gpio->lock, flags); @@ -358,7 +386,7 @@ static void aspeed_gpio_irq_ack(struct irq_data *d) if (rc) return; - status_addr = bank_irq_reg(gpio, bank, GPIO_IRQ_STATUS); + status_addr = bank_reg(gpio, bank, reg_irq_status); spin_lock_irqsave(&gpio->lock, flags); iowrite32(bit, status_addr); @@ -378,7 +406,7 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) if (rc) return; - addr = bank_irq_reg(gpio, bank, GPIO_IRQ_ENABLE); + addr = bank_reg(gpio, bank, reg_irq_enable); spin_lock_irqsave(&gpio->lock, flags); @@ -442,17 +470,17 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) spin_lock_irqsave(&gpio->lock, flags); - addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE0); + addr = bank_reg(gpio, bank, reg_irq_type0); reg = ioread32(addr); reg = (reg & ~bit) | type0; iowrite32(reg, addr); - addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE1); + addr = bank_reg(gpio, bank, reg_irq_type1); reg = ioread32(addr); reg = (reg & ~bit) | type1; iowrite32(reg, addr); - addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE2); + addr = bank_reg(gpio, bank, reg_irq_type2); reg = ioread32(addr); reg = (reg & ~bit) | type2; iowrite32(reg, addr); @@ -477,7 +505,7 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc) for (i = 0; i < ARRAY_SIZE(aspeed_gpio_banks); i++) { const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - reg = ioread32(bank_irq_reg(data, bank, GPIO_IRQ_STATUS)); + reg = ioread32(bank_reg(data, bank, reg_irq_status)); for_each_set_bit(p, ®, 32) { girq = irq_find_mapping(gc->irq.domain, i * 32 + p); @@ -549,21 +577,21 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, unsigned int offset, bool enable) { struct aspeed_gpio *gpio = gpiochip_get_data(chip); - const struct aspeed_gpio_bank *bank; unsigned long flags; + void __iomem *treg; u32 val; - bank = to_bank(offset); + treg = bank_reg(gpio, to_bank(offset), reg_tolerance); spin_lock_irqsave(&gpio->lock, flags); - val = readl(gpio->base + bank->tolerance_regs); + val = readl(treg); if (enable) val |= GPIO_BIT(offset); else val &= ~GPIO_BIT(offset); - writel(val, gpio->base + bank->tolerance_regs); + writel(val, treg); spin_unlock_irqrestore(&gpio->lock, flags); return 0; @@ -582,13 +610,6 @@ static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset) pinctrl_gpio_free(chip->base + offset); } -static inline void __iomem *bank_debounce_reg(struct aspeed_gpio *gpio, - const struct aspeed_gpio_bank *bank, - unsigned int reg) -{ - return gpio->base + bank->debounce_regs + reg; -} - static int usecs_to_cycles(struct aspeed_gpio *gpio, unsigned long usecs, u32 *cycles) { @@ -666,11 +687,11 @@ static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset, void __iomem *addr; u32 val; - addr = bank_debounce_reg(gpio, bank, GPIO_DEBOUNCE_SEL1); + addr = bank_reg(gpio, bank, reg_debounce_sel1); val = ioread32(addr); iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE1(timer, offset), addr); - addr = bank_debounce_reg(gpio, bank, GPIO_DEBOUNCE_SEL2); + addr = bank_reg(gpio, bank, reg_debounce_sel2); val = ioread32(addr); iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE2(timer, offset), addr); } @@ -904,9 +925,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) /* Populate it with initial values read from the HW */ for (i = 0; i < banks; i++) { - const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - gpio->dcache[i] = ioread32(gpio->base + bank->val_regs + - GPIO_DATA); + void __iomem *addr = bank_reg(gpio, &aspeed_gpio_banks[i], reg_val); + gpio->dcache[i] = ioread32(addr); } rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); -- cgit v1.2.3 From c67dda88cc5da58c5a63083e0405fe93e2476bb7 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 29 Jun 2018 14:11:17 +1000 Subject: gpio: aspeed: Add "Read Data" register to read the write latch The Aspeed GPIO hardware has a quirk: the value register, for an output GPIO, doesn't contain the last value written (the write latch content) but the sampled input value. This means that when reading back shortly after writing, you can get an incorrect value as the input value is delayed by a few synchronizers. The HW supports a separate read-only register "Data Read Register" which allows you to read the write latch instead. This adds the definition for it, and uses it for the initial population of the GPIO value cache. It will be used more in subsequent patches. Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Joel Stanley Reviewed-by: Andrew Jeffery Signed-off-by: Linus Walleij --- drivers/gpio/gpio-aspeed.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index c9baeeb7f0cc..a5ded50c6db0 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -59,18 +59,33 @@ struct aspeed_gpio { }; struct aspeed_gpio_bank { - uint16_t val_regs; + uint16_t val_regs; /* +0: Rd: read input value, Wr: set write latch + * +4: Rd/Wr: Direction (0=in, 1=out) + */ + uint16_t rdata_reg; /* Rd: read write latch, Wr: */ uint16_t irq_regs; uint16_t debounce_regs; uint16_t tolerance_regs; const char names[4][3]; }; +/* + * Note: The "value" register returns the input value sampled on the + * line even when the GPIO is configured as an output. Since + * that input goes through synchronizers, writing, then reading + * back may not return the written value right away. + * + * The "rdata" register returns the content of the write latch + * and thus can be used to read back what was last written + * reliably. + */ + static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 }; static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { { .val_regs = 0x0000, + .rdata_reg = 0x00c0, .irq_regs = 0x0008, .debounce_regs = 0x0040, .tolerance_regs = 0x001c, @@ -78,6 +93,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0020, + .rdata_reg = 0x00c4, .irq_regs = 0x0028, .debounce_regs = 0x0048, .tolerance_regs = 0x003c, @@ -85,6 +101,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0070, + .rdata_reg = 0x00c8, .irq_regs = 0x0098, .debounce_regs = 0x00b0, .tolerance_regs = 0x00ac, @@ -92,6 +109,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0078, + .rdata_reg = 0x00cc, .irq_regs = 0x00e8, .debounce_regs = 0x0100, .tolerance_regs = 0x00fc, @@ -99,6 +117,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0080, + .rdata_reg = 0x00d0, .irq_regs = 0x0118, .debounce_regs = 0x0130, .tolerance_regs = 0x012c, @@ -106,6 +125,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x0088, + .rdata_reg = 0x00d4, .irq_regs = 0x0148, .debounce_regs = 0x0160, .tolerance_regs = 0x015c, @@ -113,6 +133,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x01E0, + .rdata_reg = 0x00d8, .irq_regs = 0x0178, .debounce_regs = 0x0190, .tolerance_regs = 0x018c, @@ -120,6 +141,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { }, { .val_regs = 0x01e8, + .rdata_reg = 0x00dc, .irq_regs = 0x01a8, .debounce_regs = 0x01c0, .tolerance_regs = 0x01bc, @@ -129,6 +151,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { enum aspeed_gpio_reg { reg_val, + reg_rdata, reg_dir, reg_irq_enable, reg_irq_type0, @@ -160,6 +183,8 @@ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, switch (reg) { case reg_val: return gpio->base + bank->val_regs + GPIO_VAL_VALUE; + case reg_rdata: + return gpio->base + bank->rdata_reg; case reg_dir: return gpio->base + bank->val_regs + GPIO_VAL_DIR; case reg_irq_enable: @@ -925,7 +950,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) /* Populate it with initial values read from the HW */ for (i = 0; i < banks; i++) { - void __iomem *addr = bank_reg(gpio, &aspeed_gpio_banks[i], reg_val); + void __iomem *addr = bank_reg(gpio, &aspeed_gpio_banks[i], reg_rdata); gpio->dcache[i] = ioread32(addr); } -- cgit v1.2.3 From 0f1e03c2b5a395e3eb38899a41c7e74afbc16ba0 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 29 Jun 2018 14:11:18 +1000 Subject: gpio: aspeed: Add command source registers This adds the definitions for the command source registers and a helper to set them. Those registers allow to control which bus master on the SoC is allowed to modify a given bank of GPIOs and will be used by subsequent patches. Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Joel Stanley Reviewed-by: Andrew Jeffery Signed-off-by: Linus Walleij --- drivers/gpio/gpio-aspeed.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index a5ded50c6db0..b3968f66b1d2 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -66,6 +66,7 @@ struct aspeed_gpio_bank { uint16_t irq_regs; uint16_t debounce_regs; uint16_t tolerance_regs; + uint16_t cmdsrc_regs; const char names[4][3]; }; @@ -89,6 +90,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0008, .debounce_regs = 0x0040, .tolerance_regs = 0x001c, + .cmdsrc_regs = 0x0060, .names = { "A", "B", "C", "D" }, }, { @@ -97,6 +99,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0028, .debounce_regs = 0x0048, .tolerance_regs = 0x003c, + .cmdsrc_regs = 0x0068, .names = { "E", "F", "G", "H" }, }, { @@ -105,6 +108,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0098, .debounce_regs = 0x00b0, .tolerance_regs = 0x00ac, + .cmdsrc_regs = 0x0090, .names = { "I", "J", "K", "L" }, }, { @@ -113,6 +117,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x00e8, .debounce_regs = 0x0100, .tolerance_regs = 0x00fc, + .cmdsrc_regs = 0x00e0, .names = { "M", "N", "O", "P" }, }, { @@ -121,6 +126,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0118, .debounce_regs = 0x0130, .tolerance_regs = 0x012c, + .cmdsrc_regs = 0x0110, .names = { "Q", "R", "S", "T" }, }, { @@ -129,6 +135,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0148, .debounce_regs = 0x0160, .tolerance_regs = 0x015c, + .cmdsrc_regs = 0x0140, .names = { "U", "V", "W", "X" }, }, { @@ -137,6 +144,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x0178, .debounce_regs = 0x0190, .tolerance_regs = 0x018c, + .cmdsrc_regs = 0x0170, .names = { "Y", "Z", "AA", "AB" }, }, { @@ -145,6 +153,7 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .irq_regs = 0x01a8, .debounce_regs = 0x01c0, .tolerance_regs = 0x01bc, + .cmdsrc_regs = 0x01a0, .names = { "AC", "", "", "" }, }, }; @@ -161,6 +170,8 @@ enum aspeed_gpio_reg { reg_debounce_sel1, reg_debounce_sel2, reg_tolerance, + reg_cmdsrc0, + reg_cmdsrc1, }; #define GPIO_VAL_VALUE 0x00 @@ -175,6 +186,13 @@ enum aspeed_gpio_reg { #define GPIO_DEBOUNCE_SEL1 0x00 #define GPIO_DEBOUNCE_SEL2 0x04 +#define GPIO_CMDSRC_0 0x00 +#define GPIO_CMDSRC_1 0x04 +#define GPIO_CMDSRC_ARM 0 +#define GPIO_CMDSRC_LPC 1 +#define GPIO_CMDSRC_COLDFIRE 2 +#define GPIO_CMDSRC_RESERVED 3 + /* This will be resolved at compile time */ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, const struct aspeed_gpio_bank *bank, @@ -203,6 +221,10 @@ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, return gpio->base + bank->debounce_regs + GPIO_DEBOUNCE_SEL2; case reg_tolerance: return gpio->base + bank->tolerance_regs; + case reg_cmdsrc0: + return gpio->base + bank->cmdsrc_regs + GPIO_CMDSRC_0; + case reg_cmdsrc1: + return gpio->base + bank->cmdsrc_regs + GPIO_CMDSRC_1; } BUG_ON(1); } @@ -269,6 +291,38 @@ static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset) return !props || (props->output & GPIO_BIT(offset)); } +static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio, + const struct aspeed_gpio_bank *bank, + int bindex, int cmdsrc) +{ + void __iomem *c0 = bank_reg(gpio, bank, reg_cmdsrc0); + void __iomem *c1 = bank_reg(gpio, bank, reg_cmdsrc1); + u32 bit, reg; + + /* + * Each register controls 4 banks, so take the bottom 2 + * bits of the bank index, and use them to select the + * right control bit (0, 8, 16 or 24). + */ + bit = BIT((bindex & 3) << 3); + + /* Source 1 first to avoid illegal 11 combination */ + reg = ioread32(c1); + if (cmdsrc & 2) + reg |= bit; + else + reg &= ~bit; + iowrite32(reg, c1); + + /* Then Source 0 */ + reg = ioread32(c0); + if (cmdsrc & 1) + reg |= bit; + else + reg &= ~bit; + iowrite32(reg, c0); +} + static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); -- cgit v1.2.3 From a7ca13826e478f9b201eb2f9f20de0b978a82ad9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 29 Jun 2018 14:11:19 +1000 Subject: gpio: aspeed: Add interfaces for co-processor to grab GPIOs On the Aspeed chip, the GPIOs can be under control of the ARM chip or of the ColdFire coprocessor. (There's a third command source, the LPC bus, which we don't use or support yet). The control of which master is allowed to modify a given GPIO is per-bank (8 GPIOs). Unfortunately, systems already exist for which we want to use GPIOs of both sources in the same bank. This provides an API exported by the gpio-aspeed driver that an aspeed coprocessor driver can use to "grab" some GPIOs for use by the coprocessor, and allow the coprocessor driver to provide callbacks for arbitrating access. Once at least one GPIO of a given bank has been "grabbed" by the coprocessor, the entire bank is marked as being under coprocessor control. It's command source is switched to the coprocessor. If the ARM then tries to write to a GPIO in such a marked bank, the provided callbacks are used to request access from the coprocessor driver, which is responsible to doing whatever is necessary to "pause" the coprocessor or prevent it from trying to use the GPIOs while the ARM is doing its accesses. During that time, the command source for the bank is temporarily switched back to the ARM. Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Joel Stanley Reviewed-by: Andrew Jeffery Signed-off-by: Linus Walleij --- drivers/gpio/gpio-aspeed.c | 251 ++++++++++++++++++++++++++++++++++++++++---- include/linux/gpio/aspeed.h | 15 +++ 2 files changed, 246 insertions(+), 20 deletions(-) create mode 100644 include/linux/gpio/aspeed.h diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index b3968f66b1d2..1e00f4045f9d 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,15 @@ #include #include +/* + * These two headers aren't meant to be used by GPIO drivers. We need + * them in order to access gpio_chip_hwgpio() which we need to implement + * the aspeed specific API which allows the coprocessor to request + * access to some GPIOs and to arbitrate between coprocessor and ARM. + */ +#include +#include "gpiolib.h" + struct aspeed_bank_props { unsigned int bank; u32 input; @@ -56,6 +66,7 @@ struct aspeed_gpio { struct clk *clk; u32 *dcache; + u8 *cf_copro_bankmap; }; struct aspeed_gpio_bank { @@ -83,6 +94,9 @@ struct aspeed_gpio_bank { static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 }; +static const struct aspeed_gpio_copro_ops *copro_ops; +static void *copro_data; + static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { { .val_regs = 0x0000, @@ -323,6 +337,50 @@ static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio, iowrite32(reg, c0); } +static bool aspeed_gpio_copro_request(struct aspeed_gpio *gpio, + unsigned int offset) +{ + const struct aspeed_gpio_bank *bank = to_bank(offset); + + if (!copro_ops || !gpio->cf_copro_bankmap) + return false; + if (!gpio->cf_copro_bankmap[offset >> 3]) + return false; + if (!copro_ops->request_access) + return false; + + /* Pause the coprocessor */ + copro_ops->request_access(copro_data); + + /* Change command source back to ARM */ + aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, GPIO_CMDSRC_ARM); + + /* Update cache */ + gpio->dcache[GPIO_BANK(offset)] = ioread32(bank_reg(gpio, bank, reg_rdata)); + + return true; +} + +static void aspeed_gpio_copro_release(struct aspeed_gpio *gpio, + unsigned int offset) +{ + const struct aspeed_gpio_bank *bank = to_bank(offset); + + if (!copro_ops || !gpio->cf_copro_bankmap) + return; + if (!gpio->cf_copro_bankmap[offset >> 3]) + return; + if (!copro_ops->release_access) + return; + + /* Change command source back to ColdFire */ + aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, + GPIO_CMDSRC_COLDFIRE); + + /* Restart the coprocessor */ + copro_ops->release_access(copro_data); +} + static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); @@ -356,11 +414,15 @@ static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, { struct aspeed_gpio *gpio = gpiochip_get_data(gc); unsigned long flags; + bool copro; spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); __aspeed_gpio_set(gc, offset, val); + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); } @@ -368,7 +430,9 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); const struct aspeed_gpio_bank *bank = to_bank(offset); + void __iomem *addr = bank_reg(gpio, bank, reg_dir); unsigned long flags; + bool copro; u32 reg; if (!have_input(gpio, offset)) @@ -376,8 +440,13 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) spin_lock_irqsave(&gpio->lock, flags); - reg = ioread32(bank_reg(gpio, bank, reg_dir)); - iowrite32(reg & ~GPIO_BIT(offset), bank_reg(gpio, bank, reg_dir)); + reg = ioread32(addr); + reg &= ~GPIO_BIT(offset); + + copro = aspeed_gpio_copro_request(gpio, offset); + iowrite32(reg, addr); + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); @@ -389,7 +458,9 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, { struct aspeed_gpio *gpio = gpiochip_get_data(gc); const struct aspeed_gpio_bank *bank = to_bank(offset); + void __iomem *addr = bank_reg(gpio, bank, reg_dir); unsigned long flags; + bool copro; u32 reg; if (!have_output(gpio, offset)) @@ -397,10 +468,15 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, spin_lock_irqsave(&gpio->lock, flags); + reg = ioread32(addr); + reg |= GPIO_BIT(offset); + + copro = aspeed_gpio_copro_request(gpio, offset); __aspeed_gpio_set(gc, offset, val); - reg = ioread32(bank_reg(gpio, bank, reg_dir)); - iowrite32(reg | GPIO_BIT(offset), bank_reg(gpio, bank, reg_dir)); + iowrite32(reg, addr); + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); return 0; @@ -430,24 +506,23 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) } static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, - struct aspeed_gpio **gpio, - const struct aspeed_gpio_bank **bank, - u32 *bit) + struct aspeed_gpio **gpio, + const struct aspeed_gpio_bank **bank, + u32 *bit, int *offset) { - int offset; struct aspeed_gpio *internal; - offset = irqd_to_hwirq(d); + *offset = irqd_to_hwirq(d); internal = irq_data_get_irq_chip_data(d); /* This might be a bit of a questionable place to check */ - if (!have_irq(internal, offset)) + if (!have_irq(internal, *offset)) return -ENOTSUPP; *gpio = internal; - *bank = to_bank(offset); - *bit = GPIO_BIT(offset); + *bank = to_bank(*offset); + *bit = GPIO_BIT(*offset); return 0; } @@ -458,17 +533,23 @@ static void aspeed_gpio_irq_ack(struct irq_data *d) struct aspeed_gpio *gpio; unsigned long flags; void __iomem *status_addr; + int rc, offset; + bool copro; u32 bit; - int rc; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); if (rc) return; status_addr = bank_reg(gpio, bank, reg_irq_status); spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); + iowrite32(bit, status_addr); + + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); } @@ -479,15 +560,17 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) unsigned long flags; u32 reg, bit; void __iomem *addr; - int rc; + int rc, offset; + bool copro; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); if (rc) return; addr = bank_reg(gpio, bank, reg_irq_enable); spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); reg = ioread32(addr); if (set) @@ -496,6 +579,8 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) reg &= ~bit; iowrite32(reg, addr); + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); } @@ -520,9 +605,10 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) struct aspeed_gpio *gpio; unsigned long flags; void __iomem *addr; - int rc; + int rc, offset; + bool copro; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); if (rc) return -EINVAL; @@ -548,6 +634,7 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) } spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); addr = bank_reg(gpio, bank, reg_irq_type0); reg = ioread32(addr); @@ -564,6 +651,8 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) reg = (reg & ~bit) | type2; iowrite32(reg, addr); + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); irq_set_handler_locked(d, handler); @@ -658,11 +747,14 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, struct aspeed_gpio *gpio = gpiochip_get_data(chip); unsigned long flags; void __iomem *treg; + bool copro; u32 val; treg = bank_reg(gpio, to_bank(offset), reg_tolerance); spin_lock_irqsave(&gpio->lock, flags); + copro = aspeed_gpio_copro_request(gpio, offset); + val = readl(treg); if (enable) @@ -671,6 +763,9 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, val &= ~GPIO_BIT(offset); writel(val, treg); + + if (copro) + aspeed_gpio_copro_release(gpio, offset); spin_unlock_irqrestore(&gpio->lock, flags); return 0; @@ -766,6 +861,9 @@ static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset, void __iomem *addr; u32 val; + /* Note: Debounce timer isn't under control of the command + * source registers, so no need to sync with the coprocessor + */ addr = bank_reg(gpio, bank, reg_debounce_sel1); val = ioread32(addr); iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE1(timer, offset), addr); @@ -912,6 +1010,111 @@ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset, return -ENOTSUPP; } +/** + * aspeed_gpio_copro_set_ops - Sets the callbacks used for handhsaking with + * the coprocessor for shared GPIO banks + * @ops: The callbacks + * @data: Pointer passed back to the callbacks + */ +int aspeed_gpio_copro_set_ops(const struct aspeed_gpio_copro_ops *ops, void *data) +{ + copro_data = data; + copro_ops = ops; + + return 0; +} +EXPORT_SYMBOL_GPL(aspeed_gpio_copro_set_ops); + +/** + * aspeed_gpio_copro_grab_gpio - Mark a GPIO used by the coprocessor. The entire + * bank gets marked and any access from the ARM will + * result in handshaking via callbacks. + * @desc: The GPIO to be marked + * @vreg_offset: If non-NULL, returns the value register offset in the GPIO space + * @dreg_offset: If non-NULL, returns the data latch register offset in the GPIO space + * @bit: If non-NULL, returns the bit number of the GPIO in the registers + */ +int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, + u16 *vreg_offset, u16 *dreg_offset, u8 *bit) +{ + struct gpio_chip *chip = gpiod_to_chip(desc); + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); + const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + + if (!gpio->cf_copro_bankmap) + gpio->cf_copro_bankmap = kzalloc(gpio->config->nr_gpios >> 3, GFP_KERNEL); + if (!gpio->cf_copro_bankmap) + return -ENOMEM; + if (offset < 0 || offset > gpio->config->nr_gpios) + return -EINVAL; + bindex = offset >> 3; + + spin_lock_irqsave(&gpio->lock, flags); + + /* Sanity check, this shouldn't happen */ + if (gpio->cf_copro_bankmap[bindex] == 0xff) { + rc = -EIO; + goto bail; + } + gpio->cf_copro_bankmap[bindex]++; + + /* Switch command source */ + if (gpio->cf_copro_bankmap[bindex] == 1) + aspeed_gpio_change_cmd_source(gpio, bank, bindex, + GPIO_CMDSRC_COLDFIRE); + + if (vreg_offset) + *vreg_offset = bank->val_regs; + if (dreg_offset) + *dreg_offset = bank->rdata_reg; + if (bit) + *bit = GPIO_OFFSET(offset); + bail: + spin_unlock_irqrestore(&gpio->lock, flags); + return rc; +} +EXPORT_SYMBOL_GPL(aspeed_gpio_copro_grab_gpio); + +/** + * aspeed_gpio_copro_release_gpio - Unmark a GPIO used by the coprocessor. + * @desc: The GPIO to be marked + */ +int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) +{ + struct gpio_chip *chip = gpiod_to_chip(desc); + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); + const struct aspeed_gpio_bank *bank = to_bank(offset); + unsigned long flags; + + if (!gpio->cf_copro_bankmap) + return -ENXIO; + + if (offset < 0 || offset > gpio->config->nr_gpios) + return -EINVAL; + bindex = offset >> 3; + + spin_lock_irqsave(&gpio->lock, flags); + + /* Sanity check, this shouldn't happen */ + if (gpio->cf_copro_bankmap[bindex] == 0) { + rc = -EIO; + goto bail; + } + gpio->cf_copro_bankmap[bindex]--; + + /* Switch command source */ + if (gpio->cf_copro_bankmap[bindex] == 0) + aspeed_gpio_change_cmd_source(gpio, bank, bindex, + GPIO_CMDSRC_ARM); + bail: + spin_unlock_irqrestore(&gpio->lock, flags); + return rc; +} +EXPORT_SYMBOL_GPL(aspeed_gpio_copro_release_gpio); + /* * Any banks not specified in a struct aspeed_bank_props array are assumed to * have the properties: @@ -1002,10 +1205,18 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) if (!gpio->dcache) return -ENOMEM; - /* Populate it with initial values read from the HW */ + /* + * Populate it with initial values read from the HW and switch + * all command sources to the ARM by default + */ for (i = 0; i < banks; i++) { - void __iomem *addr = bank_reg(gpio, &aspeed_gpio_banks[i], reg_rdata); + const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; + void __iomem *addr = bank_reg(gpio, bank, reg_rdata); gpio->dcache[i] = ioread32(addr); + aspeed_gpio_change_cmd_source(gpio, bank, 0, GPIO_CMDSRC_ARM); + aspeed_gpio_change_cmd_source(gpio, bank, 1, GPIO_CMDSRC_ARM); + aspeed_gpio_change_cmd_source(gpio, bank, 2, GPIO_CMDSRC_ARM); + aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM); } rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); diff --git a/include/linux/gpio/aspeed.h b/include/linux/gpio/aspeed.h new file mode 100644 index 000000000000..1bfb3cdc86d0 --- /dev/null +++ b/include/linux/gpio/aspeed.h @@ -0,0 +1,15 @@ +#ifndef __GPIO_ASPEED_H +#define __GPIO_ASPEED_H + +struct aspeed_gpio_copro_ops { + int (*request_access)(void *data); + int (*release_access)(void *data); +}; + +int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, + u16 *vreg_offset, u16 *dreg_offset, u8 *bit); +int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc); +int aspeed_gpio_copro_set_ops(const struct aspeed_gpio_copro_ops *ops, void *data); + + +#endif /* __GPIO_ASPEED_H */ -- cgit v1.2.3 From b1911710e6e5a9faf91e1925b1e2cdd007920c4c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 3 Jul 2018 03:39:03 +0300 Subject: gpiolib: Join string literals back For easy grepping on debug purposes join string literals back in the messages. While here, fix couple of small indentation issues. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c6f77e806cb8..f15a222205c6 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1664,8 +1664,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, if (parent_handler) { if (gpiochip->can_sleep) { chip_err(gpiochip, - "you cannot have chained interrupts on a " - "chip that may sleep\n"); + "you cannot have chained interrupts on a chip that may sleep\n"); return; } /* @@ -1850,8 +1849,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, return 0; if (gpiochip->irq.parent_handler && gpiochip->can_sleep) { - chip_err(gpiochip, "you cannot have chained interrupts on a " - "chip that may sleep\n"); + chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n"); return -EINVAL; } @@ -3272,8 +3270,8 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) if (test_bit(FLAG_IS_OUT, &desc->flags)) { chip_err(chip, - "%s: tried to flag a GPIO set as output for IRQ\n", - __func__); + "%s: tried to flag a GPIO set as output for IRQ\n", + __func__); return -EIO; } @@ -4228,7 +4226,7 @@ static int __init gpiolib_dev_init(void) int ret; /* Register GPIO sysfs bus */ - ret = bus_register(&gpio_bus_type); + ret = bus_register(&gpio_bus_type); if (ret < 0) { pr_err("gpiolib: could not register GPIO bus type\n"); return ret; -- cgit v1.2.3 From af2b04d19242686a2c30e526c9b7a9e9c57bbce9 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Thu, 5 Jul 2018 15:43:11 +0200 Subject: gpio: mt7621: Add DT bindings Add a devicetree binding documentation for the mt7621 gpio. Signed-off-by: Sergio Paracuellos Reviewed-by: NeilBrown Reviewed-by: Rob Herring Signed-off-by: Linus Walleij --- .../bindings/gpio/mediatek,mt7621-gpio.txt | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.txt diff --git a/Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.txt b/Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.txt new file mode 100644 index 000000000000..ba455589f869 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.txt @@ -0,0 +1,35 @@ +Mediatek MT7621 SoC GPIO controller bindings + +The IP core used inside these SoCs has 3 banks of 32 GPIOs each. +The registers of all the banks are interwoven inside one single IO range. +We load one GPIO controller instance per bank. Also the GPIO controller can receive +interrupts on any of the GPIOs, either edge or level. It then interrupts the CPU +using GIC INT12. + +Required properties for the top level node: +- #gpio-cells : Should be two. The first cell is the GPIO pin number and the + second cell specifies GPIO flags, as defined in . + Only the GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt. Should be 2. The first cell defines the interrupt number, + the second encodes the triger flags encoded as described in + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +- compatible: + - "mediatek,mt7621-gpio" for Mediatek controllers +- reg : Physical base address and length of the controller's registers +- interrupt-parent : phandle of the parent interrupt controller. +- interrupts : Interrupt specifier for the controllers interrupt. +- interrupt-controller : Mark the device node as an interrupt controller. +- gpio-controller : Marks the device node as a GPIO controller. + +Example: + gpio@600 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "mediatek,mt7621-gpio"; + gpio-controller; + interrupt-controller; + reg = <0x600 0x100>; + interrupt-parent = <&gic>; + interrupts = ; + }; -- cgit v1.2.3 From 4ba9c3afda41213ec98c30053e32963892e6dc7c Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Thu, 5 Jul 2018 15:43:10 +0200 Subject: gpio: mt7621: Add a driver for MT7621 Add driver support for gpio of MT7621 SoC. Signed-off-by: Sergio Paracuellos Reviewed-by: NeilBrown [Switched wording WIDTH to STRIDE] Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-mt7621.c | 335 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 344 insertions(+) create mode 100644 drivers/gpio/gpio-mt7621.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 71c0ab46f216..836aa2173e44 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -359,6 +359,14 @@ config GPIO_MPC8XXX Say Y here if you're going to use hardware that connects to the MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs. +config GPIO_MT7621 + bool "Mediatek MT7621 GPIO Support" + depends on SOC_MT7620 || SOC_MT7621 || COMPILE_TEST + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say yes here to support the Mediatek MT7621 SoC GPIO device + config GPIO_MVEBU def_bool y depends on PLAT_ORION || ARCH_MVEBU diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1324c8f966a7..fc77989371be 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o +obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c new file mode 100644 index 000000000000..14660d38dd1a --- /dev/null +++ b/drivers/gpio/gpio-mt7621.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2009-2011 Gabor Juhos + * Copyright (C) 2013 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MTK_BANK_CNT 3 +#define MTK_BANK_WIDTH 32 + +#define GPIO_BANK_STRIDE 0x04 +#define GPIO_REG_CTRL 0x00 +#define GPIO_REG_POL 0x10 +#define GPIO_REG_DATA 0x20 +#define GPIO_REG_DSET 0x30 +#define GPIO_REG_DCLR 0x40 +#define GPIO_REG_REDGE 0x50 +#define GPIO_REG_FEDGE 0x60 +#define GPIO_REG_HLVL 0x70 +#define GPIO_REG_LLVL 0x80 +#define GPIO_REG_STAT 0x90 +#define GPIO_REG_EDGE 0xA0 + +struct mtk_gc { + struct gpio_chip chip; + spinlock_t lock; + int bank; + u32 rising; + u32 falling; + u32 hlevel; + u32 llevel; +}; + +/** + * struct mtk_data - state container for + * data of the platform driver. It is 3 + * separate gpio-chip each one with its + * own irq_chip. + * @dev: device instance + * @gpio_membase: memory base address + * @gpio_irq: irq number from the device tree + * @gc_map: array of the gpio chips + */ +struct mtk_data { + struct device *dev; + void __iomem *gpio_membase; + int gpio_irq; + struct mtk_gc gc_map[MTK_BANK_CNT]; +}; + +static inline struct mtk_gc * +to_mediatek_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct mtk_gc, chip); +} + +static inline void +mtk_gpio_w32(struct mtk_gc *rg, u32 offset, u32 val) +{ + struct gpio_chip *gc = &rg->chip; + struct mtk_data *gpio_data = gpiochip_get_data(gc); + + offset = (rg->bank * GPIO_BANK_STRIDE) + offset; + gc->write_reg(gpio_data->gpio_membase + offset, val); +} + +static inline u32 +mtk_gpio_r32(struct mtk_gc *rg, u32 offset) +{ + struct gpio_chip *gc = &rg->chip; + struct mtk_data *gpio_data = gpiochip_get_data(gc); + + offset = (rg->bank * GPIO_BANK_STRIDE) + offset; + return gc->read_reg(gpio_data->gpio_membase + offset); +} + +static irqreturn_t +mediatek_gpio_irq_handler(int irq, void *data) +{ + struct gpio_chip *gc = data; + struct mtk_gc *rg = to_mediatek_gpio(gc); + irqreturn_t ret = IRQ_NONE; + unsigned long pending; + int bit; + + pending = mtk_gpio_r32(rg, GPIO_REG_STAT); + + for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) { + u32 map = irq_find_mapping(gc->irq.domain, bit); + + generic_handle_irq(map); + mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit)); + ret |= IRQ_HANDLED; + } + + return ret; +} + +static void +mediatek_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mtk_gc *rg = to_mediatek_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 rise, fall, high, low; + + spin_lock_irqsave(&rg->lock, flags); + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); + high = mtk_gpio_r32(rg, GPIO_REG_HLVL); + low = mtk_gpio_r32(rg, GPIO_REG_LLVL); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(pin) & rg->rising)); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(pin) & rg->falling)); + mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(pin) & rg->hlevel)); + mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(pin) & rg->llevel)); + spin_unlock_irqrestore(&rg->lock, flags); +} + +static void +mediatek_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mtk_gc *rg = to_mediatek_gpio(gc); + int pin = d->hwirq; + unsigned long flags; + u32 rise, fall, high, low; + + spin_lock_irqsave(&rg->lock, flags); + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); + high = mtk_gpio_r32(rg, GPIO_REG_HLVL); + low = mtk_gpio_r32(rg, GPIO_REG_LLVL); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin)); + mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin)); + spin_unlock_irqrestore(&rg->lock, flags); +} + +static int +mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct mtk_gc *rg = to_mediatek_gpio(gc); + int pin = d->hwirq; + u32 mask = BIT(pin); + + if (type == IRQ_TYPE_PROBE) { + if ((rg->rising | rg->falling | + rg->hlevel | rg->llevel) & mask) + return 0; + + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + + rg->rising &= ~mask; + rg->falling &= ~mask; + rg->hlevel &= ~mask; + rg->llevel &= ~mask; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: + rg->rising |= mask; + rg->falling |= mask; + break; + case IRQ_TYPE_EDGE_RISING: + rg->rising |= mask; + break; + case IRQ_TYPE_EDGE_FALLING: + rg->falling |= mask; + break; + case IRQ_TYPE_LEVEL_HIGH: + rg->hlevel |= mask; + break; + case IRQ_TYPE_LEVEL_LOW: + rg->llevel |= mask; + break; + } + + return 0; +} + +static struct irq_chip mediatek_gpio_irq_chip = { + .irq_unmask = mediatek_gpio_irq_unmask, + .irq_mask = mediatek_gpio_irq_mask, + .irq_mask_ack = mediatek_gpio_irq_mask, + .irq_set_type = mediatek_gpio_irq_type, +}; + +static int +mediatek_gpio_xlate(struct gpio_chip *chip, + const struct of_phandle_args *spec, u32 *flags) +{ + int gpio = spec->args[0]; + struct mtk_gc *rg = to_mediatek_gpio(chip); + + if (rg->bank != gpio / MTK_BANK_WIDTH) + return -EINVAL; + + if (flags) + *flags = spec->args[1]; + + return gpio % MTK_BANK_WIDTH; +} + +static int +mediatek_gpio_bank_probe(struct platform_device *pdev, + struct device_node *node, int bank) +{ + struct mtk_data *gpio = dev_get_drvdata(&pdev->dev); + struct mtk_gc *rg; + void __iomem *dat, *set, *ctrl, *diro; + int ret; + + rg = &gpio->gc_map[bank]; + memset(rg, 0, sizeof(*rg)); + + spin_lock_init(&rg->lock); + rg->chip.of_node = node; + rg->bank = bank; + + dat = gpio->gpio_membase + GPIO_REG_DATA + + (rg->bank * GPIO_BANK_STRIDE); + set = gpio->gpio_membase + GPIO_REG_DSET + + (rg->bank * GPIO_BANK_STRIDE); + ctrl = gpio->gpio_membase + GPIO_REG_DCLR + + (rg->bank * GPIO_BANK_STRIDE); + diro = gpio->gpio_membase + GPIO_REG_CTRL + + (rg->bank * GPIO_BANK_STRIDE); + + ret = bgpio_init(&rg->chip, &pdev->dev, 4, + dat, set, ctrl, diro, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "bgpio_init() failed\n"); + return ret; + } + + rg->chip.of_gpio_n_cells = 2; + rg->chip.of_xlate = mediatek_gpio_xlate; + rg->chip.label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-bank%d", + dev_name(&pdev->dev), bank); + + ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n", + rg->chip.ngpio, ret); + return ret; + } + + if (gpio->gpio_irq) { + /* + * Manually request the irq here instead of passing + * a flow-handler to gpiochip_set_chained_irqchip, + * because the irq is shared. + */ + ret = devm_request_irq(&pdev->dev, gpio->gpio_irq, + mediatek_gpio_irq_handler, IRQF_SHARED, + rg->chip.label, &rg->chip); + + if (ret) { + dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n", + gpio->gpio_irq, ret); + return ret; + } + + ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip, + 0, handle_simple_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n"); + return ret; + } + + gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip, + gpio->gpio_irq, NULL); + } + + /* set polarity to low for all gpios */ + mtk_gpio_w32(rg, GPIO_REG_POL, 0); + + dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); + + return 0; +} + +static int +mediatek_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct mtk_data *gpio_data; + int i; + + gpio_data = devm_kzalloc(&pdev->dev, sizeof(*gpio_data), GFP_KERNEL); + if (!gpio_data) + return -ENOMEM; + + gpio_data->gpio_membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio_data->gpio_membase)) + return PTR_ERR(gpio_data->gpio_membase); + + gpio_data->gpio_irq = irq_of_parse_and_map(np, 0); + gpio_data->dev = &pdev->dev; + platform_set_drvdata(pdev, gpio_data); + mediatek_gpio_irq_chip.name = dev_name(&pdev->dev); + + for (i = 0; i < MTK_BANK_CNT; i++) + mediatek_gpio_bank_probe(pdev, np, i); + + return 0; +} + +static const struct of_device_id mediatek_gpio_match[] = { + { .compatible = "mediatek,mt7621-gpio" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mediatek_gpio_match); + +static struct platform_driver mediatek_gpio_driver = { + .probe = mediatek_gpio_probe, + .driver = { + .name = "mt7621_gpio", + .of_match_table = mediatek_gpio_match, + }, +}; + +builtin_platform_driver(mediatek_gpio_driver); -- cgit v1.2.3 From 8512486ba2d441187d6d619006f034704a3e5a31 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 9 Jul 2018 13:51:57 +0200 Subject: gpio: mt7621: Edit to preferred syntax This fixes some syntactic nits that makes the GPIO maintainer happier. It is way easier to show by example and do it myself than to try to explain it with comments. It's just my personal taste of minimalism. Cc: Sergio Paracuellos Cc: NeilBrown Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mt7621.c | 85 ++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c index 14660d38dd1a..d72af6f6cdbd 100644 --- a/drivers/gpio/gpio-mt7621.c +++ b/drivers/gpio/gpio-mt7621.c @@ -40,18 +40,18 @@ struct mtk_gc { }; /** - * struct mtk_data - state container for + * struct mtk - state container for * data of the platform driver. It is 3 * separate gpio-chip each one with its * own irq_chip. * @dev: device instance - * @gpio_membase: memory base address + * @base: memory base address * @gpio_irq: irq number from the device tree * @gc_map: array of the gpio chips */ -struct mtk_data { +struct mtk { struct device *dev; - void __iomem *gpio_membase; + void __iomem *base; int gpio_irq; struct mtk_gc gc_map[MTK_BANK_CNT]; }; @@ -66,20 +66,20 @@ static inline void mtk_gpio_w32(struct mtk_gc *rg, u32 offset, u32 val) { struct gpio_chip *gc = &rg->chip; - struct mtk_data *gpio_data = gpiochip_get_data(gc); + struct mtk *mtk = gpiochip_get_data(gc); offset = (rg->bank * GPIO_BANK_STRIDE) + offset; - gc->write_reg(gpio_data->gpio_membase + offset, val); + gc->write_reg(mtk->base + offset, val); } static inline u32 mtk_gpio_r32(struct mtk_gc *rg, u32 offset) { struct gpio_chip *gc = &rg->chip; - struct mtk_data *gpio_data = gpiochip_get_data(gc); + struct mtk *mtk = gpiochip_get_data(gc); offset = (rg->bank * GPIO_BANK_STRIDE) + offset; - return gc->read_reg(gpio_data->gpio_membase + offset); + return gc->read_reg(mtk->base + offset); } static irqreturn_t @@ -213,80 +213,76 @@ mediatek_gpio_xlate(struct gpio_chip *chip, } static int -mediatek_gpio_bank_probe(struct platform_device *pdev, +mediatek_gpio_bank_probe(struct device *dev, struct device_node *node, int bank) { - struct mtk_data *gpio = dev_get_drvdata(&pdev->dev); + struct mtk *mtk = dev_get_drvdata(dev); struct mtk_gc *rg; void __iomem *dat, *set, *ctrl, *diro; int ret; - rg = &gpio->gc_map[bank]; + rg = &mtk->gc_map[bank]; memset(rg, 0, sizeof(*rg)); spin_lock_init(&rg->lock); rg->chip.of_node = node; rg->bank = bank; - dat = gpio->gpio_membase + GPIO_REG_DATA + - (rg->bank * GPIO_BANK_STRIDE); - set = gpio->gpio_membase + GPIO_REG_DSET + - (rg->bank * GPIO_BANK_STRIDE); - ctrl = gpio->gpio_membase + GPIO_REG_DCLR + - (rg->bank * GPIO_BANK_STRIDE); - diro = gpio->gpio_membase + GPIO_REG_CTRL + - (rg->bank * GPIO_BANK_STRIDE); + dat = mtk->base + GPIO_REG_DATA + (rg->bank * GPIO_BANK_STRIDE); + set = mtk->base + GPIO_REG_DSET + (rg->bank * GPIO_BANK_STRIDE); + ctrl = mtk->base + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_STRIDE); + diro = mtk->base + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_STRIDE); - ret = bgpio_init(&rg->chip, &pdev->dev, 4, + ret = bgpio_init(&rg->chip, dev, 4, dat, set, ctrl, diro, NULL, 0); if (ret) { - dev_err(&pdev->dev, "bgpio_init() failed\n"); + dev_err(dev, "bgpio_init() failed\n"); return ret; } rg->chip.of_gpio_n_cells = 2; rg->chip.of_xlate = mediatek_gpio_xlate; - rg->chip.label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-bank%d", - dev_name(&pdev->dev), bank); + rg->chip.label = devm_kasprintf(dev, GFP_KERNEL, "%s-bank%d", + dev_name(dev), bank); - ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio); + ret = devm_gpiochip_add_data(dev, &rg->chip, mtk); if (ret < 0) { - dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n", + dev_err(dev, "Could not register gpio %d, ret=%d\n", rg->chip.ngpio, ret); return ret; } - if (gpio->gpio_irq) { + if (mtk->gpio_irq) { /* * Manually request the irq here instead of passing * a flow-handler to gpiochip_set_chained_irqchip, * because the irq is shared. */ - ret = devm_request_irq(&pdev->dev, gpio->gpio_irq, + ret = devm_request_irq(dev, mtk->gpio_irq, mediatek_gpio_irq_handler, IRQF_SHARED, rg->chip.label, &rg->chip); if (ret) { - dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n", - gpio->gpio_irq, ret); + dev_err(dev, "Error requesting IRQ %d: %d\n", + mtk->gpio_irq, ret); return ret; } ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip, 0, handle_simple_irq, IRQ_TYPE_NONE); if (ret) { - dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n"); + dev_err(dev, "failed to add gpiochip_irqchip\n"); return ret; } gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip, - gpio->gpio_irq, NULL); + mtk->gpio_irq, NULL); } /* set polarity to low for all gpios */ mtk_gpio_w32(rg, GPIO_REG_POL, 0); - dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); + dev_info(dev, "registering %d gpios\n", rg->chip.ngpio); return 0; } @@ -294,26 +290,27 @@ mediatek_gpio_bank_probe(struct platform_device *pdev, static int mediatek_gpio_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct mtk_data *gpio_data; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct mtk *mtk; int i; - gpio_data = devm_kzalloc(&pdev->dev, sizeof(*gpio_data), GFP_KERNEL); - if (!gpio_data) + mtk = devm_kzalloc(dev, sizeof(*mtk), GFP_KERNEL); + if (!mtk) return -ENOMEM; - gpio_data->gpio_membase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(gpio_data->gpio_membase)) - return PTR_ERR(gpio_data->gpio_membase); + mtk->base = devm_ioremap_resource(dev, res); + if (IS_ERR(mtk->base)) + return PTR_ERR(mtk->base); - gpio_data->gpio_irq = irq_of_parse_and_map(np, 0); - gpio_data->dev = &pdev->dev; - platform_set_drvdata(pdev, gpio_data); - mediatek_gpio_irq_chip.name = dev_name(&pdev->dev); + mtk->gpio_irq = irq_of_parse_and_map(np, 0); + mtk->dev = dev; + platform_set_drvdata(pdev, mtk); + mediatek_gpio_irq_chip.name = dev_name(dev); for (i = 0; i < MTK_BANK_CNT; i++) - mediatek_gpio_bank_probe(pdev, np, i); + mediatek_gpio_bank_probe(dev, np, i); return 0; } -- cgit v1.2.3 From f8b52dd50ccdae7efc42ef54278f29d2f9d6cb36 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 3 Jul 2018 09:18:14 +0800 Subject: gpio: mxc: Add clocks optional binding for imx gpio Some i.MX SoCs have GPIO clock gate in CCM, accessing GPIO registers needs to enable GPIO clock gate first, i.MX GPIO driver will enable clock gate if there is clock property in GPIO node of dtb, add optional property to i.MX GPIO binding doc. Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt b/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt index dbd22e0df21e..b4cd9f906c24 100644 --- a/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt @@ -19,6 +19,9 @@ Required properties: 4 = active high level-sensitive. 8 = active low level-sensitive. +Optional properties: +- clocks: the clock for clocking the GPIO silicon + Example: gpio0: gpio@73f84000 { -- cgit v1.2.3 From 36b312792b97933dc07abe074f50941199bd357c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 3 Jul 2018 03:38:31 +0300 Subject: gpiolib: Respect error code of ->get_direction() In case we try to lock GPIO pin as IRQ when something going wrong we print a misleading message. Correct this by checking an error code from ->get_direction() in gpiochip_lock_as_irq() and printing a corresponding message. Signed-off-by: Andy Shevchenko Cc: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f15a222205c6..8ec51b7777c6 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3262,6 +3262,12 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) if (!chip->can_sleep && chip->get_direction) { int dir = chip->get_direction(chip, offset); + if (dir < 0) { + chip_err(chip, "%s: cannot get GPIO direction\n", + __func__); + return dir; + } + if (dir) clear_bit(FLAG_IS_OUT, &desc->flags); else -- cgit v1.2.3 From 8853daf3b4acb3bf8c0244a12b4f58ed5123f449 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 4 Jul 2018 00:18:19 +0200 Subject: gpiolib: Defer on non-DT find_chip_by_name() failure Avoid replication of error code conversion in non-DT GPIO consumers' code by returning -EPROBE_DEFER from gpiod_find() in case a chip identified by its label in a registered lookup table is not ready. See https://lkml.org/lkml/2018/5/30/176 for example case. Suggested-by: Boris Brezillon Signed-off-by: Janusz Krzysztofik Reviewed-by: Boris Brezillon Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 8ec51b7777c6..a9a290999990 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3656,9 +3656,16 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, chip = find_chip_by_name(p->chip_label); if (!chip) { - dev_err(dev, "cannot find GPIO chip %s\n", - p->chip_label); - return ERR_PTR(-ENODEV); + /* + * As the lookup table indicates a chip with + * p->chip_label should exist, assume it may + * still appear later and let the interested + * consumer be probed again or let the Deferred + * Probe infrastructure handle the error. + */ + dev_warn(dev, "cannot find GPIO chip %s, deferring\n", + p->chip_label); + return ERR_PTR(-EPROBE_DEFER); } if (chip->ngpio <= p->chip_hwnum) { -- cgit v1.2.3 From 76411a0d97c3b216ce1c987aa4afa7f3789c89d9 Mon Sep 17 00:00:00 2001 From: Rafael David Tinoco Date: Wed, 6 Jun 2018 14:44:24 -0300 Subject: gpio: selftests: gpio-mockup-chardev GPIOHANDLE_REQUEST_OUTPUT fix Following logic from commit: 22f6592b23, GPIOHANDLE_REQUEST_OUTPUT should handle errors same way as GPIOHANDLE_REQUEST_INPUT does, or else the following error occurs: gpio-mockup-chardev: gpio line<0> test flag<0x2> value<0>: No such file or directory despite the real result of gpio_pin_test(), gpio_debugfs_get() and gpiotools_request_linehandle() functions. Signed-off-by: Rafael David Tinoco Signed-off-by: Linus Walleij --- tools/testing/selftests/gpio/gpio-mockup-chardev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/gpio/gpio-mockup-chardev.c b/tools/testing/selftests/gpio/gpio-mockup-chardev.c index 667e916fa7cc..f8d468f54e98 100644 --- a/tools/testing/selftests/gpio/gpio-mockup-chardev.c +++ b/tools/testing/selftests/gpio/gpio-mockup-chardev.c @@ -225,10 +225,10 @@ int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value) if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW) debugfs_value = !debugfs_value; - if (!(debugfs_dir == OUT && value == debugfs_value)) + if (!(debugfs_dir == OUT && value == debugfs_value)) { errno = -EINVAL; - ret = -errno; - + ret = -errno; + } } gpiotools_release_linehandle(fd); -- cgit v1.2.3 From b23ec59926faf05b0c43680d05671c484e810ac4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 9 Jul 2018 21:47:27 +0300 Subject: gpiolib: Mark gpio_suffixes array with __maybe_unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we put static variable to a header file it's copied to each module that includes the header. But not all of them are actually used it. Mark gpio_suffixes array with __maybe_unused to hide a compiler warning: In file included from drivers/gpio/gpiolib-legacy.c:6:0: drivers/gpio/gpiolib.h:95:27: warning: ‘gpio_suffixes’ defined but not used [-Wunused-const-variable=] static const char * const gpio_suffixes[] = { "gpios", "gpio" }; ^~~~~~~~~~~~~ In file included from drivers/gpio/gpiolib-devprop.c:17:0: drivers/gpio/gpiolib.h:95:27: warning: ‘gpio_suffixes’ defined but not used [-Wunused-const-variable=] static const char * const gpio_suffixes[] = { "gpios", "gpio" }; ^~~~~~~~~~~~~ Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 1a8e20363861..a7e49fef73d4 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -92,7 +92,7 @@ struct acpi_gpio_info { }; /* gpio suffixes used for ACPI and device tree lookup */ -static const char * const gpio_suffixes[] = { "gpios", "gpio" }; +static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" }; #ifdef CONFIG_OF_GPIO struct gpio_desc *of_find_gpio(struct device *dev, -- cgit v1.2.3 From 809567905b5f10f73828b3fab3024bfaaf967f32 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 9 Jul 2018 21:47:21 +0300 Subject: gpiolib: Consistent use of ->get_direction() inside gpiolib Two out of three calls to ->get_direction (excluding, of course, gpiod_get_direction() itself) are using gpiod_get_direction() and one is still open coded. Replace the latter one to use same API for sake of consistency. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a9a290999990..cbc071423f30 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3260,18 +3260,13 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) * behind our back */ if (!chip->can_sleep && chip->get_direction) { - int dir = chip->get_direction(chip, offset); + int dir = gpiod_get_direction(desc); if (dir < 0) { chip_err(chip, "%s: cannot get GPIO direction\n", __func__); return dir; } - - if (dir) - clear_bit(FLAG_IS_OUT, &desc->flags); - else - set_bit(FLAG_IS_OUT, &desc->flags); } if (test_bit(FLAG_IS_OUT, &desc->flags)) { -- cgit v1.2.3 From c29677312d2532f7a7d49623539e435df6d64d22 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 9 Jul 2018 16:56:03 +0200 Subject: gpio: aspeed: fix compile testing warning Gcc cannot always see that BUG_ON(1) is guaranteed to not return, so we get a warning message in some configurations: drivers/gpio/gpio-aspeed.c: In function 'bank_reg': drivers/gpio/gpio-aspeed.c:244:1: error: control reaches end of non-void function [-Werror=return-type] Using a plain BUG() is easier here and avoids the problem. Fixes: 44ddf559d579 ("gpio: aspeed: Rework register type accessors") Signed-off-by: Arnd Bergmann Acked-by: Benjamin Herrenschmidt Signed-off-by: Linus Walleij --- drivers/gpio/gpio-aspeed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 1e00f4045f9d..2342e154029b 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -240,7 +240,7 @@ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, case reg_cmdsrc1: return gpio->base + bank->cmdsrc_regs + GPIO_CMDSRC_1; } - BUG_ON(1); + BUG(); } #define GPIO_BANK(x) ((x) >> 5) -- cgit v1.2.3 From 7a9a5df0a54e4b2a36a7984800d0a064b39fb3f8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 10 Jul 2018 17:18:47 +0200 Subject: gpio: mt7621: add OF_GPIO dependency Compile-testing the driver fails unless OF_GPIO is enabled: drivers/gpio/gpio-mt7621.c: In function 'mediatek_gpio_bank_probe': drivers/gpio/gpio-mt7621.c:228:10: error: 'struct gpio_chip' has no member named 'of_node' Fixes: 4ba9c3afda41 ("gpio: mt7621: Add a driver for MT7621") Signed-off-by: Arnd Bergmann Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 836aa2173e44..7429b30e61b0 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -362,6 +362,7 @@ config GPIO_MPC8XXX config GPIO_MT7621 bool "Mediatek MT7621 GPIO Support" depends on SOC_MT7620 || SOC_MT7621 || COMPILE_TEST + depends on OF_GPIO select GPIO_GENERIC select GPIOLIB_IRQCHIP help -- cgit v1.2.3 From 9506755633d0b32ef76f67c345000178e9b0dfc4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 11 Jul 2018 13:19:38 +0000 Subject: gpio: pxa: Fix potential NULL dereference platform_get_resource() may fail and return NULL, so we should better check it's return value to avoid a NULL pointer dereference a bit later in the code. This is detected by Coccinelle semantic patch. @@ expression pdev, res, n, t, e, e1, e2; @@ res = platform_get_resource(pdev, t, n); + if (!res) + return -EINVAL; ... when != res == NULL e = devm_ioremap(e1, res->start, e2); Signed-off-by: Wei Yongjun Acked-by: Robert Jarzmik Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pxa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 1e66f808051c..0d09a4fcef49 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -646,6 +646,8 @@ static int pxa_gpio_probe(struct platform_device *pdev) pchip->irq0 = irq0; pchip->irq1 = irq1; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; gpio_reg_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!gpio_reg_base) -- cgit v1.2.3 From 1c22a252b3ded10d06acecdf8fb71f9dd8005c4f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 12 Jul 2018 20:36:42 +0300 Subject: gpiolib: Join one line back for better readability One line in gpiolib_dbg_show() still fits 80 characters, so, join it to be like that in order to increase readability. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index cbc071423f30..2e2a6f8db405 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4278,9 +4278,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s", gpio, gdesc->name ? gdesc->name : "", gdesc->label, is_out ? "out" : "in ", - chip->get - ? (chip->get(chip, i) ? "hi" : "lo") - : "? ", + chip->get ? (chip->get(chip, i) ? "hi" : "lo") : "? ", is_irq ? "IRQ" : " "); seq_printf(s, "\n"); } -- cgit v1.2.3 From ad817297418539b8895bbbf1d05ee3e5a211a117 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 12 Jul 2018 11:15:01 +0200 Subject: gpio: rcar: Implement .get_direction() callback Allow gpiolib to read back the current I/O direction configuration by implementing the .get_direction() callback. Signed-off-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 2c9a4fc92dc6..55cc61086d99 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -278,6 +278,13 @@ static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset) pm_runtime_put(&p->pdev->dev); } +static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct gpio_rcar_priv *p = gpiochip_get_data(chip); + + return !(gpio_rcar_read(p, INOUTSEL) & BIT(offset)); +} + static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) { gpio_rcar_config_general_input_output_mode(chip, offset, false); @@ -461,6 +468,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip = &p->gpio_chip; gpio_chip->request = gpio_rcar_request; gpio_chip->free = gpio_rcar_free; + gpio_chip->get_direction = gpio_rcar_get_direction; gpio_chip->direction_input = gpio_rcar_direction_input; gpio_chip->get = gpio_rcar_get; gpio_chip->direction_output = gpio_rcar_direction_output; -- cgit v1.2.3 From e5332d5437764f775cf4e3b8ca3bf592af063a02 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 16 Jul 2018 10:34:23 +0200 Subject: gpiolib: don't allow userspace to set values of input lines User space can currently both read and set values of input lines using the character device. This was not allowed by the old sysfs interface nor is it a correct behavior. Check the first descriptor in the set for the OUT flag when asked to set values and return -EPERM if the line is input. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2e2a6f8db405..c507cd3d01c0 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -449,7 +449,13 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, return 0; } else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) { - /* TODO: check if descriptors are really output */ + /* + * All line descriptors were created at once with the same + * flags so just check if the first one is really output. + */ + if (!test_bit(FLAG_IS_OUT, &lh->descs[0]->flags)) + return -EPERM; + if (copy_from_user(&ghd, ip, sizeof(ghd))) return -EFAULT; -- cgit v1.2.3 From 2b955b34c268af57e3002ece9fd2da70d19b1d5b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 16 Jul 2018 10:34:24 +0200 Subject: gpiolib: remove an unnecessary TODO It's actually fine to read values of output lines. This was also allowed by the legacy sysfs interface. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c507cd3d01c0..464d5ba79f96 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -431,7 +431,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, int i; if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { - /* TODO: check if descriptors are really input */ + /* NOTE: It's ok to read values of output lines. */ int ret = gpiod_get_array_value_complex(false, true, lh->numdescs, -- cgit v1.2.3 From 40bb5d725e797ea140e5f83822bf2b5328a2d47f Mon Sep 17 00:00:00 2001 From: Morten Hein Tiljeset Date: Mon, 16 Jul 2018 14:43:39 +0200 Subject: gpio-pisosr: add support for get_multiple Signed-off-by: Morten Hein Tiljeset Reviewed-by: Sean Nyekjaer Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pisosr.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c index f5545049c187..f809a5a8e9eb 100644 --- a/drivers/gpio/gpio-pisosr.c +++ b/drivers/gpio/gpio-pisosr.c @@ -12,6 +12,8 @@ * GNU General Public License version 2 for more details. */ +#include +#include #include #include #include @@ -90,6 +92,25 @@ static int pisosr_gpio_get(struct gpio_chip *chip, unsigned offset) return (gpio->buffer[offset / 8] >> (offset % 8)) & 0x1; } +static int pisosr_gpio_get_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct pisosr_gpio *gpio = gpiochip_get_data(chip); + unsigned int nbytes = DIV_ROUND_UP(chip->ngpio, 8); + unsigned int i, j; + + pisosr_gpio_refresh(gpio); + + bitmap_zero(bits, chip->ngpio); + for (i = 0; i < nbytes; i++) { + j = i / sizeof(unsigned long); + bits[j] |= ((unsigned long) gpio->buffer[i]) + << (8 * (i % sizeof(unsigned long))); + } + + return 0; +} + static const struct gpio_chip template_chip = { .label = "pisosr-gpio", .owner = THIS_MODULE, @@ -97,6 +118,7 @@ static const struct gpio_chip template_chip = { .direction_input = pisosr_gpio_direction_input, .direction_output = pisosr_gpio_direction_output, .get = pisosr_gpio_get, + .get_multiple = pisosr_gpio_get_multiple, .base = -1, .ngpio = DEFAULT_NGPIO, .can_sleep = true, -- cgit v1.2.3 From c19fdaeea0aa1938cf6a35aa97f9ea6fd8b22476 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Wed, 18 Jul 2018 09:25:32 +0800 Subject: gpio: mxc: add power management support GPIO registers could lose context on i.MX7D, when enter LPSR mode, the whole SoC will be powered off except LPSR domain, GPIO banks will lose context in this case, need to restore the context after resume from LPSR mode. This patch adds new compatible string for i.MX7D which supports GPIO power off feature in suspend, and adds the GPIO save/restore operations in noirq suspend/resume phase, since GPIO is fundamental module which could be used by other peripherals' resume phase. Signed-off-by: Anson Huang Reviewed-by: Fabio Estevam Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxc.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 2f2829966d4c..995cf0b9e0b1 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -45,6 +45,15 @@ struct mxc_gpio_hwdata { unsigned fall_edge; }; +struct mxc_gpio_reg_saved { + u32 icr1; + u32 icr2; + u32 imr; + u32 gdir; + u32 edge_sel; + u32 dr; +}; + struct mxc_gpio_port { struct list_head node; void __iomem *base; @@ -55,6 +64,8 @@ struct mxc_gpio_port { struct gpio_chip gc; struct device *dev; u32 both_edges; + struct mxc_gpio_reg_saved gpio_saved_reg; + bool power_off; }; static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = { @@ -143,6 +154,7 @@ static const struct of_device_id mxc_gpio_dt_ids[] = { { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], }, { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], }, { .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], }, + { .compatible = "fsl,imx7d-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], }, { /* sentinel */ } }; @@ -434,6 +446,9 @@ static int mxc_gpio_probe(struct platform_device *pdev) return err; } + if (of_device_is_compatible(np, "fsl,imx7d-gpio")) + port->power_off = true; + /* disable the interrupt and clear the status */ writel(0, port->base + GPIO_IMR); writel(~0, port->base + GPIO_ISR); @@ -497,6 +512,8 @@ static int mxc_gpio_probe(struct platform_device *pdev) list_add_tail(&port->node, &mxc_gpio_ports); + platform_set_drvdata(pdev, port); + return 0; out_irqdomain_remove: @@ -507,11 +524,67 @@ out_bgio: return err; } +static void mxc_gpio_save_regs(struct mxc_gpio_port *port) +{ + if (!port->power_off) + return; + + port->gpio_saved_reg.icr1 = readl(port->base + GPIO_ICR1); + port->gpio_saved_reg.icr2 = readl(port->base + GPIO_ICR2); + port->gpio_saved_reg.imr = readl(port->base + GPIO_IMR); + port->gpio_saved_reg.gdir = readl(port->base + GPIO_GDIR); + port->gpio_saved_reg.edge_sel = readl(port->base + GPIO_EDGE_SEL); + port->gpio_saved_reg.dr = readl(port->base + GPIO_DR); +} + +static void mxc_gpio_restore_regs(struct mxc_gpio_port *port) +{ + if (!port->power_off) + return; + + writel(port->gpio_saved_reg.icr1, port->base + GPIO_ICR1); + writel(port->gpio_saved_reg.icr2, port->base + GPIO_ICR2); + writel(port->gpio_saved_reg.imr, port->base + GPIO_IMR); + writel(port->gpio_saved_reg.gdir, port->base + GPIO_GDIR); + writel(port->gpio_saved_reg.edge_sel, port->base + GPIO_EDGE_SEL); + writel(port->gpio_saved_reg.dr, port->base + GPIO_DR); +} + +static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + + mxc_gpio_save_regs(port); + clk_disable_unprepare(port->clk); + + return 0; +} + +static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + int ret; + + ret = clk_prepare_enable(port->clk); + if (ret) + return ret; + mxc_gpio_restore_regs(port); + + return 0; +} + +static const struct dev_pm_ops mxc_gpio_dev_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume) +}; + static struct platform_driver mxc_gpio_driver = { .driver = { .name = "gpio-mxc", .of_match_table = mxc_gpio_dt_ids, .suppress_bind_attrs = true, + .pm = &mxc_gpio_dev_pm_ops, }, .probe = mxc_gpio_probe, .id_table = mxc_gpio_devtype, -- cgit v1.2.3 From f78709a5d4114edc21a5d86586ed5e56e284f2bd Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Tue, 17 Jul 2018 19:10:38 +0300 Subject: gpio: tegra: Fix tegra_gpio_irq_set_type() Commit 36b312792b97 ("gpiolib: Respect error code of ->get_direction()") broke tegra_gpio_irq_set_type() because requesting of GPIO direction must be done after enabling GPIO function for a pin. This patch fixes drivers probe failure like this: gpio gpiochip0: (tegra-gpio): gpiochip_lock_as_irq: cannot get GPIO direction tegra-gpio 6000d000.gpio: unable to lock Tegra GPIO 144 as IRQ Fixes: 36b312792b97 ("gpiolib: Respect error code of ->get_direction()") Signed-off-by: Dmitry Osipenko Acked-by: Jon Hunter Tested-by: Jon Hunter Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 94396caaca75..22e7c99ed69e 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -323,13 +323,6 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - ret = gpiochip_lock_as_irq(&tgi->gc, gpio); - if (ret) { - dev_err(tgi->dev, - "unable to lock Tegra GPIO %u as IRQ\n", gpio); - return ret; - } - spin_lock_irqsave(&bank->lvl_lock[port], flags); val = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio)); @@ -342,6 +335,14 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, gpio), gpio, 0); tegra_gpio_enable(tgi, gpio); + ret = gpiochip_lock_as_irq(&tgi->gc, gpio); + if (ret) { + dev_err(tgi->dev, + "unable to lock Tegra GPIO %u as IRQ\n", gpio); + tegra_gpio_disable(tgi, gpio); + return ret; + } + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) -- cgit v1.2.3 From 1777fc97302997f016b720fea9c4d0e1ad858f56 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Fri, 20 Jul 2018 09:54:49 +0200 Subject: gpiolib: probe deferral error reporting Actually report the error code from devm_regulator_get() which may as well just be a probe deferral. This is e.g. what one gets upon booting a Colibri T20: gpiochip_add_data_with_key: GPIOs 0..223 (tegra-gpio) failed to register Signed-off-by: Marcel Ziswiler Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 464d5ba79f96..bdbfc95793e7 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1414,9 +1414,9 @@ err_free_descs: err_free_gdev: ida_simple_remove(&gpio_ida, gdev->id); /* failures here can mean systems won't boot... */ - pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, + pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__, gdev->base, gdev->base + gdev->ngpio - 1, - chip->label ? : "generic"); + chip->label ? : "generic", status); kfree(gdev); return status; } -- cgit v1.2.3 From 4bf4eed44bfe288f459496eaf38089502ef91a79 Mon Sep 17 00:00:00 2001 From: Anton Vasilyev Date: Mon, 23 Jul 2018 19:53:30 +0300 Subject: gpio: ml-ioh: Fix buffer underwrite on probe error path If ioh_gpio_probe() fails on devm_irq_alloc_descs() then chip may point to any element of chip_save array, so reverse iteration from pointer chip may become chip_save[-1] and gpiochip_remove() will operate with wrong memory. The patch fix the error path of ioh_gpio_probe() to correctly bypass chip_save array. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Anton Vasilyev Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ml-ioh.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index b23d9a36be1f..51c7d1b84c2e 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -496,9 +496,10 @@ static int ioh_gpio_probe(struct pci_dev *pdev, return 0; err_gpiochip_add: + chip = chip_save; while (--i >= 0) { - chip--; gpiochip_remove(&chip->gpio); + chip++; } kfree(chip_save); -- cgit v1.2.3 From 9dabfdd84bdfa25f0df486dd3de43e53e79a1892 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 13 Jul 2018 18:15:38 +0200 Subject: gpio: pxa: disable pinctrl calls for PXA3xx The pxa3xx driver uses the pinctrl-single driver since a while which does not implement a .gpio_set_direction() callback. The pinmux core will simply return 0 in this case, and the pxa3xx gpio driver hence believes the pinctrl driver did its job and returns as well. This effectively makes pxa_gpio_direction_{input,output} no-ops. To fix this, do not call into the pinctrl subsystem for the PXA3xx platform for now. We can revert this once the pinctrl-single driver learned to support setting pin directions. Signed-off-by: Daniel Mack Acked-by: Robert Jarzmik Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pxa.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 0d09a4fcef49..99070e2ac3cd 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -241,6 +241,17 @@ int pxa_irq_to_gpio(int irq) return irq_gpio0; } +static bool pxa_gpio_has_pinctrl(void) +{ + switch (gpio_type) { + case PXA3XX_GPIO: + return false; + + default: + return true; + } +} + static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct pxa_gpio_chip *pchip = chip_to_pxachip(chip); @@ -255,9 +266,11 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) unsigned long flags; int ret; - ret = pinctrl_gpio_direction_input(chip->base + offset); - if (!ret) - return 0; + if (pxa_gpio_has_pinctrl()) { + ret = pinctrl_gpio_direction_input(chip->base + offset); + if (!ret) + return 0; + } spin_lock_irqsave(&gpio_lock, flags); @@ -282,9 +295,11 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip, writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); - ret = pinctrl_gpio_direction_output(chip->base + offset); - if (ret) - return ret; + if (pxa_gpio_has_pinctrl()) { + ret = pinctrl_gpio_direction_output(chip->base + offset); + if (ret) + return ret; + } spin_lock_irqsave(&gpio_lock, flags); @@ -348,8 +363,12 @@ static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, pchip->chip.set = pxa_gpio_set; pchip->chip.to_irq = pxa_gpio_to_irq; pchip->chip.ngpio = ngpio; - pchip->chip.request = gpiochip_generic_request; - pchip->chip.free = gpiochip_generic_free; + + if (pxa_gpio_has_pinctrl()) { + pchip->chip.request = gpiochip_generic_request; + pchip->chip.free = gpiochip_generic_free; + } + #ifdef CONFIG_OF_GPIO pchip->chip.of_node = np; pchip->chip.of_xlate = pxa_gpio_of_xlate; -- cgit v1.2.3 From 2bee9e067cad4446928cbdcdaf788be463e74240 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 24 Jul 2018 13:29:28 -0300 Subject: gpio: mxs: Fit writel() into a single line There is no need for splitting the writel() call in two lines. Make it fit into a single line instead. Signed-off-by: Fabio Estevam Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index e2831ee70cdc..df30490da820 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -126,8 +126,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type) else writel(pin_mask, pin_addr + MXS_CLR); - writel(pin_mask, - port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); + writel(pin_mask, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); return 0; } -- cgit v1.2.3 From 23211b08c367bc9b22469c1460f5dbb67142e06d Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Tue, 24 Jul 2018 19:57:43 +0800 Subject: gpio: fix meaningless return expression Fix the following sparse error: drivers/gpio/gpio-ath79.c:54:16: error: return expression in void function Signed-off-by: zhong jiang Acked-by: Alban Bedel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ath79.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index 684e9d6d6623..0a553d676042 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -51,7 +51,7 @@ static u32 ath79_gpio_read(struct ath79_gpio_ctrl *ctrl, unsigned reg) static void ath79_gpio_write(struct ath79_gpio_ctrl *ctrl, unsigned reg, u32 val) { - return writel(val, ctrl->base + reg); + writel(val, ctrl->base + reg); } static bool ath79_gpio_update_bits( -- cgit v1.2.3 From 0b07609ccd48a23103881a161e49eb7a282170e7 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 26 Jul 2018 17:42:52 +0200 Subject: gpio: tegra: drop tegra specific GPIO lockdep classes Since commit e45d1c80c0ee ("gpio: put GPIO IRQs into their own lock class") and commit a0a8bcf4670c ("gpiolib: irqchip: use different lockdep class for each gpio irqchip") GPIO lib takes care of lockdep classes. In fact, gpiochip_irq_map() overwrites the class anyway, so the lockdep class set by the driver is useless. Remove it. Signed-off-by: Stefan Agner Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 22e7c99ed69e..2d940785bad0 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -551,13 +551,6 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) }; -/* - * This lock class tells lockdep that GPIO irqs are in a different category - * than their parents, so it won't report false recursion. - */ -static struct lock_class_key gpio_lock_class; -static struct lock_class_key gpio_request_class; - static int tegra_gpio_probe(struct platform_device *pdev) { struct tegra_gpio_info *tgi; @@ -662,8 +655,6 @@ static int tegra_gpio_probe(struct platform_device *pdev) bank = &tgi->bank_info[GPIO_BANK(gpio)]; - irq_set_lockdep_class(irq, &gpio_lock_class, - &gpio_request_class); irq_set_chip_data(irq, bank); irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq); } -- cgit v1.2.3 From 0969a204bfdaf7470d2666736b90a8595ae671e9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 27 Jul 2018 17:47:01 +0300 Subject: gpiolib: Use GPIOD_OUT_{LOW,HIGH} macros in open drain ones There should not be anything more than stated by the name of newly introduced constants, i.e. GPIOD_OUT_LOW_OPEN_DRAIN == GPIOD_OUT_LOW + open drain and nothing more. Make it better to read and slightly more robust by using GPIOD_OUT_LOW and GPIOD_OUT_HIGH constants with open drain flag. No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- include/linux/gpio/consumer.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index e8aaf34dd65d..21ddbe440030 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -41,11 +41,8 @@ enum gpiod_flags { GPIOD_OUT_LOW = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT, GPIOD_OUT_HIGH = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT | GPIOD_FLAGS_BIT_DIR_VAL, - GPIOD_OUT_LOW_OPEN_DRAIN = GPIOD_FLAGS_BIT_DIR_SET | - GPIOD_FLAGS_BIT_DIR_OUT | GPIOD_FLAGS_BIT_OPEN_DRAIN, - GPIOD_OUT_HIGH_OPEN_DRAIN = GPIOD_FLAGS_BIT_DIR_SET | - GPIOD_FLAGS_BIT_DIR_OUT | GPIOD_FLAGS_BIT_DIR_VAL | - GPIOD_FLAGS_BIT_OPEN_DRAIN, + GPIOD_OUT_LOW_OPEN_DRAIN = GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_OPEN_DRAIN, + GPIOD_OUT_HIGH_OPEN_DRAIN = GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_OPEN_DRAIN, }; #ifdef CONFIG_GPIOLIB -- cgit v1.2.3 From 4e133828e2ca6de5b7563842817a65836a45f63f Mon Sep 17 00:00:00 2001 From: Vincent Prince Date: Mon, 30 Jul 2018 11:30:25 +0200 Subject: gpio-it87: add support for IT8786E Super I/O From the datasheet, the GPIO interface is identical to IT8728 (same description), so just add it to the same case as the other chip. Signed-off-by: Vincent Prince Signed-off-by: Linus Walleij --- drivers/gpio/gpio-it87.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index 7cad14d3f127..7b017f43dc6b 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -41,6 +41,7 @@ #define IT8732_ID 0x8732 #define IT8761_ID 0x8761 #define IT8772_ID 0x8772 +#define IT8786_ID 0x8786 /* IO Ports */ #define REG 0x2e @@ -317,6 +318,7 @@ static int __init it87_gpio_init(void) case IT8728_ID: case IT8732_ID: case IT8772_ID: + case IT8786_ID: gpio_ba_reg = 0x62; it87_gpio->io_size = 8; it87_gpio->output_base = 0xc8; -- cgit v1.2.3 From ae61bac9c470cf546558ea525e7cf6b636f04046 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 1 Aug 2018 01:40:31 +0000 Subject: gpio: pxa: remove set but not used variable 'gpio_offset' Fixes gcc '-Wunused-but-set-variable' warning: drivers/gpio/gpio-pxa.c: In function "pxa_gpio_probe": drivers/gpio/gpio-pxa.c:629:35: warning: variable "gpio_offset" set but not used [-Wunused-but-set-variable] int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0; ^ Signed-off-by: Wei Yongjun Acked-by: Robert Jarzmik Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pxa.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 99070e2ac3cd..c18712dabf93 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -626,7 +626,7 @@ static int pxa_gpio_probe(struct platform_device *pdev) struct pxa_gpio_platform_data *info; void __iomem *gpio_reg_base; int gpio, ret; - int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0; + int irq0 = 0, irq1 = 0, irq_mux; pchip = devm_kzalloc(&pdev->dev, sizeof(*pchip), GFP_KERNEL); if (!pchip) @@ -672,9 +672,6 @@ static int pxa_gpio_probe(struct platform_device *pdev) if (!gpio_reg_base) return -EINVAL; - if (irq0 > 0) - gpio_offset = 2; - clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Error %ld to get gpio clock\n", -- cgit v1.2.3 From 442af1403a2886f8f6d43f2f67f8a8b001e048d8 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Thu, 19 Jul 2018 01:57:08 +0200 Subject: gpio: omap: Add get/set_multiple() callbacks This should make applications utilizing whole banks work faster. Signed-off-by: Janusz Krzysztofik Acked-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index d1afedf4dcbf..e81008678a38 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -77,6 +77,8 @@ struct gpio_bank { bool workaround_enabled; void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable); + void (*set_dataout_multiple)(struct gpio_bank *bank, + unsigned long *mask, unsigned long *bits); int (*get_context_loss_count)(struct device *dev); struct omap_gpio_reg_offs *regs; @@ -161,6 +163,51 @@ static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset) return (readl_relaxed(reg) & (BIT(offset))) != 0; } +/* set multiple data out values using dedicate set/clear register */ +static void omap_set_gpio_dataout_reg_multiple(struct gpio_bank *bank, + unsigned long *mask, + unsigned long *bits) +{ + void __iomem *reg = bank->base; + u32 l; + + l = *bits & *mask; + writel_relaxed(l, reg + bank->regs->set_dataout); + bank->context.dataout |= l; + + l = ~*bits & *mask; + writel_relaxed(l, reg + bank->regs->clr_dataout); + bank->context.dataout &= ~l; +} + +/* set multiple data out values using mask register */ +static void omap_set_gpio_dataout_mask_multiple(struct gpio_bank *bank, + unsigned long *mask, + unsigned long *bits) +{ + void __iomem *reg = bank->base + bank->regs->dataout; + u32 l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask); + + writel_relaxed(l, reg); + bank->context.dataout = l; +} + +static unsigned long omap_get_gpio_datain_multiple(struct gpio_bank *bank, + unsigned long *mask) +{ + void __iomem *reg = bank->base + bank->regs->datain; + + return readl_relaxed(reg) & *mask; +} + +static unsigned long omap_get_gpio_dataout_multiple(struct gpio_bank *bank, + unsigned long *mask) +{ + void __iomem *reg = bank->base + bank->regs->dataout; + + return readl_relaxed(reg) & *mask; +} + static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) { int l = readl_relaxed(base + reg); @@ -968,6 +1015,26 @@ static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value) return 0; } +static int omap_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct gpio_bank *bank = gpiochip_get_data(chip); + void __iomem *reg = bank->base + bank->regs->direction; + unsigned long in = readl_relaxed(reg), l; + + *bits = 0; + + l = in & *mask; + if (l) + *bits |= omap_get_gpio_datain_multiple(bank, &l); + + l = ~in & *mask; + if (l) + *bits |= omap_get_gpio_dataout_multiple(bank, &l); + + return 0; +} + static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, unsigned debounce) { @@ -1012,6 +1079,17 @@ static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value) raw_spin_unlock_irqrestore(&bank->lock, flags); } +static void omap_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct gpio_bank *bank = gpiochip_get_data(chip); + unsigned long flags; + + raw_spin_lock_irqsave(&bank->lock, flags); + bank->set_dataout_multiple(bank, mask, bits); + raw_spin_unlock_irqrestore(&bank->lock, flags); +} + /*---------------------------------------------------------------------*/ static void omap_gpio_show_rev(struct gpio_bank *bank) @@ -1073,9 +1151,11 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) bank->chip.get_direction = omap_gpio_get_direction; bank->chip.direction_input = omap_gpio_input; bank->chip.get = omap_gpio_get; + bank->chip.get_multiple = omap_gpio_get_multiple; bank->chip.direction_output = omap_gpio_output; bank->chip.set_config = omap_gpio_set_config; bank->chip.set = omap_gpio_set; + bank->chip.set_multiple = omap_gpio_set_multiple; if (bank->is_mpuio) { bank->chip.label = "mpuio"; if (bank->regs->wkup_en) @@ -1209,10 +1289,14 @@ static int omap_gpio_probe(struct platform_device *pdev) pdata->get_context_loss_count; } - if (bank->regs->set_dataout && bank->regs->clr_dataout) + if (bank->regs->set_dataout && bank->regs->clr_dataout) { bank->set_dataout = omap_set_gpio_dataout_reg; - else + bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple; + } else { bank->set_dataout = omap_set_gpio_dataout_mask; + bank->set_dataout_multiple = + omap_set_gpio_dataout_mask_multiple; + } raw_spin_lock_init(&bank->lock); raw_spin_lock_init(&bank->wa_lock); -- cgit v1.2.3 From cf2ff877a4eea5f5ad959050284eb93d5d2f803a Mon Sep 17 00:00:00 2001 From: Levin Du Date: Tue, 31 Jul 2018 13:59:19 +0800 Subject: gpio: syscon: rockchip: add GRF GPIO support for rk3328 In Rockchip RK3328, the output only GPIO_MUTE pin, originally for codec mute control, can also be used for general purpose. It is manipulated by the GRF_SOC_CON10 register in GRF. Aside from the GPIO_MUTE pin, the HDMI pins can also be set in the same way. Currently this GRF GPIO controller only supports the mute pin. If needed in the future, the HDMI pins support can also be added. Signed-off-by: Levin Du Reviewed-by: Rob Herring Reviewed-by: Heiko Stuebner Signed-off-by: Linus Walleij --- .../bindings/gpio/rockchip,rk3328-grf-gpio.txt | 32 ++++++++++++++++++++++ drivers/gpio/gpio-syscon.c | 31 +++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/rockchip,rk3328-grf-gpio.txt diff --git a/Documentation/devicetree/bindings/gpio/rockchip,rk3328-grf-gpio.txt b/Documentation/devicetree/bindings/gpio/rockchip,rk3328-grf-gpio.txt new file mode 100644 index 000000000000..f9231df17c2b --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/rockchip,rk3328-grf-gpio.txt @@ -0,0 +1,32 @@ +Rockchip RK3328 GRF (General Register Files) GPIO controller. + +In Rockchip RK3328, the output only GPIO_MUTE pin, originally for codec mute +control, can also be used for general purpose. It is manipulated by the +GRF_SOC_CON10 register in GRF. Aside from the GPIO_MUTE pin, the HDMI pins can +also be set in the same way. + +Currently this GPIO controller only supports the mute pin. If needed in the +future, the HDMI pins support can also be added. + +Required properties: +- compatible: Should contain "rockchip,rk3328-grf-gpio". +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be 2. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = Active high, + 1 = Active low. + +Example: + + grf: syscon@ff100000 { + compatible = "rockchip,rk3328-grf", "syscon", "simple-mfd"; + + grf_gpio: grf-gpio { + compatible = "rockchip,rk3328-grf-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + +Note: The grf_gpio node should be declared as the child of the GRF (General +Register File) node. The GPIO_MUTE pin is referred to as <&grf_gpio 0>. diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index d40cabd15e9e..87c18a544513 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -135,6 +135,33 @@ static const struct syscon_gpio_data clps711x_mctrl_gpio = { .dat_bit_offset = 0x40 * 8 + 8, }; +static void rockchip_gpio_set(struct gpio_chip *chip, unsigned int offset, + int val) +{ + struct syscon_gpio_priv *priv = gpiochip_get_data(chip); + unsigned int offs; + u8 bit; + u32 data; + int ret; + + offs = priv->dreg_offset + priv->data->dat_bit_offset + offset; + bit = offs % SYSCON_REG_BITS; + data = (val ? BIT(bit) : 0) | BIT(bit + 16); + ret = regmap_write(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + data); + if (ret < 0) + dev_err(chip->parent, "gpio write failed ret(%d)\n", ret); +} + +static const struct syscon_gpio_data rockchip_rk3328_gpio_mute = { + /* RK3328 GPIO_MUTE is an output only pin at GRF_SOC_CON10[1] */ + .flags = GPIO_SYSCON_FEAT_OUT, + .bit_count = 1, + .dat_bit_offset = 0x0428 * 8 + 1, + .set = rockchip_gpio_set, +}; + #define KEYSTONE_LOCK_BIT BIT(0) static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val) @@ -175,6 +202,10 @@ static const struct of_device_id syscon_gpio_ids[] = { .compatible = "ti,keystone-dsp-gpio", .data = &keystone_dsp_gpio, }, + { + .compatible = "rockchip,rk3328-grf-gpio", + .data = &rockchip_rk3328_gpio_mute, + }, { } }; MODULE_DEVICE_TABLE(of, syscon_gpio_ids); -- cgit v1.2.3 From 3a2f335c418fed18fc3e4b3d0ee0955e8b2c5f21 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Jul 2018 15:38:31 +0300 Subject: gpiolib: Don't shadow error code of gpiochip_lock_as_irq() gpiochip_lock_as_irq() may return a few error codes, do not shadow them by -EINVAL and let caller to decide. No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bdbfc95793e7..6bfd4e5cc161 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1805,16 +1805,18 @@ static const struct irq_domain_ops gpiochip_domain_ops = { static int gpiochip_irq_reqres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + int ret; if (!try_module_get(chip->gpiodev->owner)) return -ENODEV; - if (gpiochip_lock_as_irq(chip, d->hwirq)) { + ret = gpiochip_lock_as_irq(chip, d->hwirq); + if (ret) { chip_err(chip, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); module_put(chip->gpiodev->owner); - return -EINVAL; + return ret; } return 0; } -- cgit v1.2.3 From 9b073332dd12553751951b08f78d7d1416f5bee2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Jul 2018 15:38:32 +0300 Subject: gpio: bcm-kona: Don't shadow error code of gpiochip_lock_as_irq() gpiochip_lock_as_irq() may return a few error codes, do not shadow them by -EINVAL and let caller to decide. No functional change intended. Cc: Ray Jui Cc: Scott Branden Signed-off-by: Andy Shevchenko Reviewed-by: Florian Fainelli Signed-off-by: Linus Walleij --- drivers/gpio/gpio-bcm-kona.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 00272fa7cc4f..d0707fc23afd 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -485,12 +485,14 @@ static void bcm_kona_gpio_irq_handler(struct irq_desc *desc) static int bcm_kona_gpio_irq_reqres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); + int ret; - if (gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) { + ret = gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq); + if (ret) { dev_err(kona_gpio->gpio_chip.parent, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); - return -EINVAL; + return ret; } return 0; } -- cgit v1.2.3 From 10ed35399ab0a46c2ff07b35977e0d423bde48f2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Jul 2018 15:38:33 +0300 Subject: gpio: dwapb: Don't shadow error code of gpiochip_lock_as_irq() gpiochip_lock_as_irq() may return a few error codes, do not shadow them by -EINVAL and let caller to decide. No functional change intended. Cc: Hoan Tran Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 7a2de3de6571..28da700f5f52 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -255,11 +255,13 @@ static int dwapb_irq_reqres(struct irq_data *d) struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); struct dwapb_gpio *gpio = igc->private; struct gpio_chip *gc = &gpio->ports[0].gc; + int ret; - if (gpiochip_lock_as_irq(gc, irqd_to_hwirq(d))) { + ret = gpiochip_lock_as_irq(gc, irqd_to_hwirq(d)); + if (ret) { dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - return -EINVAL; + return ret; } return 0; } -- cgit v1.2.3 From 41d69087fd75f7288378082ee45c850109d9d289 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Jul 2018 15:38:34 +0300 Subject: gpio: em: Don't shadow error code of gpiochip_lock_as_irq() gpiochip_lock_as_irq() may return a few error codes, do not shadow them by -EINVAL and let caller to decide. No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 2b466b80e70a..982e699a5b81 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -101,12 +101,14 @@ static void em_gio_irq_enable(struct irq_data *d) static int em_gio_irq_reqres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); + int ret; - if (gpiochip_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) { + ret = gpiochip_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)); + if (ret) { dev_err(p->gpio_chip.parent, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - return -EINVAL; + return ret; } return 0; } -- cgit v1.2.3 From 6d7a2b8b559e5682167187d4413d5f11251fcb01 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Jul 2018 15:38:35 +0300 Subject: gpio: xgene-sb: Don't shadow error code of gpiochip_lock_as_irq() gpiochip_lock_as_irq() may return a few error codes, do not shadow them by -ENOSPC and let caller to decide. No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xgene-sb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index acd59113e08b..2eb76f35aa7e 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -143,12 +143,14 @@ static int xgene_gpio_sb_domain_activate(struct irq_domain *d, { struct xgene_gpio_sb *priv = d->host_data; u32 gpio = HWIRQ_TO_GPIO(priv, irq_data->hwirq); + int ret; - if (gpiochip_lock_as_irq(&priv->gc, gpio)) { + ret = gpiochip_lock_as_irq(&priv->gc, gpio); + if (ret) { dev_err(priv->gc.parent, "Unable to configure XGene GPIO standby pin %d as IRQ\n", gpio); - return -ENOSPC; + return ret; } xgene_gpio_set_bit(&priv->gc, priv->regs + MPA_GPIO_SEL_LO, -- cgit v1.2.3 From d124339da78d1f3b97d1dfa01dc4b52fca2f28e0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Jul 2018 15:38:36 +0300 Subject: gpio: uniphier: Bail out on gpiochip_lock_as_irq() error gpiochip_lock_as_irq() may return a few error codes, bail out if it fails with corresponding returned code. Signed-off-by: Andy Shevchenko Acked-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/gpio/gpio-uniphier.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index d3cf9502e7e7..ed2badecc050 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -306,8 +306,7 @@ static int uniphier_gpio_irq_domain_activate(struct irq_domain *domain, struct uniphier_gpio_priv *priv = domain->host_data; struct gpio_chip *chip = &priv->chip; - gpiochip_lock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET); - return 0; + return gpiochip_lock_as_irq(chip, data->hwirq + UNIPHIER_GPIO_IRQ_OFFSET); } static void uniphier_gpio_irq_domain_deactivate(struct irq_domain *domain, -- cgit v1.2.3 From f8ad8aa551af812adf2ba49a554c73cc9daa8d36 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 30 Jul 2018 15:38:37 +0300 Subject: gpio: vr41xx: Bail out on gpiochip_lock_as_irq() error gpiochip_lock_as_irq() may return a few error codes, bail out if it fails with corresponding returned code. Signed-off-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vr41xx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index ac8deb01f6f6..027699cec911 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -138,10 +138,16 @@ static void unmask_giuint_low(struct irq_data *d) static unsigned int startup_giuint(struct irq_data *data) { - if (gpiochip_lock_as_irq(&vr41xx_gpio_chip, data->hwirq)) + int ret; + + ret = gpiochip_lock_as_irq(&vr41xx_gpio_chip, irqd_to_hwirq(data)); + if (ret) { dev_err(vr41xx_gpio_chip.parent, "unable to lock HW IRQ %lu for IRQ\n", data->hwirq); + return ret; + } + /* Satisfy the .enable semantics by unmasking the line */ unmask_giuint_low(data); return 0; -- cgit v1.2.3 From 6ff0497402ef7269ee6a72f62eb85adaa7a4768e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 6 Aug 2018 10:48:01 +0100 Subject: gpiolib: Fix of_node inconsistency Some platforms are not setting of_node in the driver. On these platforms defining gpio-reserved-ranges on device tree leads to kernel crash. It is due to some parts of the gpio core relying on the driver to set up of_node,while other parts do themselves.This inconsistent behaviour leads to a crash. gpiochip_add_data_with_key() calls gpiochip_init_valid_mask() with of_node as NULL. of_gpiochip_add() fills "of_node" and calls of_gpiochip_init_valid_mask(). The fix is to move the assignment to chip->of_node from of_gpiochip_add() to gpiochip_add_data_with_key(). Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 3 --- drivers/gpio/gpiolib.c | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 28d968088131..91174bf15cf3 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -620,9 +620,6 @@ int of_gpiochip_add(struct gpio_chip *chip) { int status; - if ((!chip->of_node) && (chip->parent)) - chip->of_node = chip->parent->of_node; - if (!chip->of_node) return 0; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 6bfd4e5cc161..2c457e604403 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1262,6 +1262,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, /* If the gpiochip has an assigned OF node this takes precedence */ if (chip->of_node) gdev->dev.of_node = chip->of_node; + else + chip->of_node = gdev->dev.of_node; #endif gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL); -- cgit v1.2.3 From 32e49b9a808a59791513ec59fec6466d8577a5fa Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 6 Aug 2018 16:18:05 +0200 Subject: gpio: tb10x: Use the right include This driver includes the legacy and but all it needs is really . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tb10x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index ac6f2a9841e5..a12cd0b5c972 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 50fe83a3eb5000a9ea3586e1fcd8034bd3892b90 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 6 Aug 2018 17:42:46 +0200 Subject: gpio: timberdale: Include the right header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a GPIO driver so include only . Cc: Richard Röjfors Signed-off-by: Linus Walleij --- drivers/gpio/gpio-timberdale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 6520a8475910..314e300d6ba3 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -22,7 +22,7 @@ */ #include -#include +#include #include #include #include -- cgit v1.2.3 From 516df4eb284d5a5ee8f80f7b59170ba8e919b299 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 6 Aug 2018 18:39:59 +0200 Subject: gpio: xilinx: Use the right include This is a GPIO driver so use only . Acked-by: Michal Simek Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index e8ec0e33a0a9..8f24478cc18b 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include /* Register Offset Definitions */ -- cgit v1.2.3 From d799a4de0a250f1bdd99765bb8e55a5e2f469a1f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 3 Aug 2018 00:52:18 +0200 Subject: gpio: mmio: Fix up inverted direction registers The bgpio_init() takes one of two arguments to specify a register to set the direction of the GPIO line: either dirout that indicates that a 1 in the bit in that register sets the corresponding line to output, or dirin which indicates that a 1 in the bit in that register sets the corresponding line to input. Conversely setting the bit to 0 on these will turn the line into input and output respectively. One of these can be defined but not both. This means that a platform that sets a bit to 1 for output only defines dirout and a platform that sets a bit to 0 for output only defines dirin. In short this defines the polarity of the direction register. Both can also be left as NULL meaning the GPIO chip is either input only or output only. Tomer Maimon discovered that for get/set chips (those where the get and set registers are defined but no separate clear register, and specifying BGPIOF_READ_OUTPUT_REG_SET so that we say we want to read the output value from the SET register) we are unconditionally reading the value from the SET register when the direction bit is 1 and from the DAT register when the direction bit is 0, not taking the direction bit polarity into account. It would be expected that when the direction bit is inverted (dirin is defined but not dirout) we read the current value from the DAT register when the bit is 1 and from the SET register when the bit is 0. Currently only some versions of ATH79, brcmstb, some versions of CLP711x, GE, IOP and Loongson use the dirin mode (a 1 in the register means input). They are unaffected because BGPIOF_READ_OUTPUT_REG_SET is not set on any of them. (They do not read back the SET register to figure out the output value.) So this is no regression with current drivers. However the behaviour is wrong and does not work with Tomer's new driver where he needs to use the BGIOF_READ_OUTPUT_REG_SET. This fixes the above issue by: - Instead of defining separate functions for the inverted case, set up a flag in the gpio_chip that indicates that the direction is inverted. - Remove the special inverted functions for setting input/output and getting the direction, rely on the flag instead. - Respect this flag in bgpio_get_set() and bgpio_get_set_multiple() Reported-by: Tomer Maimon Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mmio.c | 108 ++++++++++++++++++++++++++------------------ include/linux/gpio/driver.h | 3 ++ 2 files changed, 66 insertions(+), 45 deletions(-) diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 7b14d6280e44..935292a30c99 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -136,8 +136,20 @@ static unsigned long bgpio_line2mask(struct gpio_chip *gc, unsigned int line) static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio) { unsigned long pinmask = bgpio_line2mask(gc, gpio); + bool dir = !!(gc->bgpio_dir & pinmask); - if (gc->bgpio_dir & pinmask) + /* + * If the direction is OUT we read the value from the SET + * register, and if the direction is IN we read the value + * from the DAT register. + * + * If the direction bits are inverted, naturally this gets + * inverted too. + */ + if (gc->bgpio_dir_inverted) + dir = !dir; + + if (dir) return !!(gc->read_reg(gc->reg_set) & pinmask); else return !!(gc->read_reg(gc->reg_dat) & pinmask); @@ -157,8 +169,13 @@ static int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask, *bits &= ~*mask; /* Exploit the fact that we know which directions are set */ - set_mask = *mask & gc->bgpio_dir; - get_mask = *mask & ~gc->bgpio_dir; + if (gc->bgpio_dir_inverted) { + set_mask = *mask & ~gc->bgpio_dir; + get_mask = *mask & gc->bgpio_dir; + } else { + set_mask = *mask & gc->bgpio_dir; + get_mask = *mask & ~gc->bgpio_dir; + } if (set_mask) *bits |= gc->read_reg(gc->reg_set) & set_mask; @@ -359,7 +376,10 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) spin_lock_irqsave(&gc->bgpio_lock, flags); - gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); + if (gc->bgpio_dir_inverted) + gc->bgpio_dir |= bgpio_line2mask(gc, gpio); + else + gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); gc->write_reg(gc->reg_dir, gc->bgpio_dir); spin_unlock_irqrestore(&gc->bgpio_lock, flags); @@ -370,7 +390,10 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) { /* Return 0 if output, 1 of input */ - return !(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); + if (gc->bgpio_dir_inverted) + return !!(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); + else + return !(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); } static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) @@ -381,37 +404,10 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) spin_lock_irqsave(&gc->bgpio_lock, flags); - gc->bgpio_dir |= bgpio_line2mask(gc, gpio); - gc->write_reg(gc->reg_dir, gc->bgpio_dir); - - spin_unlock_irqrestore(&gc->bgpio_lock, flags); - - return 0; -} - -static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio) -{ - unsigned long flags; - - spin_lock_irqsave(&gc->bgpio_lock, flags); - - gc->bgpio_dir |= bgpio_line2mask(gc, gpio); - gc->write_reg(gc->reg_dir, gc->bgpio_dir); - - spin_unlock_irqrestore(&gc->bgpio_lock, flags); - - return 0; -} - -static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) -{ - unsigned long flags; - - gc->set(gc, gpio, val); - - spin_lock_irqsave(&gc->bgpio_lock, flags); - - gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); + if (gc->bgpio_dir_inverted) + gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); + else + gc->bgpio_dir |= bgpio_line2mask(gc, gpio); gc->write_reg(gc->reg_dir, gc->bgpio_dir); spin_unlock_irqrestore(&gc->bgpio_lock, flags); @@ -419,12 +415,6 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } -static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio) -{ - /* Return 0 if output, 1 if input */ - return !!(gc->read_reg(gc->reg_dir) & bgpio_line2mask(gc, gpio)); -} - static int bgpio_setup_accessors(struct device *dev, struct gpio_chip *gc, bool byte_be) @@ -560,9 +550,10 @@ static int bgpio_setup_direction(struct gpio_chip *gc, gc->get_direction = bgpio_get_dir; } else if (dirin) { gc->reg_dir = dirin; - gc->direction_output = bgpio_dir_out_inv; - gc->direction_input = bgpio_dir_in_inv; - gc->get_direction = bgpio_get_dir_inv; + gc->direction_output = bgpio_dir_out; + gc->direction_input = bgpio_dir_in; + gc->get_direction = bgpio_get_dir; + gc->bgpio_dir_inverted = true; } else { if (flags & BGPIOF_NO_OUTPUT) gc->direction_output = bgpio_dir_out_err; @@ -582,6 +573,33 @@ static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin) return -EINVAL; } +/** + * bgpio_init() - Initialize generic GPIO accessor functions + * @gc: the GPIO chip to set up + * @dev: the parent device of the new GPIO chip (compulsory) + * @sz: the size (width) of the MMIO registers in bytes, typically 1, 2 or 4 + * @dat: MMIO address for the register to READ the value of the GPIO lines, it + * is expected that a 1 in the corresponding bit in this register means the + * line is asserted + * @set: MMIO address for the register to SET the value of the GPIO lines, it is + * expected that we write the line with 1 in this register to drive the GPIO line + * high. + * @clr: MMIO address for the register to CLEAR the value of the GPIO lines, it is + * expected that we write the line with 1 in this register to drive the GPIO line + * low. It is allowed to leave this address as NULL, in that case the SET register + * will be assumed to also clear the GPIO lines, by actively writing the line + * with 0. + * @dirout: MMIO address for the register to set the line as OUTPUT. It is assumed + * that setting a line to 1 in this register will turn that line into an + * output line. Conversely, setting the line to 0 will turn that line into + * an input. Either this or @dirin can be defined, but never both. + * @dirin: MMIO address for the register to set this line as INPUT. It is assumed + * that setting a line to 1 in this register will turn that line into an + * input line. Conversely, setting the line to 0 will turn that line into + * an output. Either this or @dirout can be defined, but never both. + * @flags: Different flags that will affect the behaviour of the device, such as + * endianness etc. + */ int bgpio_init(struct gpio_chip *gc, struct device *dev, unsigned long sz, void __iomem *dat, void __iomem *set, void __iomem *clr, void __iomem *dirout, void __iomem *dirin, diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 5382b5183b7e..0ea328e71ec9 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -201,6 +201,8 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip) * @reg_set: output set register (out=high) for generic GPIO * @reg_clr: output clear register (out=low) for generic GPIO * @reg_dir: direction setting register for generic GPIO + * @bgpio_dir_inverted: indicates that the direction register is inverted + * (gpiolib private state variable) * @bgpio_bits: number of register bits used for a generic GPIO i.e. * * 8 * @bgpio_lock: used to lock chip->bgpio_data. Also, this is needed to keep @@ -267,6 +269,7 @@ struct gpio_chip { void __iomem *reg_set; void __iomem *reg_clr; void __iomem *reg_dir; + bool bgpio_dir_inverted; int bgpio_bits; spinlock_t bgpio_lock; unsigned long bgpio_data; -- cgit v1.2.3 From 21041daba2300c88f0da538b3480a9fae37430ea Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 6 Aug 2018 17:38:33 +0200 Subject: gpio: tegra: Include the right header This is a GPIO driver so include only . Drop the use of GPIOF_* flags: these are for consumers, not drivers. Just return 0/1. Cc: Stefan Agner Cc: Thierry Reding Reviewed-by: Dmitry Osipenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 2d940785bad0..8e5f3150c6af 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -207,7 +207,7 @@ static int tegra_gpio_get_direction(struct gpio_chip *chip, oe = tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)); - return (oe & pin_mask) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; + return !(oe & pin_mask); } static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, -- cgit v1.2.3 From 3789f5acb9bbe088f70779002f32e7c6a64000bc Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 7 Aug 2018 08:15:18 +0100 Subject: gpiolib: Avoid calling chip->request() for unused gpios Add a check for unused gpios to avoid chip->request() call to client driver for unused gpios. Signed-off-by: Biju Das Reviewed-by: Fabrizio Castro Reviewed-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2c457e604403..e8f8a1999393 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2267,6 +2267,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) struct gpio_chip *chip = desc->gdev->chip; int status; unsigned long flags; + unsigned offset; spin_lock_irqsave(&gpio_lock, flags); @@ -2285,7 +2286,11 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) if (chip->request) { /* chip->request may sleep */ spin_unlock_irqrestore(&gpio_lock, flags); - status = chip->request(chip, gpio_chip_hwgpio(desc)); + offset = gpio_chip_hwgpio(desc); + if (gpiochip_line_is_valid(chip, offset)) + status = chip->request(chip, offset); + else + status = -EINVAL; spin_lock_irqsave(&gpio_lock, flags); if (status < 0) { -- cgit v1.2.3 From 62885203f71b1116d6f56ae2e6014767e1d47995 Mon Sep 17 00:00:00 2001 From: Ivan Podovalov Date: Wed, 8 Aug 2018 11:46:22 +0300 Subject: gpio: it87: add support for IT8718F Super I/O. The DIO connector on the WAFER-945GSE is interfaced to GPIO ports on the ITE IT8718F Super I/O chipset. From the datasheet of ITE IT8718F, the GPIO interface is identical to IT8728, so just add it to the same case as the other chip. Signed-off-by: Ivan Podovalov Signed-off-by: Linus Walleij --- drivers/gpio/gpio-it87.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index 7b017f43dc6b..d34f517fdd44 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -37,6 +37,7 @@ #define NO_DEV_ID 0xffff #define IT8620_ID 0x8620 #define IT8628_ID 0x8628 +#define IT8718_ID 0x8718 #define IT8728_ID 0x8728 #define IT8732_ID 0x8732 #define IT8761_ID 0x8761 @@ -315,6 +316,7 @@ static int __init it87_gpio_init(void) it87_gpio->simple_size = 0; it87_gpio->chip.ngpio = 64; break; + case IT8718_ID: case IT8728_ID: case IT8732_ID: case IT8772_ID: -- cgit v1.2.3 From a5ec96ddfd55c501d451cb310566a1170c267ecb Mon Sep 17 00:00:00 2001 From: Leonid Bloch Date: Thu, 9 Aug 2018 01:26:36 +0300 Subject: gpio: it87: Add support for IT8613 This was tested on actual hardware and found to work fine, but currently the official specifications of this chip could not be obtained to confirm the numbers. Signed-off-by: Leonid Bloch Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 3 ++- drivers/gpio/gpio-it87.c | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7429b30e61b0..f7a0f576f918 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -693,7 +693,8 @@ config GPIO_IT87 Say yes here to support GPIO functionality of IT87xx Super I/O chips. This driver is tested with ITE IT8728 and IT8732 Super I/O chips, and - supports the IT8761E, IT8620E and IT8628E Super I/O chip as well. + supports the IT8761E, IT8613, IT8620E, and IT8628E Super I/O chips as + well. To compile this driver as a module, choose M here: the module will be called gpio_it87 diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index d34f517fdd44..389ecd8b7d26 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -35,6 +35,7 @@ /* Chip Id numbers */ #define NO_DEV_ID 0xffff +#define IT8613_ID 0x8613 #define IT8620_ID 0x8620 #define IT8628_ID 0x8628 #define IT8718_ID 0x8718 @@ -308,6 +309,14 @@ static int __init it87_gpio_init(void) it87_gpio->chip = it87_template_chip; switch (chip_type) { + case IT8613_ID: + gpio_ba_reg = 0x62; + it87_gpio->io_size = 8; /* it8613 only needs 6, use 8 for alignment */ + it87_gpio->output_base = 0xc8; + it87_gpio->simple_base = 0xc0; + it87_gpio->simple_size = 6; + it87_gpio->chip.ngpio = 64; /* has 48, use 64 for convenient calc */ + break; case IT8620_ID: case IT8628_ID: gpio_ba_reg = 0x62; -- cgit v1.2.3