From b5cd7802dd7c10c5be388c8820d8e753f4f8fce7 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 12 Jan 2018 21:30:09 +0100 Subject: gpio-wm831x: Use seq_putc() in wm831x_gpio_dbg_show() A single character (line break) should be put into a sequence. Thus use the corresponding function "seq_putc". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Charles Keepax Signed-off-by: Linus Walleij --- drivers/gpio/gpio-wm831x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 938bbe3f831c..324813e8304e 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -182,7 +182,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) dev_err(wm831x->dev, "GPIO control %d read failed: %d\n", gpio, reg); - seq_printf(s, "\n"); + seq_putc(s, '\n'); continue; } -- cgit v1.2.3 From 3c87d7c874b2119c1cff4eee5586b9a6bc0b7fe9 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 21 Jan 2018 17:09:40 -0600 Subject: gpio: davinci: add support for pinmux gpio ranges This adds support for the pinmux gpio ranges feature to the DaVinci gpio driver. Only device tree is supported since the non-DT boards don't use a generic pinmux controller. Cc: Keerthy Cc: Linus Walleij Signed-off-by: David Lechner Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 0b951ca78ec4..987126c4c6f6 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -225,6 +226,11 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips->chip.of_gpio_n_cells = 2; chips->chip.parent = dev; chips->chip.of_node = dev->of_node; + + if (of_property_read_bool(dev->of_node, "gpio-ranges")) { + chips->chip.request = gpiochip_generic_request; + chips->chip.free = gpiochip_generic_free; + } #endif spin_lock_init(&chips->lock); bank_base += ngpio; -- cgit v1.2.3 From 69a87f290b46228c2ff1cc942326a90c468a2a68 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Feb 2018 22:40:23 +0100 Subject: gpio: ftgpio010: Fix some more registers There is a register for "bypass" which seems to not be used for anything in some silicon designs, but may be used in others, and there is both a raw and masked interrupt status register. Define them all for clarity, no semantic changes. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ftgpio010.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index b7a3a2db699b..e80634c464a9 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -21,12 +21,14 @@ #define GPIO_DATA_OUT 0x00 #define GPIO_DATA_IN 0x04 #define GPIO_DIR 0x08 +#define GPIO_BYPASS_IN 0x0C #define GPIO_DATA_SET 0x10 #define GPIO_DATA_CLR 0x14 #define GPIO_PULL_EN 0x18 #define GPIO_PULL_TYPE 0x1C #define GPIO_INT_EN 0x20 -#define GPIO_INT_STAT 0x24 +#define GPIO_INT_STAT_RAW 0x24 +#define GPIO_INT_STAT_MASKED 0x28 #define GPIO_INT_MASK 0x2C #define GPIO_INT_CLR 0x30 #define GPIO_INT_TYPE 0x34 @@ -147,7 +149,7 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc) chained_irq_enter(irqchip, desc); - stat = readl(g->base + GPIO_INT_STAT); + stat = readl(g->base + GPIO_INT_STAT_RAW); if (stat) for_each_set_bit(offset, &stat, gc->ngpio) generic_handle_irq(irq_find_mapping(gc->irq.domain, -- cgit v1.2.3 From a98d90e7d588045716c3c85d63f93dc3f15a079b Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 20 Feb 2018 14:19:33 +0200 Subject: gpio: raspberrypi-exp: Driver for RPi3 GPIO expander via mailbox service Pi3 and Compute Module 3 have a GPIO expander that the VPU communicates with. There is a mailbox service that now allows control of this expander, so add a kernel driver that can make use of it. Reviewed-by: Stefan Wahren Signed-off-by: Dave Stevenson Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-raspberrypi-exp.c | 252 ++++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 drivers/gpio/gpio-raspberrypi-exp.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8dbb2280538d..fd0562a37f68 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -122,6 +122,15 @@ config GPIO_ATH79 Select this option to enable GPIO driver for Atheros AR71XX/AR724X/AR913X SoC devices. +config GPIO_RASPBERRYPI_EXP + tristate "Raspberry Pi 3 GPIO Expander" + default RASPBERRYPI_FIRMWARE + depends on OF_GPIO + depends on (ARCH_BCM2835 && RASPBERRYPI_FIRMWARE) || COMPILE_TEST + help + Turn on GPIO support for the expander on Raspberry Pi 3 boards, using + the firmware mailbox to communicate with VideoCore on BCM283x chips. + config GPIO_BCM_KONA bool "Broadcom Kona GPIO" depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index cccb0d40846c..76dc0a02bd56 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o +obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c new file mode 100644 index 000000000000..d6d36d537e37 --- /dev/null +++ b/drivers/gpio/gpio-raspberrypi-exp.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Raspberry Pi 3 expander GPIO driver + * + * Uses the firmware mailbox service to communicate with the + * GPIO expander on the VPU. + * + * Copyright (C) 2017 Raspberry Pi Trading Ltd. + */ + +#include +#include +#include +#include +#include + +#define MODULE_NAME "raspberrypi-exp-gpio" +#define NUM_GPIO 8 + +#define RPI_EXP_GPIO_BASE 128 + +#define RPI_EXP_GPIO_DIR_IN 0 +#define RPI_EXP_GPIO_DIR_OUT 1 + +struct rpi_exp_gpio { + struct gpio_chip gc; + struct rpi_firmware *fw; +}; + +/* VC4 firmware mailbox interface data structures */ + +struct gpio_set_config { + u32 gpio; + u32 direction; + u32 polarity; + u32 term_en; + u32 term_pull_up; + u32 state; +}; + +struct gpio_get_config { + u32 gpio; + u32 direction; + u32 polarity; + u32 term_en; + u32 term_pull_up; +}; + +struct gpio_get_set_state { + u32 gpio; + u32 state; +}; + +static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off) +{ + struct rpi_exp_gpio *gpio; + struct gpio_get_config get; + int ret; + + gpio = gpiochip_get_data(gc); + + get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */ + + ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG, + &get, sizeof(get)); + if (ret || get.gpio != 0) { + dev_err(gc->parent, "Failed to get GPIO %u config (%d %x)\n", + off, ret, get.gpio); + return ret ? ret : -EIO; + } + return get.polarity; +} + +static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off) +{ + struct rpi_exp_gpio *gpio; + struct gpio_set_config set_in; + int ret; + + gpio = gpiochip_get_data(gc); + + set_in.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */ + set_in.direction = RPI_EXP_GPIO_DIR_IN; + set_in.term_en = 0; /* termination disabled */ + set_in.term_pull_up = 0; /* n/a as termination disabled */ + set_in.state = 0; /* n/a as configured as an input */ + + ret = rpi_exp_gpio_get_polarity(gc, off); + if (ret < 0) + return ret; + set_in.polarity = ret; /* Retain existing setting */ + + ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG, + &set_in, sizeof(set_in)); + if (ret || set_in.gpio != 0) { + dev_err(gc->parent, "Failed to set GPIO %u to input (%d %x)\n", + off, ret, set_in.gpio); + return ret ? ret : -EIO; + } + return 0; +} + +static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val) +{ + struct rpi_exp_gpio *gpio; + struct gpio_set_config set_out; + int ret; + + gpio = gpiochip_get_data(gc); + + set_out.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */ + set_out.direction = RPI_EXP_GPIO_DIR_OUT; + set_out.term_en = 0; /* n/a as an output */ + set_out.term_pull_up = 0; /* n/a as termination disabled */ + set_out.state = val; /* Output state */ + + ret = rpi_exp_gpio_get_polarity(gc, off); + if (ret < 0) + return ret; + set_out.polarity = ret; /* Retain existing setting */ + + ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG, + &set_out, sizeof(set_out)); + if (ret || set_out.gpio != 0) { + dev_err(gc->parent, "Failed to set GPIO %u to output (%d %x)\n", + off, ret, set_out.gpio); + return ret ? ret : -EIO; + } + return 0; +} + +static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off) +{ + struct rpi_exp_gpio *gpio; + struct gpio_get_config get; + int ret; + + gpio = gpiochip_get_data(gc); + + get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */ + + ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG, + &get, sizeof(get)); + if (ret || get.gpio != 0) { + dev_err(gc->parent, + "Failed to get GPIO %u config (%d %x)\n", off, ret, + get.gpio); + return ret ? ret : -EIO; + } + return !get.direction; +} + +static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off) +{ + struct rpi_exp_gpio *gpio; + struct gpio_get_set_state get; + int ret; + + gpio = gpiochip_get_data(gc); + + get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */ + get.state = 0; /* storage for returned value */ + + ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_STATE, + &get, sizeof(get)); + if (ret || get.gpio != 0) { + dev_err(gc->parent, + "Failed to get GPIO %u state (%d %x)\n", off, ret, + get.gpio); + return ret ? ret : -EIO; + } + return !!get.state; +} + +static void rpi_exp_gpio_set(struct gpio_chip *gc, unsigned int off, int val) +{ + struct rpi_exp_gpio *gpio; + struct gpio_get_set_state set; + int ret; + + gpio = gpiochip_get_data(gc); + + set.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */ + set.state = val; /* Output state */ + + ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_STATE, + &set, sizeof(set)); + if (ret || set.gpio != 0) + dev_err(gc->parent, + "Failed to set GPIO %u state (%d %x)\n", off, ret, + set.gpio); +} + +static int rpi_exp_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *fw_node; + struct rpi_firmware *fw; + struct rpi_exp_gpio *rpi_gpio; + + fw_node = of_get_parent(np); + if (!fw_node) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + fw = rpi_firmware_get(fw_node); + if (!fw) + return -EPROBE_DEFER; + + rpi_gpio = devm_kzalloc(dev, sizeof(*rpi_gpio), GFP_KERNEL); + if (!rpi_gpio) + return -ENOMEM; + + rpi_gpio->fw = fw; + rpi_gpio->gc.parent = dev; + rpi_gpio->gc.label = MODULE_NAME; + rpi_gpio->gc.owner = THIS_MODULE; + rpi_gpio->gc.of_node = np; + rpi_gpio->gc.base = -1; + rpi_gpio->gc.ngpio = NUM_GPIO; + + rpi_gpio->gc.direction_input = rpi_exp_gpio_dir_in; + rpi_gpio->gc.direction_output = rpi_exp_gpio_dir_out; + rpi_gpio->gc.get_direction = rpi_exp_gpio_get_direction; + rpi_gpio->gc.get = rpi_exp_gpio_get; + rpi_gpio->gc.set = rpi_exp_gpio_set; + rpi_gpio->gc.can_sleep = true; + + return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio); +} + +static const struct of_device_id rpi_exp_gpio_ids[] = { + { .compatible = "raspberrypi,firmware-gpio" }, + { } +}; +MODULE_DEVICE_TABLE(of, rpi_exp_gpio_ids); + +static struct platform_driver rpi_exp_gpio_driver = { + .driver = { + .name = MODULE_NAME, + .of_match_table = of_match_ptr(rpi_exp_gpio_ids), + }, + .probe = rpi_exp_gpio_probe, +}; +module_platform_driver(rpi_exp_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Dave Stevenson "); +MODULE_DESCRIPTION("Raspberry Pi 3 expander GPIO driver"); +MODULE_ALIAS("platform:rpi-exp-gpio"); -- cgit v1.2.3 From 8f55fed3c98ced66fff21a41e57fd1784f4fd723 Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Fri, 9 Feb 2018 13:07:29 +0100 Subject: gpio: Add GPIO driver for Nintendo Wii MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Nintendo Wii's chipset (called "Hollywood") has a GPIO controller that supports a configurable number of pins (up to 32), interrupts, and some special mechanisms to share the controller between the system's security processor (an ARM926) and the PowerPC CPU. Pin multiplexing is not supported. This patch adds a basic driver for this GPIO controller. Interrupt support will come in a later patch. This patch is based on code developed by Albert Herranz and the GameCube Linux Team, file arch/powerpc/platforms/embedded6xx/hlwd-gpio.c, available at https://github.com/DeltaResero/GC-Wii-Linux-Kernels, but has grown quite dissimilar. v3: - Do some style cleanups, as suggest by Andy Shevchenko v2: - Change hlwd_gpio_driver.driver.name to "gpio-hlwd" to match the filename (was "hlwd_gpio") - Remove unnecessary include of linux/of_gpio.h, as suggested by Linus Walleij. - Add struct device pointer to context struct to make it possible to use dev_info(hlwd->dev, "..."), as suggested by Linus Walleij - Use the GPIO_GENERIC library to reduce code size, as suggested by Linus Walleij - Use iowrite32be instead of __raw_writel for big-endian MMIO access, as suggested by Linus Walleij - Remove commit message paragraph suggesting to diff against the original driver, because it's so different now Signed-off-by: Jonathan Neuschäfer Cc: Albert Herranz Reviewed-by: Segher Boessenkool Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 9 ++++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-hlwd.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 drivers/gpio/gpio-hlwd.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index fd0562a37f68..13728dd639e6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -232,6 +232,15 @@ config GPIO_GRGPIO Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB VHDL IP core library. +config GPIO_HLWD + tristate "Nintendo Wii (Hollywood) GPIO" + depends on OF_GPIO + select GPIO_GENERIC + help + Select this to support the GPIO controller of the Nintendo Wii. + + If unsure, say N. + config GPIO_ICH tristate "Intel ICH GPIO" depends on PCI && X86 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 76dc0a02bd56..77f88bc086c4 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o +obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_INGENIC) += gpio-ingenic.o diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c new file mode 100644 index 000000000000..a63136a68ba3 --- /dev/null +++ b/drivers/gpio/gpio-hlwd.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (C) 2008-2009 The GameCube Linux Team +// Copyright (C) 2008,2009 Albert Herranz +// Copyright (C) 2017-2018 Jonathan Neuschäfer +// +// Nintendo Wii (Hollywood) GPIO driver + +#include +#include +#include +#include +#include +#include +#include + +/* + * Register names and offsets courtesy of WiiBrew: + * https://wiibrew.org/wiki/Hardware/Hollywood_GPIOs + * + * Note that for most registers, there are two versions: + * - HW_GPIOB_* Is always accessible by the Broadway PowerPC core, but does + * always give access to all GPIO lines + * - HW_GPIO_* Is only accessible by the Broadway PowerPC code if the memory + * firewall (AHBPROT) in the Hollywood chipset has been configured to allow + * such access. + * + * The ownership of each GPIO line can be configured in the HW_GPIO_OWNER + * register: A one bit configures the line for access via the HW_GPIOB_* + * registers, a zero bit indicates access via HW_GPIO_*. This driver uses + * HW_GPIOB_*. + */ +#define HW_GPIOB_OUT 0x00 +#define HW_GPIOB_DIR 0x04 +#define HW_GPIOB_IN 0x08 +#define HW_GPIOB_INTLVL 0x0c +#define HW_GPIOB_INTFLAG 0x10 +#define HW_GPIOB_INTMASK 0x14 +#define HW_GPIOB_INMIR 0x18 +#define HW_GPIO_ENABLE 0x1c +#define HW_GPIO_OUT 0x20 +#define HW_GPIO_DIR 0x24 +#define HW_GPIO_IN 0x28 +#define HW_GPIO_INTLVL 0x2c +#define HW_GPIO_INTFLAG 0x30 +#define HW_GPIO_INTMASK 0x34 +#define HW_GPIO_INMIR 0x38 +#define HW_GPIO_OWNER 0x3c + +struct hlwd_gpio { + struct gpio_chip gpioc; + void __iomem *regs; +}; + +static int hlwd_gpio_probe(struct platform_device *pdev) +{ + struct hlwd_gpio *hlwd; + struct resource *regs_resource; + u32 ngpios; + int res; + + hlwd = devm_kzalloc(&pdev->dev, sizeof(*hlwd), GFP_KERNEL); + if (!hlwd) + return -ENOMEM; + + regs_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hlwd->regs = devm_ioremap_resource(&pdev->dev, regs_resource); + if (IS_ERR(hlwd->regs)) + return PTR_ERR(hlwd->regs); + + /* + * Claim all GPIOs using the OWNER register. This will not work on + * systems where the AHBPROT memory firewall hasn't been configured to + * permit PPC access to HW_GPIO_*. + * + * Note that this has to happen before bgpio_init reads the + * HW_GPIOB_OUT and HW_GPIOB_DIR, because otherwise it reads the wrong + * values. + */ + iowrite32be(0xffffffff, hlwd->regs + HW_GPIO_OWNER); + + res = bgpio_init(&hlwd->gpioc, &pdev->dev, 4, + hlwd->regs + HW_GPIOB_IN, hlwd->regs + HW_GPIOB_OUT, + NULL, hlwd->regs + HW_GPIOB_DIR, NULL, + BGPIOF_BIG_ENDIAN_BYTE_ORDER); + if (res < 0) { + dev_warn(&pdev->dev, "bgpio_init failed: %d\n", res); + return res; + } + + res = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios); + if (res) + ngpios = 32; + hlwd->gpioc.ngpio = ngpios; + + return devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd); +} + +static const struct of_device_id hlwd_gpio_match[] = { + { .compatible = "nintendo,hollywood-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, hlwd_gpio_match); + +static struct platform_driver hlwd_gpio_driver = { + .driver = { + .name = "gpio-hlwd", + .of_match_table = hlwd_gpio_match, + }, + .probe = hlwd_gpio_probe, +}; +module_platform_driver(hlwd_gpio_driver); + +MODULE_AUTHOR("Jonathan Neuschäfer "); +MODULE_DESCRIPTION("Nintendo Wii GPIO driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 587ca5ed56679f7697919b90eeb0ea8a87d55368 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 10 Feb 2018 21:09:08 +0100 Subject: gpio: timberdale: Delete an error message Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/gpio/gpio-timberdale.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 181f86ce00cd..ff155e437210 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -239,10 +239,9 @@ static int timbgpio_probe(struct platform_device *pdev) } tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL); - if (!tgpio) { - dev_err(dev, "Memory alloc failed\n"); + if (!tgpio) return -EINVAL; - } + tgpio->irq_base = pdata->irq_base; spin_lock_init(&tgpio->lock); -- cgit v1.2.3 From 2c3087e1649fe4391b565fc31f588670e11fc4d4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 10 Feb 2018 21:13:28 +0100 Subject: gpio: timberdale: Improve a size determination Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/gpio/gpio-timberdale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index ff155e437210..6520a8475910 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -238,7 +238,7 @@ static int timbgpio_probe(struct platform_device *pdev) return -EINVAL; } - tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL); + tgpio = devm_kzalloc(dev, sizeof(*tgpio), GFP_KERNEL); if (!tgpio) return -EINVAL; -- cgit v1.2.3 From 9117d40b5dec65fb4b1320cbad54c9c9e067de00 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 10 Feb 2018 21:46:30 +0100 Subject: gpio: omap: Delete an error message Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index ab5035b96886..4db6f13fa133 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1158,10 +1158,8 @@ static int omap_gpio_probe(struct platform_device *pdev) return -EINVAL; bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL); - if (!bank) { - dev_err(dev, "Memory alloc failed\n"); + if (!bank) return -ENOMEM; - } irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL); if (!irqc) -- cgit v1.2.3 From f97364c9b89ea0e60f3fa2e9d6e7bdf9627b891b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 10 Feb 2018 21:49:22 +0100 Subject: gpio: omap: Improve a size determination Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 4db6f13fa133..35971a341c40 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1157,7 +1157,7 @@ static int omap_gpio_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL); + bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); if (!bank) return -ENOMEM; -- cgit v1.2.3 From 4aed95793f9bd492380e6165fa6d3b02263017c4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 10 Feb 2018 22:27:15 +0100 Subject: gpio-ml-ioh: Delete an error message Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ml-ioh.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 4b80e996d976..b3678bd1c120 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -445,7 +445,6 @@ static int ioh_gpio_probe(struct pci_dev *pdev, chip_save = kzalloc(sizeof(*chip) * 8, GFP_KERNEL); if (chip_save == NULL) { - dev_err(&pdev->dev, "%s : kzalloc failed", __func__); ret = -ENOMEM; goto err_kzalloc; } -- cgit v1.2.3 From 4b7edaef795c1bc848cab3b3b6a5b42f2d64db29 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 11 Feb 2018 13:30:14 +0100 Subject: gpio: merrifield: Delete an error message Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index c38624ea0251..97421bd4a60f 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -416,10 +416,8 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id pcim_iounmap_regions(pdev, BIT(1)); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "can't allocate chip data\n"); + if (!priv) return -ENOMEM; - } priv->dev = &pdev->dev; priv->reg_base = pcim_iomap_table(pdev)[0]; -- cgit v1.2.3 From 2773eb2f98011b398fcf8f6cc12c4981a00ed452 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 12 Feb 2018 22:01:57 +0800 Subject: gpio: tegra: Convert to use DEFINE_SHOW_ATTRIBUTE macro Use DEFINE_SHOW_ATTRIBUTE macro to simplify the code. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 02fa8fe2292a..94396caaca75 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -506,7 +506,7 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) #include #include -static int dbg_gpio_show(struct seq_file *s, void *unused) +static int tegra_dbg_gpio_show(struct seq_file *s, void *unused) { struct tegra_gpio_info *tgi = s->private; unsigned int i, j; @@ -530,22 +530,12 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) return 0; } -static int dbg_gpio_open(struct inode *inode, struct file *file) -{ - return single_open(file, dbg_gpio_show, inode->i_private); -} - -static const struct file_operations debug_fops = { - .open = dbg_gpio_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(tegra_dbg_gpio); static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi) { (void) debugfs_create_file("tegra_gpio", 0444, - NULL, tgi, &debug_fops); + NULL, tgi, &tegra_dbg_gpio_fops); } #else -- cgit v1.2.3 From 75f8f5af0c2b633352baabd288eff419eb921106 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 11 Feb 2018 21:56:42 +0100 Subject: gpio-intel-mid: Delete an error message Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-intel-mid.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index 629575ea46a0..028d64c2cb1e 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -361,10 +361,8 @@ static int intel_gpio_probe(struct pci_dev *pdev, pcim_iounmap_regions(pdev, 1 << 1); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "can't allocate chip data\n"); + if (!priv) return -ENOMEM; - } priv->reg_base = pcim_iomap_table(pdev)[0]; priv->chip.label = dev_name(&pdev->dev); -- cgit v1.2.3 From 63f2dc0a76120e07c7482c7c95b2254fad39b343 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 8 Feb 2018 17:57:43 +0100 Subject: gpio: include consumer header in gpiolib.h We are forward-declaring enum gpiod_flags, but this is not referenced by pointer, it is a real struct member, so we need to actually include it to compile anything including the local gpiolib.h header. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index b17ec6795c81..ad456b6f9d8b 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -13,13 +13,13 @@ #define GPIOLIB_H #include +#include /* for enum gpiod_flags */ #include #include #include #include enum of_gpio_flags; -enum gpiod_flags; enum gpio_lookup_flags; struct acpi_device; -- cgit v1.2.3 From 89f99feb9c73d823d15f40599d998eb11a228465 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 8 Feb 2018 17:03:58 +0100 Subject: gpio: dwapb: Use "stride" rather than "size" for register distance This terminology is more precise. Also cut the stride calculation in the preprocessor, it confuses more than it helps when reading the driver. Acked-by: Hoan Tran Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 6730c6642ce3..677988f21369 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -53,9 +53,9 @@ #define GPIO_EXT_PORTD 0x5c #define DWAPB_MAX_PORTS 4 -#define GPIO_EXT_PORT_SIZE (GPIO_EXT_PORTB - GPIO_EXT_PORTA) -#define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR) -#define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR) +#define GPIO_EXT_PORT_STRIDE 0x04 /* register stride 32 bits */ +#define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */ +#define GPIO_SWPORT_DDR_STRIDE 0x0c /* register stride 3*32 bits */ #define GPIO_REG_OFFSET_V2 1 @@ -476,10 +476,10 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, return -ENOMEM; #endif - dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_SIZE); - set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_SIZE); + dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_STRIDE); + set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_STRIDE); dirout = gpio->regs + GPIO_SWPORTA_DDR + - (pp->idx * GPIO_SWPORT_DDR_SIZE); + (pp->idx * GPIO_SWPORT_DDR_STRIDE); err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout, NULL, 0); @@ -710,13 +710,13 @@ static int dwapb_gpio_suspend(struct device *dev) BUG_ON(!ctx); - offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE; + offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE; ctx->dir = dwapb_read(gpio, offset); - offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE; + offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE; ctx->data = dwapb_read(gpio, offset); - offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE; + offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_STRIDE; ctx->ext = dwapb_read(gpio, offset); /* Only port A can provide interrupts */ @@ -753,13 +753,13 @@ static int dwapb_gpio_resume(struct device *dev) BUG_ON(!ctx); - offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE; + offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE; dwapb_write(gpio, offset, ctx->data); - offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE; + offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE; dwapb_write(gpio, offset, ctx->dir); - offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE; + offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_STRIDE; dwapb_write(gpio, offset, ctx->ext); /* Only port A can provide interrupts */ -- cgit v1.2.3 From 62c16234bbfd2758ec2fdd1a716d13418c58044d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 8 Feb 2018 18:00:05 +0100 Subject: gpio: dwapb: Call directly into the gpiochip to read value We were going out through the (legacy) gpio API to read the value of a line to set up polarity inversion. This is abusive. Do something less abusive by looking up the actual struct gpio_chip * instance and calling .get() directly on it. Acked-by: Hoan Tran Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 677988f21369..b0704a883513 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -9,8 +9,6 @@ */ #include #include -/* FIXME: for gpio_get_value(), replace this with direct register read */ -#include #include #include #include @@ -153,16 +151,40 @@ static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return irq_find_mapping(gpio->domain, offset); } +static struct dwapb_gpio_port *dwapb_offs_to_port(struct dwapb_gpio *gpio, unsigned int offs) +{ + struct dwapb_gpio_port *port; + int i; + + for (i = 0; i < gpio->nr_ports; i++) { + port = &gpio->ports[i]; + if (port->idx == offs / 32) + return port; + } + + return NULL; +} + static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs) { - u32 v = dwapb_read(gpio, GPIO_INT_POLARITY); + struct dwapb_gpio_port *port = dwapb_offs_to_port(gpio, offs); + struct gpio_chip *gc; + u32 pol; + int val; + + if (!port) + return; + gc = &port->gc; - if (gpio_get_value(gpio->ports[0].gc.base + offs)) - v &= ~BIT(offs); + pol = dwapb_read(gpio, GPIO_INT_POLARITY); + /* Just read the current value right out of the data register */ + val = gc->get(gc, offs % 32); + if (val) + pol &= ~BIT(offs); else - v |= BIT(offs); + pol |= BIT(offs); - dwapb_write(gpio, GPIO_INT_POLARITY, v); + dwapb_write(gpio, GPIO_INT_POLARITY, pol); } static u32 dwapb_do_irq(struct dwapb_gpio *gpio) @@ -481,6 +503,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, dirout = gpio->regs + GPIO_SWPORTA_DDR + (pp->idx * GPIO_SWPORT_DDR_STRIDE); + /* This registers 32 GPIO lines per port */ err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout, NULL, 0); if (err) { -- cgit v1.2.3 From 51750fb167a054684a18c20e0e78f7f65b12c985 Mon Sep 17 00:00:00 2001 From: Hien Dang Date: Mon, 5 Feb 2018 04:15:02 +0900 Subject: gpio: gpio-rcar: Support S2RAM This patch adds an implementation that saves and restores the state of GPIO configuration on suspend and resume. Signed-off-by: Hien Dang Signed-off-by: Takeshi Kihara [Modify structure of the bank info to simplify a saving registers] [Remove DEV_PM_OPS macro] Signed-off-by: Yoshihiro Kaneko Tested-by: Nguyen Viet Dung Reviewed-by: Simon Horman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index e76de57dd617..e5b0dbe43c01 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -31,6 +31,16 @@ #include #include +struct gpio_rcar_bank_info { + u32 iointsel; + u32 inoutsel; + u32 outdt; + u32 posneg; + u32 edglevel; + u32 bothedge; + u32 intmsk; +}; + struct gpio_rcar_priv { void __iomem *base; spinlock_t lock; @@ -41,6 +51,7 @@ struct gpio_rcar_priv { unsigned int irq_parent; bool has_both_edge_trigger; bool needs_clk; + struct gpio_rcar_bank_info bank_info; }; #define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ @@ -531,11 +542,66 @@ static int gpio_rcar_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int gpio_rcar_suspend(struct device *dev) +{ + struct gpio_rcar_priv *p = dev_get_drvdata(dev); + + p->bank_info.iointsel = gpio_rcar_read(p, IOINTSEL); + p->bank_info.inoutsel = gpio_rcar_read(p, INOUTSEL); + p->bank_info.outdt = gpio_rcar_read(p, OUTDT); + p->bank_info.intmsk = gpio_rcar_read(p, INTMSK); + p->bank_info.posneg = gpio_rcar_read(p, POSNEG); + p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL); + if (p->has_both_edge_trigger) + p->bank_info.bothedge = gpio_rcar_read(p, BOTHEDGE); + + return 0; +} + +static int gpio_rcar_resume(struct device *dev) +{ + struct gpio_rcar_priv *p = dev_get_drvdata(dev); + unsigned int offset; + u32 mask; + + for (offset = 0; offset < p->gpio_chip.ngpio; offset++) { + mask = BIT(offset); + /* I/O pin */ + if (!(p->bank_info.iointsel & mask)) { + if (p->bank_info.inoutsel & mask) + gpio_rcar_direction_output( + &p->gpio_chip, offset, + !!(p->bank_info.outdt & mask)); + else + gpio_rcar_direction_input(&p->gpio_chip, + offset); + } else { + /* Interrupt pin */ + gpio_rcar_config_interrupt_input_mode( + p, + offset, + !(p->bank_info.posneg & mask), + !(p->bank_info.edglevel & mask), + !!(p->bank_info.bothedge & mask)); + + if (p->bank_info.intmsk & mask) + gpio_rcar_write(p, MSKCLR, mask); + } + } + + return 0; +} +#endif /* CONFIG_PM_SLEEP*/ + +static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, gpio_rcar_resume); + static struct platform_driver gpio_rcar_device_driver = { .probe = gpio_rcar_probe, .remove = gpio_rcar_remove, .driver = { .name = "gpio_rcar", + .pm = &gpio_rcar_pm_ops, .of_match_table = of_match_ptr(gpio_rcar_of_table), } }; -- cgit v1.2.3 From 1f8f93683da36a64109178344aee0dddd594bc7f Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Fri, 29 Dec 2017 15:13:19 -0500 Subject: iio: Change ISA_BUS_API dependency to selection The ISA_BUS_API Kconfig option enables the compilation of the ISA bus driver. The ISA bus driver does not perform any hardware interaction, and is instead just a thin layer of software abstraction to eliminate boilerplate code common to ISA-style device drivers. Since ISA_BUS_API has no dependencies and does not jeopardize the integrity of the system when enabled, drivers should select it when the ISA bus driver functionality is needed. Cc: Hartmut Knaack Cc: Lars-Peter Clausen Cc: Peter Meerwald-Stadler Signed-off-by: William Breathitt Gray Acked-by: Jonathan Cameron Signed-off-by: Linus Walleij --- drivers/iio/adc/Kconfig | 3 ++- drivers/iio/counter/Kconfig | 3 ++- drivers/iio/dac/Kconfig | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 72bc2b71765a..aa333184ddcf 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -698,7 +698,8 @@ config STM32_DFSDM_ADC config STX104 tristate "Apex Embedded Systems STX104 driver" - depends on PC104 && X86 && ISA_BUS_API + depends on PC104 && X86 + select ISA_BUS_API select GPIOLIB help Say yes here to build support for the Apex Embedded Systems STX104 diff --git a/drivers/iio/counter/Kconfig b/drivers/iio/counter/Kconfig index 474e1ac4e7c0..bf1e559ad7cd 100644 --- a/drivers/iio/counter/Kconfig +++ b/drivers/iio/counter/Kconfig @@ -7,7 +7,8 @@ menu "Counters" config 104_QUAD_8 tristate "ACCES 104-QUAD-8 driver" - depends on PC104 && X86 && ISA_BUS_API + depends on PC104 && X86 + select ISA_BUS_API help Say yes here to build support for the ACCES 104-QUAD-8 quadrature encoder counter/interface device family (104-QUAD-8, 104-QUAD-4). diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 965d5c0d2468..76db0768e454 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -195,7 +195,8 @@ config AD7303 config CIO_DAC tristate "Measurement Computing CIO-DAC IIO driver" - depends on X86 && ISA_BUS_API + depends on X86 && (ISA_BUS || PC104) + select ISA_BUS_API help Say yes here to build support for the Measurement Computing CIO-DAC analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The -- cgit v1.2.3 From ccfe35eac21e2f3f99f44c6f4e1bd4d3ba20fe3b Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Fri, 29 Dec 2017 15:13:34 -0500 Subject: watchdog: Change ISA_BUS_API dependency to selection The ISA_BUS_API Kconfig option enables the compilation of the ISA bus driver. The ISA bus driver does not perform any hardware interaction, and is instead just a thin layer of software abstraction to eliminate boilerplate code common to ISA-style device drivers. Since ISA_BUS_API has no dependencies and does not jeopardize the integrity of the system when enabled, drivers should select it when the ISA bus driver functionality is needed. Cc: Wim Van Sebroeck Acked-by: Guenter Roeck Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/watchdog/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index aff773bcebdb..15ff803a666f 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -882,7 +882,8 @@ config ALIM7101_WDT config EBC_C384_WDT tristate "WinSystems EBC-C384 Watchdog Timer" - depends on X86 && ISA_BUS_API + depends on X86 + select ISA_BUS_API select WATCHDOG_CORE help Enables watchdog timer support for the watchdog timer on the -- cgit v1.2.3 From 35decc803c8ad9a84de890c1fea0ba1768666390 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Fri, 29 Dec 2017 15:13:46 -0500 Subject: gpio: Change ISA_BUS_API dependency to selection The ISA_BUS_API Kconfig option enables the compilation of the ISA bus driver. The ISA bus driver does not perform any hardware interaction, and is instead just a thin layer of software abstraction to eliminate boilerplate code common to ISA-style device drivers. Since ISA_BUS_API has no dependencies and does not jeopardize the integrity of the system when enabled, drivers should select it when the ISA bus driver functionality is needed. Cc: Linus Walleij Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 13728dd639e6..dff99871bca8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -608,7 +608,8 @@ menu "Port-mapped I/O GPIO drivers" config GPIO_104_DIO_48E tristate "ACCES 104-DIO-48E GPIO support" - depends on PC104 && ISA_BUS_API + depends on PC104 + select ISA_BUS_API select GPIOLIB_IRQCHIP help Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, @@ -618,7 +619,8 @@ config GPIO_104_DIO_48E config GPIO_104_IDIO_16 tristate "ACCES 104-IDIO-16 GPIO support" - depends on PC104 && ISA_BUS_API + depends on PC104 + select ISA_BUS_API select GPIOLIB_IRQCHIP help Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16, @@ -629,7 +631,8 @@ config GPIO_104_IDIO_16 config GPIO_104_IDI_48 tristate "ACCES 104-IDI-48 GPIO support" - depends on PC104 && ISA_BUS_API + depends on PC104 + select ISA_BUS_API select GPIOLIB_IRQCHIP help Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A, @@ -649,7 +652,8 @@ config GPIO_F7188X config GPIO_GPIO_MM tristate "Diamond Systems GPIO-MM GPIO support" - depends on PC104 && ISA_BUS_API + depends on PC104 + select ISA_BUS_API help Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12. @@ -734,7 +738,7 @@ config GPIO_WINBOND config GPIO_WS16C48 tristate "WinSystems WS16C48 GPIO support" - depends on ISA_BUS_API + select ISA_BUS_API select GPIOLIB_IRQCHIP help Enables GPIO support for the WinSystems WS16C48. The base port -- cgit v1.2.3 From ca34b4f0bed802e1c8612ef08456b20992aeb02a Mon Sep 17 00:00:00 2001 From: Rajmohan Mani Date: Tue, 20 Feb 2018 15:54:08 -0800 Subject: gpio: tps68470: Update to SPDX license identifier Remove the GPL v2 license boilerplate and update with the SPDX license identifier. Signed-off-by: Rajmohan Mani Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tps68470.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tps68470.c b/drivers/gpio/gpio-tps68470.c index fa2662f8b026..aff6e504c666 100644 --- a/drivers/gpio/gpio-tps68470.c +++ b/drivers/gpio/gpio-tps68470.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * GPIO driver for TPS68470 PMIC * @@ -8,15 +9,6 @@ * Tianshu Qiu * Jian Xu Zheng * Yuning Pu - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include -- cgit v1.2.3 From b995ff3b3017073f5251be9d525b3741e631c30f Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Fri, 23 Feb 2018 15:55:17 +0100 Subject: Revert "gpio: winbond: fix ISA_BUS_API dependency" This reverts commit 92a8046c9d952a2a7d21dfcd3afadc72a0bc0f72. Now that the patch series changing ISA_BUS_API dependency to selection was merged this reversion will do the same for gpio-winbond driver to make it consistent with other ISA bus gpio drivers. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index dff99871bca8..6d481ef03623 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -722,7 +722,7 @@ config GPIO_TS5500 config GPIO_WINBOND tristate "Winbond Super I/O GPIO support" - depends on ISA_BUS_API + select ISA_BUS_API help This option enables support for GPIOs found on Winbond Super I/O chips. -- cgit v1.2.3 From 8f6d3b01477e09fc3e53a4935eba095b2357306f Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 21 Feb 2018 23:38:22 +0000 Subject: gpio: Drop TZ1090 drivers Now that arch/metag/ has been removed, along with TZ1090 SoC support, remove the TZ1090 GPIO drivers. They are of no value without the architecture and SoC platform code. Signed-off-by: James Hogan Cc: linux-gpio@vger.kernel.org Cc: linux-metag@vger.kernel.org Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-tz1090-pdc.txt | 45 -- .../devicetree/bindings/gpio/gpio-tz1090.txt | 88 --- drivers/gpio/Kconfig | 15 - drivers/gpio/Makefile | 2 - drivers/gpio/gpio-tz1090-pdc.c | 231 -------- drivers/gpio/gpio-tz1090.c | 602 --------------------- 6 files changed, 983 deletions(-) delete mode 100644 Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt delete mode 100644 Documentation/devicetree/bindings/gpio/gpio-tz1090.txt delete mode 100644 drivers/gpio/gpio-tz1090-pdc.c delete mode 100644 drivers/gpio/gpio-tz1090.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt b/Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt deleted file mode 100644 index 528f5ef5a893..000000000000 --- a/Documentation/devicetree/bindings/gpio/gpio-tz1090-pdc.txt +++ /dev/null @@ -1,45 +0,0 @@ -ImgTec TZ1090 PDC GPIO Controller - -Required properties: -- compatible: Compatible property value should be "img,tz1090-pdc-gpio". - -- reg: Physical base address of the controller and length of memory mapped - region. This starts at and cover the SOC_GPIO_CONTROL registers. - -- gpio-controller: Specifies that the node is a gpio controller. - -- #gpio-cells: Should be 2. The syntax of the gpio specifier used by client - nodes should have the following values. - <[phandle of the gpio controller node] - [PDC gpio number] - [gpio flags]> - - Values for gpio specifier: - - GPIO number: a value in the range 0 to 6. - - GPIO flags: bit field of flags, as defined in . - Only the following flags are supported: - GPIO_ACTIVE_HIGH - GPIO_ACTIVE_LOW - -Optional properties: -- gpio-ranges: Mapping to pin controller pins (as described in - Documentation/devicetree/bindings/gpio/gpio.txt) - -- interrupts: Individual syswake interrupts (other GPIOs cannot interrupt) - - -Example: - - pdc_gpios: gpio-controller@2006500 { - gpio-controller; - #gpio-cells = <2>; - - compatible = "img,tz1090-pdc-gpio"; - reg = <0x02006500 0x100>; - - interrupt-parent = <&pdc>; - interrupts = <8 IRQ_TYPE_NONE>, /* Syswake 0 */ - <9 IRQ_TYPE_NONE>, /* Syswake 1 */ - <10 IRQ_TYPE_NONE>; /* Syswake 2 */ - gpio-ranges = <&pdc_pinctrl 0 0 7>; - }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-tz1090.txt b/Documentation/devicetree/bindings/gpio/gpio-tz1090.txt deleted file mode 100644 index b05a90e0ab29..000000000000 --- a/Documentation/devicetree/bindings/gpio/gpio-tz1090.txt +++ /dev/null @@ -1,88 +0,0 @@ -ImgTec TZ1090 GPIO Controller - -Required properties: -- compatible: Compatible property value should be "img,tz1090-gpio". - -- reg: Physical base address of the controller and length of memory mapped - region. - -- #address-cells: Should be 1 (for bank subnodes) - -- #size-cells: Should be 0 (for bank subnodes) - -- Each bank of GPIOs should have a subnode to represent it. - - Bank subnode required properties: - - reg: Index of bank in the range 0 to 2. - - - gpio-controller: Specifies that the node is a gpio controller. - - - #gpio-cells: Should be 2. The syntax of the gpio specifier used by client - nodes should have the following values. - <[phandle of the gpio controller node] - [gpio number within the gpio bank] - [gpio flags]> - - Values for gpio specifier: - - GPIO number: a value in the range 0 to 29. - - GPIO flags: bit field of flags, as defined in . - Only the following flags are supported: - GPIO_ACTIVE_HIGH - GPIO_ACTIVE_LOW - - Bank subnode optional properties: - - gpio-ranges: Mapping to pin controller pins (as described in - Documentation/devicetree/bindings/gpio/gpio.txt) - - - interrupts: Interrupt for the entire bank - - - interrupt-controller: Specifies that the node is an interrupt controller - - - #interrupt-cells: Should be 2. The syntax of the interrupt specifier used by - client nodes should have the following values. - <[phandle of the interurupt controller] - [gpio number within the gpio bank] - [irq flags]> - - Values for irq specifier: - - GPIO number: a value in the range 0 to 29 - - IRQ flags: value to describe edge and level triggering, as defined in - . Only the following flags are - supported: - IRQ_TYPE_EDGE_RISING - IRQ_TYPE_EDGE_FALLING - IRQ_TYPE_EDGE_BOTH - IRQ_TYPE_LEVEL_HIGH - IRQ_TYPE_LEVEL_LOW - - - -Example: - - gpios: gpio-controller@2005800 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "img,tz1090-gpio"; - reg = <0x02005800 0x90>; - - /* bank 0 with an interrupt */ - gpios0: bank@0 { - #gpio-cells = <2>; - #interrupt-cells = <2>; - reg = <0>; - interrupts = <13 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - gpio-ranges = <&pinctrl 0 0 30>; - interrupt-controller; - }; - - /* bank 2 without interrupt */ - gpios2: bank@2 { - #gpio-cells = <2>; - reg = <2>; - gpio-controller; - gpio-ranges = <&pinctrl 0 60 30>; - }; - }; - - diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6d481ef03623..2ecd2adbaec6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -480,21 +480,6 @@ config GPIO_THUNDERX Say yes here to support the on-chip GPIO lines on the ThunderX and OCTEON-TX families of SoCs. -config GPIO_TZ1090 - bool "Toumaz Xenif TZ1090 GPIO support" - depends on SOC_TZ1090 - select GENERIC_IRQ_CHIP - default y - help - Say yes here to support Toumaz Xenif TZ1090 GPIOs. - -config GPIO_TZ1090_PDC - bool "Toumaz Xenif TZ1090 PDC GPIO support" - depends on SOC_TZ1090 - default y - help - Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs. - config GPIO_UNIPHIER tristate "UniPhier GPIO support" depends on ARCH_UNIPHIER || COMPILE_TEST diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 77f88bc086c4..3ad5e3cb628b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -133,8 +133,6 @@ obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o -obj-$(CONFIG_GPIO_TZ1090) += gpio-tz1090.o -obj-$(CONFIG_GPIO_TZ1090_PDC) += gpio-tz1090-pdc.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c deleted file mode 100644 index 5b7781741ee9..000000000000 --- a/drivers/gpio/gpio-tz1090-pdc.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Toumaz Xenif TZ1090 PDC GPIO handling. - * - * Copyright (C) 2012-2013 Imagination Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Register offsets from SOC_GPIO_CONTROL0 */ -#define REG_SOC_GPIO_CONTROL0 0x00 -#define REG_SOC_GPIO_CONTROL1 0x04 -#define REG_SOC_GPIO_CONTROL2 0x08 -#define REG_SOC_GPIO_CONTROL3 0x0c -#define REG_SOC_GPIO_STATUS 0x80 - -/* PDC GPIOs go after normal GPIOs */ -#define GPIO_PDC_BASE 90 -#define GPIO_PDC_NGPIO 7 - -/* Out of PDC gpios, only syswakes have irqs */ -#define GPIO_PDC_IRQ_FIRST 2 -#define GPIO_PDC_NIRQ 3 - -/** - * struct tz1090_pdc_gpio - GPIO bank private data - * @chip: Generic GPIO chip for GPIO bank - * @reg: Base of registers, offset for this GPIO bank - * @irq: IRQ numbers for Syswake GPIOs - * - * This is the main private data for the PDC GPIO driver. It encapsulates a - * gpio_chip, and the callbacks for the gpio_chip can access the private data - * with the to_pdc() macro below. - */ -struct tz1090_pdc_gpio { - struct gpio_chip chip; - void __iomem *reg; - int irq[GPIO_PDC_NIRQ]; -}; - -/* Register accesses into the PDC MMIO area */ - -static inline void pdc_write(struct tz1090_pdc_gpio *priv, unsigned int reg_offs, - unsigned int data) -{ - writel(data, priv->reg + reg_offs); -} - -static inline unsigned int pdc_read(struct tz1090_pdc_gpio *priv, - unsigned int reg_offs) -{ - return readl(priv->reg + reg_offs); -} - -/* Generic GPIO interface */ - -static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip, - unsigned int offset) -{ - struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip); - u32 value; - int lstat; - - __global_lock2(lstat); - value = pdc_read(priv, REG_SOC_GPIO_CONTROL1); - value |= BIT(offset); - pdc_write(priv, REG_SOC_GPIO_CONTROL1, value); - __global_unlock2(lstat); - - return 0; -} - -static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, - int output_value) -{ - struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip); - u32 value; - int lstat; - - __global_lock2(lstat); - /* EXT_POWER doesn't seem to have an output value bit */ - if (offset < 6) { - value = pdc_read(priv, REG_SOC_GPIO_CONTROL0); - if (output_value) - value |= BIT(offset); - else - value &= ~BIT(offset); - pdc_write(priv, REG_SOC_GPIO_CONTROL0, value); - } - - value = pdc_read(priv, REG_SOC_GPIO_CONTROL1); - value &= ~BIT(offset); - pdc_write(priv, REG_SOC_GPIO_CONTROL1, value); - __global_unlock2(lstat); - - return 0; -} - -static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip); - return !!(pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset)); -} - -static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset, - int output_value) -{ - struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip); - u32 value; - int lstat; - - /* EXT_POWER doesn't seem to have an output value bit */ - if (offset >= 6) - return; - - __global_lock2(lstat); - value = pdc_read(priv, REG_SOC_GPIO_CONTROL0); - if (output_value) - value |= BIT(offset); - else - value &= ~BIT(offset); - pdc_write(priv, REG_SOC_GPIO_CONTROL0, value); - __global_unlock2(lstat); -} - -static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip); - unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST; - int irq; - - /* only syswakes have irqs */ - if (syswake >= GPIO_PDC_NIRQ) - return -EINVAL; - - irq = priv->irq[syswake]; - if (!irq) - return -EINVAL; - - return irq; -} - -static int tz1090_pdc_gpio_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct resource *res_regs; - struct tz1090_pdc_gpio *priv; - unsigned int i; - - if (!np) { - dev_err(&pdev->dev, "must be instantiated via devicetree\n"); - return -ENOENT; - } - - res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res_regs) { - dev_err(&pdev->dev, "cannot find registers resource\n"); - return -ENOENT; - } - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "unable to allocate driver data\n"); - return -ENOMEM; - } - - /* Ioremap the registers */ - priv->reg = devm_ioremap(&pdev->dev, res_regs->start, - resource_size(res_regs)); - if (!priv->reg) { - dev_err(&pdev->dev, "unable to ioremap registers\n"); - return -ENOMEM; - } - - /* Set up GPIO chip */ - priv->chip.label = "tz1090-pdc-gpio"; - priv->chip.parent = &pdev->dev; - priv->chip.direction_input = tz1090_pdc_gpio_direction_input; - priv->chip.direction_output = tz1090_pdc_gpio_direction_output; - priv->chip.get = tz1090_pdc_gpio_get; - priv->chip.set = tz1090_pdc_gpio_set; - priv->chip.free = gpiochip_generic_free; - priv->chip.request = gpiochip_generic_request; - priv->chip.to_irq = tz1090_pdc_gpio_to_irq; - priv->chip.of_node = np; - - /* GPIO numbering */ - priv->chip.base = GPIO_PDC_BASE; - priv->chip.ngpio = GPIO_PDC_NGPIO; - - /* Map the syswake irqs */ - for (i = 0; i < GPIO_PDC_NIRQ; ++i) - priv->irq[i] = irq_of_parse_and_map(np, i); - - /* Add the GPIO bank */ - gpiochip_add_data(&priv->chip, priv); - - return 0; -} - -static struct of_device_id tz1090_pdc_gpio_of_match[] = { - { .compatible = "img,tz1090-pdc-gpio" }, - { }, -}; - -static struct platform_driver tz1090_pdc_gpio_driver = { - .driver = { - .name = "tz1090-pdc-gpio", - .of_match_table = tz1090_pdc_gpio_of_match, - }, - .probe = tz1090_pdc_gpio_probe, -}; - -static int __init tz1090_pdc_gpio_init(void) -{ - return platform_driver_register(&tz1090_pdc_gpio_driver); -} -subsys_initcall(tz1090_pdc_gpio_init); diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c deleted file mode 100644 index 0bb9bb583889..000000000000 --- a/drivers/gpio/gpio-tz1090.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Toumaz Xenif TZ1090 GPIO handling. - * - * Copyright (C) 2008-2013 Imagination Technologies Ltd. - * - * Based on ARM PXA code and others. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Register offsets from bank base address */ -#define REG_GPIO_DIR 0x00 -#define REG_GPIO_IRQ_PLRT 0x20 -#define REG_GPIO_IRQ_TYPE 0x30 -#define REG_GPIO_IRQ_EN 0x40 -#define REG_GPIO_IRQ_STS 0x50 -#define REG_GPIO_BIT_EN 0x60 -#define REG_GPIO_DIN 0x70 -#define REG_GPIO_DOUT 0x80 - -/* REG_GPIO_IRQ_PLRT */ -#define REG_GPIO_IRQ_PLRT_LOW 0 -#define REG_GPIO_IRQ_PLRT_HIGH 1 - -/* REG_GPIO_IRQ_TYPE */ -#define REG_GPIO_IRQ_TYPE_LEVEL 0 -#define REG_GPIO_IRQ_TYPE_EDGE 1 - -/** - * struct tz1090_gpio_bank - GPIO bank private data - * @chip: Generic GPIO chip for GPIO bank - * @domain: IRQ domain for GPIO bank (may be NULL) - * @reg: Base of registers, offset for this GPIO bank - * @irq: IRQ number for GPIO bank - * @label: Debug GPIO bank label, used for storage of chip->label - * - * This is the main private data for a GPIO bank. It encapsulates a gpio_chip, - * and the callbacks for the gpio_chip can access the private data with the - * to_bank() macro below. - */ -struct tz1090_gpio_bank { - struct gpio_chip chip; - struct irq_domain *domain; - void __iomem *reg; - int irq; - char label[16]; -}; - -/** - * struct tz1090_gpio - Overall GPIO device private data - * @dev: Device (from platform device) - * @reg: Base of GPIO registers - * - * Represents the overall GPIO device. This structure is actually only - * temporary, and used during init. - */ -struct tz1090_gpio { - struct device *dev; - void __iomem *reg; -}; - -/** - * struct tz1090_gpio_bank_info - Temporary registration info for GPIO bank - * @priv: Overall GPIO device private data - * @node: Device tree node specific to this GPIO bank - * @index: Index of bank in range 0-2 - */ -struct tz1090_gpio_bank_info { - struct tz1090_gpio *priv; - struct device_node *node; - unsigned int index; -}; - -/* Convenience register accessors */ -static inline void tz1090_gpio_write(struct tz1090_gpio_bank *bank, - unsigned int reg_offs, u32 data) -{ - iowrite32(data, bank->reg + reg_offs); -} - -static inline u32 tz1090_gpio_read(struct tz1090_gpio_bank *bank, - unsigned int reg_offs) -{ - return ioread32(bank->reg + reg_offs); -} - -/* caller must hold LOCK2 */ -static inline void _tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank, - unsigned int reg_offs, - unsigned int offset) -{ - u32 value; - - value = tz1090_gpio_read(bank, reg_offs); - value &= ~BIT(offset); - tz1090_gpio_write(bank, reg_offs, value); -} - -static void tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank, - unsigned int reg_offs, - unsigned int offset) -{ - int lstat; - - __global_lock2(lstat); - _tz1090_gpio_clear_bit(bank, reg_offs, offset); - __global_unlock2(lstat); -} - -/* caller must hold LOCK2 */ -static inline void _tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank, - unsigned int reg_offs, - unsigned int offset) -{ - u32 value; - - value = tz1090_gpio_read(bank, reg_offs); - value |= BIT(offset); - tz1090_gpio_write(bank, reg_offs, value); -} - -static void tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank, - unsigned int reg_offs, - unsigned int offset) -{ - int lstat; - - __global_lock2(lstat); - _tz1090_gpio_set_bit(bank, reg_offs, offset); - __global_unlock2(lstat); -} - -/* caller must hold LOCK2 */ -static inline void _tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank, - unsigned int reg_offs, - unsigned int offset, - bool val) -{ - u32 value; - - value = tz1090_gpio_read(bank, reg_offs); - value &= ~BIT(offset); - if (val) - value |= BIT(offset); - tz1090_gpio_write(bank, reg_offs, value); -} - -static void tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank, - unsigned int reg_offs, - unsigned int offset, - bool val) -{ - int lstat; - - __global_lock2(lstat); - _tz1090_gpio_mod_bit(bank, reg_offs, offset, val); - __global_unlock2(lstat); -} - -static inline int tz1090_gpio_read_bit(struct tz1090_gpio_bank *bank, - unsigned int reg_offs, - unsigned int offset) -{ - return tz1090_gpio_read(bank, reg_offs) & BIT(offset); -} - -/* GPIO chip callbacks */ - -static int tz1090_gpio_direction_input(struct gpio_chip *chip, - unsigned int offset) -{ - struct tz1090_gpio_bank *bank = gpiochip_get_data(chip); - tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset); - - return 0; -} - -static int tz1090_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int output_value) -{ - struct tz1090_gpio_bank *bank = gpiochip_get_data(chip); - int lstat; - - __global_lock2(lstat); - _tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value); - _tz1090_gpio_clear_bit(bank, REG_GPIO_DIR, offset); - __global_unlock2(lstat); - - return 0; -} - -/* - * Return GPIO level - */ -static int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct tz1090_gpio_bank *bank = gpiochip_get_data(chip); - - return !!tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset); -} - -/* - * Set output GPIO level - */ -static void tz1090_gpio_set(struct gpio_chip *chip, unsigned int offset, - int output_value) -{ - struct tz1090_gpio_bank *bank = gpiochip_get_data(chip); - - tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value); -} - -static int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset) -{ - struct tz1090_gpio_bank *bank = gpiochip_get_data(chip); - int ret; - - ret = pinctrl_gpio_request(chip->base + offset); - if (ret) - return ret; - - tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset); - tz1090_gpio_set_bit(bank, REG_GPIO_BIT_EN, offset); - - return 0; -} - -static void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset) -{ - struct tz1090_gpio_bank *bank = gpiochip_get_data(chip); - - pinctrl_gpio_free(chip->base + offset); - - tz1090_gpio_clear_bit(bank, REG_GPIO_BIT_EN, offset); -} - -static int tz1090_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - struct tz1090_gpio_bank *bank = gpiochip_get_data(chip); - - if (!bank->domain) - return -EINVAL; - - return irq_create_mapping(bank->domain, offset); -} - -/* IRQ chip handlers */ - -/* Get TZ1090 GPIO chip from irq data provided to generic IRQ callbacks */ -static inline struct tz1090_gpio_bank *irqd_to_gpio_bank(struct irq_data *data) -{ - return (struct tz1090_gpio_bank *)data->domain->host_data; -} - -static void tz1090_gpio_irq_polarity(struct tz1090_gpio_bank *bank, - unsigned int offset, unsigned int polarity) -{ - tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_PLRT, offset, polarity); -} - -static void tz1090_gpio_irq_type(struct tz1090_gpio_bank *bank, - unsigned int offset, unsigned int type) -{ - tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_TYPE, offset, type); -} - -/* set polarity to trigger on next edge, whether rising or falling */ -static void tz1090_gpio_irq_next_edge(struct tz1090_gpio_bank *bank, - unsigned int offset) -{ - unsigned int value_p, value_i; - int lstat; - - /* - * Set the GPIO's interrupt polarity to the opposite of the current - * input value so that the next edge triggers an interrupt. - */ - __global_lock2(lstat); - value_i = ~tz1090_gpio_read(bank, REG_GPIO_DIN); - value_p = tz1090_gpio_read(bank, REG_GPIO_IRQ_PLRT); - value_p &= ~BIT(offset); - value_p |= value_i & BIT(offset); - tz1090_gpio_write(bank, REG_GPIO_IRQ_PLRT, value_p); - __global_unlock2(lstat); -} - -static unsigned int gpio_startup_irq(struct irq_data *data) -{ - /* - * This warning indicates that the type of the irq hasn't been set - * before enabling the irq. This would normally be done by passing some - * trigger flags to request_irq(). - */ - WARN(irqd_get_trigger_type(data) == IRQ_TYPE_NONE, - "irq type not set before enabling gpio irq %d", data->irq); - - irq_gc_ack_clr_bit(data); - irq_gc_mask_set_bit(data); - return 0; -} - -static int gpio_set_irq_type(struct irq_data *data, unsigned int flow_type) -{ - struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); - unsigned int type; - unsigned int polarity; - - switch (flow_type) { - case IRQ_TYPE_EDGE_BOTH: - type = REG_GPIO_IRQ_TYPE_EDGE; - polarity = REG_GPIO_IRQ_PLRT_LOW; - break; - case IRQ_TYPE_EDGE_RISING: - type = REG_GPIO_IRQ_TYPE_EDGE; - polarity = REG_GPIO_IRQ_PLRT_HIGH; - break; - case IRQ_TYPE_EDGE_FALLING: - type = REG_GPIO_IRQ_TYPE_EDGE; - polarity = REG_GPIO_IRQ_PLRT_LOW; - break; - case IRQ_TYPE_LEVEL_HIGH: - type = REG_GPIO_IRQ_TYPE_LEVEL; - polarity = REG_GPIO_IRQ_PLRT_HIGH; - break; - case IRQ_TYPE_LEVEL_LOW: - type = REG_GPIO_IRQ_TYPE_LEVEL; - polarity = REG_GPIO_IRQ_PLRT_LOW; - break; - default: - return -EINVAL; - } - - tz1090_gpio_irq_type(bank, data->hwirq, type); - irq_setup_alt_chip(data, flow_type); - - if (flow_type == IRQ_TYPE_EDGE_BOTH) - tz1090_gpio_irq_next_edge(bank, data->hwirq); - else - tz1090_gpio_irq_polarity(bank, data->hwirq, polarity); - - return 0; -} - -#ifdef CONFIG_SUSPEND -static int gpio_set_irq_wake(struct irq_data *data, unsigned int on) -{ - struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data); - -#ifdef CONFIG_PM_DEBUG - pr_info("irq_wake irq%d state:%d\n", data->irq, on); -#endif - - /* wake on gpio block interrupt */ - return irq_set_irq_wake(bank->irq, on); -} -#else -#define gpio_set_irq_wake NULL -#endif - -static void tz1090_gpio_irq_handler(struct irq_desc *desc) -{ - irq_hw_number_t hw; - unsigned int irq_stat, irq_no; - struct tz1090_gpio_bank *bank; - struct irq_desc *child_desc; - - bank = (struct tz1090_gpio_bank *)irq_desc_get_handler_data(desc); - irq_stat = tz1090_gpio_read(bank, REG_GPIO_DIR) & - tz1090_gpio_read(bank, REG_GPIO_IRQ_STS) & - tz1090_gpio_read(bank, REG_GPIO_IRQ_EN) & - 0x3FFFFFFF; /* 30 bits only */ - - for (hw = 0; irq_stat; irq_stat >>= 1, ++hw) { - if (!(irq_stat & 1)) - continue; - - irq_no = irq_linear_revmap(bank->domain, hw); - child_desc = irq_to_desc(irq_no); - - /* Toggle edge for pin with both edges triggering enabled */ - if (irqd_get_trigger_type(&child_desc->irq_data) - == IRQ_TYPE_EDGE_BOTH) - tz1090_gpio_irq_next_edge(bank, hw); - - generic_handle_irq_desc(child_desc); - } -} - -static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) -{ - struct device_node *np = info->node; - struct device *dev = info->priv->dev; - struct tz1090_gpio_bank *bank; - struct irq_chip_generic *gc; - int err; - - bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); - if (!bank) { - dev_err(dev, "unable to allocate driver data\n"); - return -ENOMEM; - } - - /* Offset the main registers to the first register in this bank */ - bank->reg = info->priv->reg + info->index * 4; - - /* Set up GPIO chip */ - snprintf(bank->label, sizeof(bank->label), "tz1090-gpio-%u", - info->index); - bank->chip.label = bank->label; - bank->chip.parent = dev; - bank->chip.direction_input = tz1090_gpio_direction_input; - bank->chip.direction_output = tz1090_gpio_direction_output; - bank->chip.get = tz1090_gpio_get; - bank->chip.set = tz1090_gpio_set; - bank->chip.free = tz1090_gpio_free; - bank->chip.request = tz1090_gpio_request; - bank->chip.to_irq = tz1090_gpio_to_irq; - bank->chip.of_node = np; - - /* GPIO numbering from 0 */ - bank->chip.base = info->index * 30; - bank->chip.ngpio = 30; - - /* Add the GPIO bank */ - gpiochip_add_data(&bank->chip, bank); - - /* Get the GPIO bank IRQ if provided */ - bank->irq = irq_of_parse_and_map(np, 0); - - /* The interrupt is optional (it may be used by another core on chip) */ - if (!bank->irq) { - dev_info(dev, "IRQ not provided for bank %u, IRQs disabled\n", - info->index); - return 0; - } - - dev_info(dev, "Setting up IRQs for GPIO bank %u\n", - info->index); - - /* - * Initialise all interrupts to disabled so we don't get - * spurious ones on a dirty boot and hit the BUG_ON in the - * handler. - */ - tz1090_gpio_write(bank, REG_GPIO_IRQ_EN, 0); - - /* Add a virtual IRQ for each GPIO */ - bank->domain = irq_domain_add_linear(np, - bank->chip.ngpio, - &irq_generic_chip_ops, - bank); - - /* Set up a generic irq chip with 2 chip types (level and edge) */ - err = irq_alloc_domain_generic_chips(bank->domain, bank->chip.ngpio, 2, - bank->label, handle_bad_irq, 0, 0, - IRQ_GC_INIT_NESTED_LOCK); - if (err) { - dev_info(dev, - "irq_alloc_domain_generic_chips failed for bank %u, IRQs disabled\n", - info->index); - irq_domain_remove(bank->domain); - return 0; - } - - gc = irq_get_domain_generic_chip(bank->domain, 0); - gc->reg_base = bank->reg; - - /* level chip type */ - gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK; - gc->chip_types[0].handler = handle_level_irq; - gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS; - gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[0].chip.irq_startup = gpio_startup_irq; - gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit; - gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; - gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; - gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type; - gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake; - gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND; - - /* edge chip type */ - gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; - gc->chip_types[1].handler = handle_edge_irq; - gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS; - gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[1].chip.irq_startup = gpio_startup_irq; - gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit; - gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit; - gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit; - gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type; - gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake; - gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND; - - /* Setup chained handler for this GPIO bank */ - irq_set_chained_handler_and_data(bank->irq, tz1090_gpio_irq_handler, - bank); - - return 0; -} - -static void tz1090_gpio_register_banks(struct tz1090_gpio *priv) -{ - struct device_node *np = priv->dev->of_node; - struct device_node *node; - - for_each_available_child_of_node(np, node) { - struct tz1090_gpio_bank_info info; - u32 addr; - int ret; - - ret = of_property_read_u32(node, "reg", &addr); - if (ret) { - dev_err(priv->dev, "invalid reg on %pOF\n", node); - continue; - } - if (addr >= 3) { - dev_err(priv->dev, "index %u in %pOF out of range\n", - addr, node); - continue; - } - - info.index = addr; - info.node = of_node_get(node); - info.priv = priv; - - ret = tz1090_gpio_bank_probe(&info); - if (ret) { - dev_err(priv->dev, "failure registering %pOF\n", node); - of_node_put(node); - continue; - } - } -} - -static int tz1090_gpio_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct resource *res_regs; - struct tz1090_gpio priv; - - if (!np) { - dev_err(&pdev->dev, "must be instantiated via devicetree\n"); - return -ENOENT; - } - - res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res_regs) { - dev_err(&pdev->dev, "cannot find registers resource\n"); - return -ENOENT; - } - - priv.dev = &pdev->dev; - - /* Ioremap the registers */ - priv.reg = devm_ioremap(&pdev->dev, res_regs->start, - resource_size(res_regs)); - if (!priv.reg) { - dev_err(&pdev->dev, "unable to ioremap registers\n"); - return -ENOMEM; - } - - /* Look for banks */ - tz1090_gpio_register_banks(&priv); - - return 0; -} - -static struct of_device_id tz1090_gpio_of_match[] = { - { .compatible = "img,tz1090-gpio" }, - { }, -}; - -static struct platform_driver tz1090_gpio_driver = { - .driver = { - .name = "tz1090-gpio", - .of_match_table = tz1090_gpio_of_match, - }, - .probe = tz1090_gpio_probe, -}; - -static int __init tz1090_gpio_init(void) -{ - return platform_driver_register(&tz1090_gpio_driver); -} -subsys_initcall(tz1090_gpio_init); -- cgit v1.2.3 From 9d5a1f2ca6618bffd79c834d3e090a086fe35e6a Mon Sep 17 00:00:00 2001 From: Wang Dongsheng Date: Tue, 27 Feb 2018 00:12:13 -0800 Subject: gpiolib: friendly debug information for consumer "failed" maybe makes observer confuse when a consumer can not lookup, so change to a friendly information. Signed-off-by: Wang Dongsheng Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d66de67ef307..f220d844b607 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3689,7 +3689,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, } if (IS_ERR(desc)) { - dev_dbg(dev, "lookup for GPIO %s failed\n", con_id); + dev_dbg(dev, "No GPIO consumer %s found\n", con_id); return desc; } -- cgit v1.2.3 From 7ed915059c3001ddebfc2aa993cc172d10123806 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 28 Feb 2018 14:48:08 +0100 Subject: gpio: raspberrypi-ext: fix firmware dependency When the firmware driver is a loadable module, the gpio driver cannot be built-in: drivers/gpio/gpio-raspberrypi-exp.o: In function `rpi_exp_gpio_set': gpio-raspberrypi-exp.c:(.text+0xb4): undefined reference to `rpi_firmware_property' drivers/gpio/gpio-raspberrypi-exp.o: In function `rpi_exp_gpio_get': gpio-raspberrypi-exp.c:(.text+0x1ec): undefined reference to `rpi_firmware_property' drivers/gpio/gpio-raspberrypi-exp.o: In function `rpi_exp_gpio_get_direction': gpio-raspberrypi-exp.c:(.text+0x360): undefined reference to `rpi_firmware_property' drivers/gpio/gpio-raspberrypi-exp.o: In function `rpi_exp_gpio_get_polarity': gpio-raspberrypi-exp.c:(.text+0x4d4): undefined reference to `rpi_firmware_property' drivers/gpio/gpio-raspberrypi-exp.o: In function `rpi_exp_gpio_dir_out': gpio-raspberrypi-exp.c:(.text+0x670): undefined reference to `rpi_firmware_property' drivers/gpio/gpio-raspberrypi-exp.o:gpio-raspberrypi-exp.c:(.text+0x7fc): more undefined references to `rpi_firmware_property' follow drivers/gpio/gpio-raspberrypi-exp.o: In function `rpi_exp_gpio_dir_in': drivers/gpio/gpio-raspberrypi-exp.o: In function `rpi_exp_gpio_probe': gpio-raspberrypi-exp.c:(.text+0x93c): undefined reference to `rpi_firmware_get' We already have a Kconfig dependency for it, but when compile-testing, it is disregarded. This changes the dependency so that compile-testing is only done when the firmware driver is completely disabled. Fixes: a98d90e7d588 ("gpio: raspberrypi-exp: Driver for RPi3 GPIO expander via mailbox service") Signed-off-by: Arnd Bergmann Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2ecd2adbaec6..52a8b0a6f4e1 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -126,7 +126,7 @@ config GPIO_RASPBERRYPI_EXP tristate "Raspberry Pi 3 GPIO Expander" default RASPBERRYPI_FIRMWARE depends on OF_GPIO - depends on (ARCH_BCM2835 && RASPBERRYPI_FIRMWARE) || COMPILE_TEST + depends on (ARCH_BCM2835 && RASPBERRYPI_FIRMWARE) || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) help Turn on GPIO support for the expander on Raspberry Pi 3 boards, using the firmware mailbox to communicate with VideoCore on BCM283x chips. -- cgit v1.2.3 From 9a3821c2bb47d2582b0c8f053d4c3bed7bd8d3d1 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Sat, 24 Feb 2018 10:07:18 +0800 Subject: gpio: Add GPIO driver for Spreadtrum SC9860 platform The Spreadtrum SC9860 platform GPIO controller contains 16 groups and each group contains 16 GPIOs. Each GPIO can set input/output and has the interrupt capability. Signed-off-by: Baolin Wang Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-sprd.c | 290 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 299 insertions(+) create mode 100644 drivers/gpio/gpio-sprd.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 52a8b0a6f4e1..f298a18b1f69 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -416,6 +416,14 @@ config GPIO_SPEAR_SPICS help Say yes here to support ST SPEAr SPI Chip Select as GPIO device +config GPIO_SPRD + tristate "Spreadtrum GPIO support" + depends on ARCH_SPRD || COMPILE_TEST + depends on OF_GPIO + select GPIOLIB_IRQCHIP + help + Say yes here to support Spreadtrum GPIO device. + config GPIO_STA2X11 bool "STA2x11/ConneXt GPIO support" depends on MFD_STA2X11 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 3ad5e3cb628b..5c1f087c65aa 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -110,6 +110,7 @@ obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o +obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o diff --git a/drivers/gpio/gpio-sprd.c b/drivers/gpio/gpio-sprd.c new file mode 100644 index 000000000000..55072d2b367f --- /dev/null +++ b/drivers/gpio/gpio-sprd.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Spreadtrum Communications Inc. + * Copyright (C) 2018 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* GPIO registers definition */ +#define SPRD_GPIO_DATA 0x0 +#define SPRD_GPIO_DMSK 0x4 +#define SPRD_GPIO_DIR 0x8 +#define SPRD_GPIO_IS 0xc +#define SPRD_GPIO_IBE 0x10 +#define SPRD_GPIO_IEV 0x14 +#define SPRD_GPIO_IE 0x18 +#define SPRD_GPIO_RIS 0x1c +#define SPRD_GPIO_MIS 0x20 +#define SPRD_GPIO_IC 0x24 +#define SPRD_GPIO_INEN 0x28 + +/* We have 16 banks GPIOs and each bank contain 16 GPIOs */ +#define SPRD_GPIO_BANK_NR 16 +#define SPRD_GPIO_NR 256 +#define SPRD_GPIO_BANK_SIZE 0x80 +#define SPRD_GPIO_BANK_MASK GENMASK(15, 0) +#define SPRD_GPIO_BIT(x) ((x) & (SPRD_GPIO_BANK_NR - 1)) + +struct sprd_gpio { + struct gpio_chip chip; + void __iomem *base; + spinlock_t lock; + int irq; +}; + +static inline void __iomem *sprd_gpio_bank_base(struct sprd_gpio *sprd_gpio, + unsigned int bank) +{ + return sprd_gpio->base + SPRD_GPIO_BANK_SIZE * bank; +} + +static void sprd_gpio_update(struct gpio_chip *chip, unsigned int offset, + u16 reg, int val) +{ + struct sprd_gpio *sprd_gpio = gpiochip_get_data(chip); + void __iomem *base = sprd_gpio_bank_base(sprd_gpio, + offset / SPRD_GPIO_BANK_NR); + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&sprd_gpio->lock, flags); + tmp = readl_relaxed(base + reg); + + if (val) + tmp |= BIT(SPRD_GPIO_BIT(offset)); + else + tmp &= ~BIT(SPRD_GPIO_BIT(offset)); + + writel_relaxed(tmp, base + reg); + spin_unlock_irqrestore(&sprd_gpio->lock, flags); +} + +static int sprd_gpio_read(struct gpio_chip *chip, unsigned int offset, u16 reg) +{ + struct sprd_gpio *sprd_gpio = gpiochip_get_data(chip); + void __iomem *base = sprd_gpio_bank_base(sprd_gpio, + offset / SPRD_GPIO_BANK_NR); + + return !!(readl_relaxed(base + reg) & BIT(SPRD_GPIO_BIT(offset))); +} + +static int sprd_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + sprd_gpio_update(chip, offset, SPRD_GPIO_DMSK, 1); + return 0; +} + +static void sprd_gpio_free(struct gpio_chip *chip, unsigned int offset) +{ + sprd_gpio_update(chip, offset, SPRD_GPIO_DMSK, 0); +} + +static int sprd_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + sprd_gpio_update(chip, offset, SPRD_GPIO_DIR, 0); + sprd_gpio_update(chip, offset, SPRD_GPIO_INEN, 1); + return 0; +} + +static int sprd_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + sprd_gpio_update(chip, offset, SPRD_GPIO_DIR, 1); + sprd_gpio_update(chip, offset, SPRD_GPIO_INEN, 0); + sprd_gpio_update(chip, offset, SPRD_GPIO_DATA, value); + return 0; +} + +static int sprd_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + return sprd_gpio_read(chip, offset, SPRD_GPIO_DATA); +} + +static void sprd_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + sprd_gpio_update(chip, offset, SPRD_GPIO_DATA, value); +} + +static void sprd_gpio_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + + sprd_gpio_update(chip, offset, SPRD_GPIO_IE, 0); +} + +static void sprd_gpio_irq_ack(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + + sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1); +} + +static void sprd_gpio_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + + sprd_gpio_update(chip, offset, SPRD_GPIO_IE, 1); +} + +static int sprd_gpio_irq_set_type(struct irq_data *data, + unsigned int flow_type) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + u32 offset = irqd_to_hwirq(data); + + switch (flow_type) { + case IRQ_TYPE_EDGE_RISING: + sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0); + sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0); + sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_FALLING: + sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0); + sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0); + sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 0); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_BOTH: + sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0); + sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_HIGH: + sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 1); + sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0); + sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 1); + irq_set_handler_locked(data, handle_level_irq); + break; + case IRQ_TYPE_LEVEL_LOW: + sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 1); + sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0); + sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 0); + irq_set_handler_locked(data, handle_level_irq); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void sprd_gpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct irq_chip *ic = irq_desc_get_chip(desc); + struct sprd_gpio *sprd_gpio = gpiochip_get_data(chip); + u32 bank, n, girq; + + chained_irq_enter(ic, desc); + + for (bank = 0; bank * SPRD_GPIO_BANK_NR < chip->ngpio; bank++) { + void __iomem *base = sprd_gpio_bank_base(sprd_gpio, bank); + unsigned long reg = readl_relaxed(base + SPRD_GPIO_MIS) & + SPRD_GPIO_BANK_MASK; + + for_each_set_bit(n, ®, SPRD_GPIO_BANK_NR) { + girq = irq_find_mapping(chip->irq.domain, + bank * SPRD_GPIO_BANK_NR + n); + + generic_handle_irq(girq); + } + + } + chained_irq_exit(ic, desc); +} + +static struct irq_chip sprd_gpio_irqchip = { + .name = "sprd-gpio", + .irq_ack = sprd_gpio_irq_ack, + .irq_mask = sprd_gpio_irq_mask, + .irq_unmask = sprd_gpio_irq_unmask, + .irq_set_type = sprd_gpio_irq_set_type, + .flags = IRQCHIP_SKIP_SET_WAKE, +}; + +static int sprd_gpio_probe(struct platform_device *pdev) +{ + struct gpio_irq_chip *irq; + struct sprd_gpio *sprd_gpio; + struct resource *res; + int ret; + + sprd_gpio = devm_kzalloc(&pdev->dev, sizeof(*sprd_gpio), GFP_KERNEL); + if (!sprd_gpio) + return -ENOMEM; + + sprd_gpio->irq = platform_get_irq(pdev, 0); + if (sprd_gpio->irq < 0) { + dev_err(&pdev->dev, "Failed to get GPIO interrupt.\n"); + return sprd_gpio->irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sprd_gpio->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(sprd_gpio->base)) + return PTR_ERR(sprd_gpio->base); + + spin_lock_init(&sprd_gpio->lock); + + sprd_gpio->chip.label = dev_name(&pdev->dev); + sprd_gpio->chip.ngpio = SPRD_GPIO_NR; + sprd_gpio->chip.base = -1; + sprd_gpio->chip.parent = &pdev->dev; + sprd_gpio->chip.of_node = pdev->dev.of_node; + sprd_gpio->chip.request = sprd_gpio_request; + sprd_gpio->chip.free = sprd_gpio_free; + sprd_gpio->chip.get = sprd_gpio_get; + sprd_gpio->chip.set = sprd_gpio_set; + sprd_gpio->chip.direction_input = sprd_gpio_direction_input; + sprd_gpio->chip.direction_output = sprd_gpio_direction_output; + + irq = &sprd_gpio->chip.irq; + irq->chip = &sprd_gpio_irqchip; + irq->handler = handle_bad_irq; + irq->default_type = IRQ_TYPE_NONE; + irq->parent_handler = sprd_gpio_irq_handler; + irq->parent_handler_data = sprd_gpio; + irq->num_parents = 1; + irq->parents = &sprd_gpio->irq; + + ret = devm_gpiochip_add_data(&pdev->dev, &sprd_gpio->chip, sprd_gpio); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, sprd_gpio); + return 0; +} + +static const struct of_device_id sprd_gpio_of_match[] = { + { .compatible = "sprd,sc9860-gpio", }, + { /* end of list */ } +}; +MODULE_DEVICE_TABLE(of, sprd_gpio_of_match); + +static struct platform_driver sprd_gpio_driver = { + .probe = sprd_gpio_probe, + .driver = { + .name = "sprd-gpio", + .of_match_table = sprd_gpio_of_match, + }, +}; + +module_platform_driver_probe(sprd_gpio_driver, sprd_gpio_probe); + +MODULE_DESCRIPTION("Spreadtrum GPIO driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 94337b72618eacc1756eba4765a15b3748f80fbc Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Fri, 2 Mar 2018 11:47:01 +0200 Subject: gpio: raspberrypi-exp: explain Kconfig dependency Commit 7ed915059c3001 (gpio: raspberrypi-ext: fix firmware dependency) fixed the Kconfig dependency to ensure that gpio-raspberrypi-exp is not built-in when the firmware is a module. But the Kconfig syntax for doing so is cryptic. Add a comment to make it a little easier. Cc: Arnd Bergmann Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f298a18b1f69..6b1ee11295d5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -126,6 +126,8 @@ config GPIO_RASPBERRYPI_EXP tristate "Raspberry Pi 3 GPIO Expander" default RASPBERRYPI_FIRMWARE depends on OF_GPIO + # Make sure not 'y' when RASPBERRYPI_FIRMWARE is 'm'. This can only + # happen when COMPILE_TEST=y, hence the added !RASPBERRYPI_FIRMWARE. depends on (ARCH_BCM2835 && RASPBERRYPI_FIRMWARE) || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) help Turn on GPIO support for the expander on Raspberry Pi 3 boards, using -- cgit v1.2.3 From 4f9a4cd66c1201ce2b26ba895b2be63b8b38bb68 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Mar 2018 09:04:15 +0100 Subject: gpio: mockup: Update Bamvors mail address Bamvor changed his mail so let's updat his mail address everywhere. Cc: Bamvor Jian Zhang Signed-off-by: Linus Walleij --- MAINTAINERS | 2 +- drivers/gpio/gpio-mockup.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 3bdc260e36b7..8aafb7e230da 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6014,7 +6014,7 @@ S: Maintained F: drivers/media/rc/gpio-ir-tx.c GPIO MOCKUP DRIVER -M: Bamvor Jian Zhang +M: Bamvor Jian Zhang R: Bartosz Golaszewski L: linux-gpio@vger.kernel.org S: Maintained diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 3a545ad17817..21422b8e487b 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -2,7 +2,7 @@ * GPIO Testing Device Driver * * Copyright (C) 2014 Kamlakant Patel - * Copyright (C) 2015-2016 Bamvor Jian Zhang + * Copyright (C) 2015-2016 Bamvor Jian Zhang * Copyright (C) 2017 Bartosz Golaszewski * * This program is free software; you can redistribute it and/or modify it @@ -411,7 +411,7 @@ module_init(gpio_mockup_init); module_exit(gpio_mockup_exit); MODULE_AUTHOR("Kamlakant Patel "); -MODULE_AUTHOR("Bamvor Jian Zhang "); +MODULE_AUTHOR("Bamvor Jian Zhang "); MODULE_AUTHOR("Bartosz Golaszewski "); MODULE_DESCRIPTION("GPIO Testing driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 1cb6610aec83a592ca04d92d6a4fadaee5611e44 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 24 Jan 2018 13:55:22 +0100 Subject: gpio: dln2: Include proper header This driver has no business including , it is a driver so include . GPIOF_DIR_IN/GPIOF_DIR_OUT are for consumers and should not be used in drivers to use just 1/0 instead. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dln2.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c index 1dada68b9a27..c4e7953c093e 100644 --- a/drivers/gpio/gpio-dln2.c +++ b/drivers/gpio/gpio-dln2.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -204,9 +203,9 @@ static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset) struct dln2_gpio *dln2 = gpiochip_get_data(chip); if (test_bit(offset, dln2->output_enabled)) - return GPIOF_DIR_OUT; + return 0; - return GPIOF_DIR_IN; + return 1; } static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset) @@ -218,7 +217,7 @@ static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset) if (dir < 0) return dir; - if (dir == GPIOF_DIR_IN) + if (dir == 1) return dln2_gpio_pin_get_in_val(dln2, offset); return dln2_gpio_pin_get_out_val(dln2, offset); -- cgit v1.2.3 From d90f2adee479ac885401ce77ad8493ec7d70fe97 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 9 Feb 2018 00:42:39 +0100 Subject: gpio: ge: Drop of_gpio.h include This driver does not make use of the functions in so drop this include. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ge.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index 6f5a7fe9787d..1fe2d3418f2f 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 7275cb75b96f5cec924ea95685d906d09b6a82f4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 9 Feb 2018 00:45:50 +0100 Subject: gpio: em: Use the right include The Emma Mobile (EM) GPIO driver uses the too generic include . It is a driver so it should just use . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index b86e09e1b13b..2b466b80e70a 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From 7113ea8a8f56e8d33824e215757fae9e38f3b1fb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 4 Mar 2018 22:59:49 +0100 Subject: gpio: ftgpio010: Drop of_gpio.h include This driver does not make use of the functions in so drop this include. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ftgpio010.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index e80634c464a9..868bf8501560 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -14,7 +14,6 @@ #include #include #include -#include #include /* GPIO registers definition */ -- cgit v1.2.3 From 00d712a93037c7569d72cf59dc8fb930250264e8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 4 Mar 2018 23:17:31 +0100 Subject: gpio: grgpio: Include the right header This driver is a pure GPIO driver and should only include . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-grgpio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index e2fc561f4315..60a1556c570a 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -26,9 +26,8 @@ #include #include #include -#include #include -#include +#include #include #include #include -- cgit v1.2.3 From f63109f0cb40bca848eef9bf096dfdb7def5e20d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 4 Mar 2018 23:37:22 +0100 Subject: gpio: htc-gpio: Include the right header This driver is a pure GPIO driver and should only include . Drop the include of from the platform data header as well, it serves no purpose. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-htc-egpio.c | 1 + include/linux/platform_data/gpio-htc-egpio.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index 271356effb2e..516383934945 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -18,6 +18,7 @@ #include #include #include +#include struct egpio_chip { int reg_start; diff --git a/include/linux/platform_data/gpio-htc-egpio.h b/include/linux/platform_data/gpio-htc-egpio.h index b7baf1e42c55..9a3e78082883 100644 --- a/include/linux/platform_data/gpio-htc-egpio.h +++ b/include/linux/platform_data/gpio-htc-egpio.h @@ -6,8 +6,6 @@ #ifndef __HTC_EGPIO_H__ #define __HTC_EGPIO_H__ -#include - /* Descriptive values for all-in or all-out htc_egpio_chip descriptors. */ #define HTC_EGPIO_OUTPUT (~0) #define HTC_EGPIO_INPUT 0 -- cgit v1.2.3 From 3f4290d4dcf1cfdc242fc4d0874995c3aead72e9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 4 Mar 2018 23:44:49 +0100 Subject: gpio: ich: Include the right header This driver is a pure GPIO driver and should only include . Refrain from using GPIOF_* flags in the driver, just use 1/0 to return direction. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ich.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 4f6d643516b7..7a54165d7276 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -176,7 +176,7 @@ static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr) { - return ichx_read_bit(GPIO_IO_SEL, nr) ? GPIOF_DIR_IN : GPIOF_DIR_OUT; + return ichx_read_bit(GPIO_IO_SEL, nr); } static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) -- cgit v1.2.3 From 7a8fd1f5cc3fd0a8fd06634b9dc6750f8c5b2354 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Mar 2018 08:56:06 +0100 Subject: gpio: ich: Use BIT() macro Using BIT() makes (1 << foo) constructions easier to read, and also account for common mistakes where bit 31 is not working because of numbers being interpreted as negative unless specified as unsigned. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ich.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 7a54165d7276..dba392221042 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -26,6 +26,7 @@ #include #include #include +#include #define DRV_NAME "gpio_ich" @@ -131,9 +132,9 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify) ichx_priv.gpio_base); if (val) - data |= 1 << bit; + data |= BIT(bit); else - data &= ~(1 << bit); + data &= ~BIT(bit); ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr], ichx_priv.gpio_base); if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) @@ -166,12 +167,12 @@ static int ichx_read_bit(int reg, unsigned nr) spin_unlock_irqrestore(&ichx_priv.lock, flags); - return data & (1 << bit) ? 1 : 0; + return !!(data & BIT(bit)); } static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) { - return !!(ichx_priv.use_gpio & (1 << (nr / 32))); + return !!(ichx_priv.use_gpio & BIT(nr / 32)); } static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr) @@ -232,12 +233,12 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr) spin_lock_irqsave(&ichx_priv.lock, flags); /* GPI 0 - 15 are latched, write 1 to clear*/ - ICHX_WRITE(1 << (16 + nr), 0, ichx_priv.pm_base); + ICHX_WRITE(BIT(16 + nr), 0, ichx_priv.pm_base); data = ICHX_READ(0, ichx_priv.pm_base); spin_unlock_irqrestore(&ichx_priv.lock, flags); - return (data >> 16) & (1 << nr) ? 1 : 0; + return !!((data >> 16) & BIT(nr)); } else { return ichx_gpio_get(chip, nr); } @@ -254,7 +255,7 @@ static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr) * the chipset's USE value can be trusted for this specific bit. * If it can't be trusted, assume that the pin can be used as a GPIO. */ - if (ichx_priv.desc->use_sel_ignore[nr / 32] & (1 << (nr & 0x1f))) + if (ichx_priv.desc->use_sel_ignore[nr / 32] & BIT(nr & 0x1f)) return 0; return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV; @@ -394,7 +395,7 @@ static int ichx_gpio_request_regions(struct device *dev, return -ENODEV; for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { - if (!(use_gpio & (1 << i))) + if (!(use_gpio & BIT(i))) continue; if (!devm_request_region(dev, res_base->start + ichx_priv.desc->regs[0][i], -- cgit v1.2.3 From c3a174036f648f0a28e047bb90784051b42c3021 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 6 Mar 2018 09:00:37 +0100 Subject: gpio: it87: Include the right header This driver is a pure GPIO driver and should only include . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-it87.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c index efb46edff81f..7cad14d3f127 100644 --- a/drivers/gpio/gpio-it87.c +++ b/drivers/gpio/gpio-it87.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include /* Chip Id numbers */ #define NO_DEV_ID 0xffff -- cgit v1.2.3 From 1c947b7f48783a3470611fc3eba61daac2629148 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Mar 2018 12:08:02 +0100 Subject: gpio: janz-ttl: Include the right header This driver is a pure GPIO driver and should only include . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-janz-ttl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c index a8d0a6b8025a..e9f4612cd2cc 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/gpio-janz-ttl.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include -- cgit v1.2.3 From 96d0d03dc447993d0eaca5c4294b7560860a378b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Mar 2018 12:11:45 +0100 Subject: gpio: janz-ttl: Use BIT() macro This makes the code more readable by using the BIT() macro. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-janz-ttl.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c index e9f4612cd2cc..6b9bf8b7bf16 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/gpio-janz-ttl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -33,9 +34,9 @@ #define MASTER_INT_CTL 0x00 #define MASTER_CONF_CTL 0x01 -#define CONF_PAE (1 << 2) -#define CONF_PBE (1 << 7) -#define CONF_PCE (1 << 4) +#define CONF_PAE BIT(2) +#define CONF_PBE BIT(7) +#define CONF_PCE BIT(4) struct ttl_control_regs { __be16 portc; @@ -74,7 +75,7 @@ static int ttl_get_value(struct gpio_chip *gpio, unsigned offset) } spin_lock(&mod->lock); - ret = *shadow & (1 << offset); + ret = *shadow & BIT(offset); spin_unlock(&mod->lock); return !!ret; } @@ -100,9 +101,9 @@ static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value) spin_lock(&mod->lock); if (value) - *shadow |= (1 << offset); + *shadow |= BIT(offset); else - *shadow &= ~(1 << offset); + *shadow &= ~BIT(offset); iowrite16be(*shadow, port); spin_unlock(&mod->lock); -- cgit v1.2.3 From 430f64998789e80e5ed22de85c18b62d6a835dcd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Mar 2018 12:16:34 +0100 Subject: gpio: kempld: Include the right header This driver is a pure GPIO driver and should only include . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-kempld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index 701f1510328c..7bb96f48ef76 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #define KEMPLD_GPIO_MAX_NUM 16 -- cgit v1.2.3 From 6e9554a48bd1840dded782af1484ae911c14ebfd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Mar 2018 12:20:23 +0100 Subject: gpio: ks8695: Include the right header This driver is a pure GPIO driver and should only include . Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ks8695.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c index 179723d02f55..55d562e1278e 100644 --- a/drivers/gpio/gpio-ks8695.c +++ b/drivers/gpio/gpio-ks8695.c @@ -18,7 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include #include #include #include -- cgit v1.2.3 From 15f59cfff92bcbbb67e1b7ebb4d10b845797bdeb Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 22 Mar 2018 08:59:37 -0400 Subject: gpio: 104-idio-16: Implement get_multiple callback The ACCES I/O 104-IDIO-16 series of devices provides 16 optically-isolated digital inputs accessed via two 8-bit ports. Since eight input lines are acquired on a single port input read, the 104-IDIO-16 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idio_16_gpio_get_multiple function which serves as the respective get_multiple callback. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-idio-16.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index 2f16638a0589..96700308c1e3 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -90,6 +90,20 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(inb(idio16gpio->base + 5) & (mask>>8)); } +static int idio_16_gpio_get_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); + + *bits = 0; + if (*mask & GENMASK(23, 16)) + *bits |= (unsigned long)inb(idio16gpio->base + 1) << 16; + if (*mask & GENMASK(31, 24)) + *bits |= (unsigned long)inb(idio16gpio->base + 5) << 24; + + return 0; +} + static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); @@ -244,6 +258,7 @@ static int idio_16_probe(struct device *dev, unsigned int id) idio16gpio->chip.direction_input = idio_16_gpio_direction_input; idio16gpio->chip.direction_output = idio_16_gpio_direction_output; idio16gpio->chip.get = idio_16_gpio_get; + idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple; idio16gpio->chip.set = idio_16_gpio_set; idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; idio16gpio->base = base[id]; -- cgit v1.2.3 From 810ebfc5efca9a05c57e5d2bad0f944b0f24267d Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 22 Mar 2018 08:59:48 -0400 Subject: gpio: pci-idio-16: Implement get_multiple callback The ACCES I/O PCI-IDIO-16 series of devices provides 16 optically-isolated digital inputs accessed via two 8-bit ports. Since eight input lines are acquired on a single port input read, the PCI-IDIO-16 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idio_16_gpio_get_multiple function which serves as the respective get_multiple callback. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pci-idio-16.c | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c index 57d1b7fbf07b..1948724d8c36 100644 --- a/drivers/gpio/gpio-pci-idio-16.c +++ b/drivers/gpio/gpio-pci-idio-16.c @@ -11,6 +11,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ +#include #include #include #include @@ -103,6 +104,54 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24)); } +static int idio_16_gpio_get_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); + size_t i; + const unsigned int gpio_reg_size = 8; + unsigned int bits_offset; + size_t word_index; + unsigned int word_offset; + unsigned long word_mask; + const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); + unsigned long port_state; + u8 __iomem ports[] = { + idio16gpio->reg->out0_7, idio16gpio->reg->out8_15, + idio16gpio->reg->in0_7, idio16gpio->reg->in8_15, + }; + + /* clear bits array to a clean slate */ + bitmap_zero(bits, chip->ngpio); + + /* get bits are evaluated a gpio port register at a time */ + for (i = 0; i < ARRAY_SIZE(ports); i++) { + /* gpio offset in bits array */ + bits_offset = i * gpio_reg_size; + + /* word index for bits array */ + word_index = BIT_WORD(bits_offset); + + /* gpio offset within current word of bits array */ + word_offset = bits_offset % BITS_PER_LONG; + + /* mask of get bits for current gpio within current word */ + word_mask = mask[word_index] & (port_mask << word_offset); + if (!word_mask) { + /* no get bits in this port so skip to next one */ + continue; + } + + /* read bits from current gpio port */ + port_state = ioread8(ports + i); + + /* store acquired bits at respective bits array offset */ + bits[word_index] |= port_state << word_offset; + } + + return 0; +} + static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { @@ -299,6 +348,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) idio16gpio->chip.direction_input = idio_16_gpio_direction_input; idio16gpio->chip.direction_output = idio_16_gpio_direction_output; idio16gpio->chip.get = idio_16_gpio_get; + idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple; idio16gpio->chip.set = idio_16_gpio_set; idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; -- cgit v1.2.3 From ca37081595a2fa1d67c962d416392d36ae8d05ad Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 22 Mar 2018 09:00:00 -0400 Subject: gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks The ACCES I/O PCIe-IDIO-24 series of devices provides 24 optically-isolated digital I/O accessed via six 8-bit ports. Since eight input lines are acquired on a single port input read -- and similarly eight output lines are set on a single port output write -- the PCIe-IDIO-24 GPIO driver may improve multiple I/O reads/writes by utilizing a get_multiple/set_multiple callbacks. This patch implements the idio_24_gpio_get_multiple function which serves as the respective get_multiple callback, and implements the idio_24_gpio_set_multiple function which serves as the respective set_multiple callback. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pcie-idio-24.c | 117 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c index f666e2e69074..835607ecf658 100644 --- a/drivers/gpio/gpio-pcie-idio-24.c +++ b/drivers/gpio/gpio-pcie-idio-24.c @@ -15,6 +15,7 @@ * This driver supports the following ACCES devices: PCIe-IDIO-24, * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12. */ +#include #include #include #include @@ -193,6 +194,61 @@ static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset) return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask); } +static int idio_24_gpio_get_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + size_t i; + const unsigned int gpio_reg_size = 8; + unsigned int bits_offset; + size_t word_index; + unsigned int word_offset; + unsigned long word_mask; + const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); + unsigned long port_state; + u8 __iomem ports[] = { + idio24gpio->reg->out0_7, idio24gpio->reg->out8_15, + idio24gpio->reg->out16_23, idio24gpio->reg->in0_7, + idio24gpio->reg->in8_15, idio24gpio->reg->in16_23, + }; + const unsigned long out_mode_mask = BIT(1); + + /* clear bits array to a clean slate */ + bitmap_zero(bits, chip->ngpio); + + /* get bits are evaluated a gpio port register at a time */ + for (i = 0; i < ARRAY_SIZE(ports); i++) { + /* gpio offset in bits array */ + bits_offset = i * gpio_reg_size; + + /* word index for bits array */ + word_index = BIT_WORD(bits_offset); + + /* gpio offset within current word of bits array */ + word_offset = bits_offset % BITS_PER_LONG; + + /* mask of get bits for current gpio within current word */ + word_mask = mask[word_index] & (port_mask << word_offset); + if (!word_mask) { + /* no get bits in this port so skip to next one */ + continue; + } + + /* read bits from current gpio port (port 6 is TTL GPIO) */ + if (i < 6) + port_state = ioread8(ports + i); + else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask) + port_state = ioread8(&idio24gpio->reg->ttl_out0_7); + else + port_state = ioread8(&idio24gpio->reg->ttl_in0_7); + + /* store acquired bits at respective bits array offset */ + bits[word_index] |= port_state << word_offset; + } + + return 0; +} + static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { @@ -234,6 +290,65 @@ static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset, raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); } +static void idio_24_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip); + size_t i; + unsigned long bits_offset; + unsigned long gpio_mask; + const unsigned int gpio_reg_size = 8; + const unsigned long port_mask = GENMASK(gpio_reg_size, 0); + unsigned long flags; + unsigned int out_state; + u8 __iomem ports[] = { + idio24gpio->reg->out0_7, idio24gpio->reg->out8_15, + idio24gpio->reg->out16_23 + }; + const unsigned long out_mode_mask = BIT(1); + const unsigned int ttl_offset = 48; + const size_t ttl_i = BIT_WORD(ttl_offset); + const unsigned int word_offset = ttl_offset % BITS_PER_LONG; + const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask; + const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask; + + /* set bits are processed a gpio port register at a time */ + for (i = 0; i < ARRAY_SIZE(ports); i++) { + /* gpio offset in bits array */ + bits_offset = i * gpio_reg_size; + + /* check if any set bits for current port */ + gpio_mask = (*mask >> bits_offset) & port_mask; + if (!gpio_mask) { + /* no set bits for this port so move on to next port */ + continue; + } + + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + /* process output lines */ + out_state = ioread8(ports + i) & ~gpio_mask; + out_state |= (*bits >> bits_offset) & gpio_mask; + iowrite8(out_state, ports + i); + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); + } + + /* check if setting TTL lines and if they are in output mode */ + if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask)) + return; + + /* handle TTL output */ + raw_spin_lock_irqsave(&idio24gpio->lock, flags); + + /* process output lines */ + out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask; + out_state |= ttl_bits; + iowrite8(out_state, &idio24gpio->reg->ttl_out0_7); + + raw_spin_unlock_irqrestore(&idio24gpio->lock, flags); +} + static void idio_24_irq_ack(struct irq_data *data) { } @@ -397,7 +512,9 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) idio24gpio->chip.direction_input = idio_24_gpio_direction_input; idio24gpio->chip.direction_output = idio_24_gpio_direction_output; idio24gpio->chip.get = idio_24_gpio_get; + idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple; idio24gpio->chip.set = idio_24_gpio_set; + idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple; raw_spin_lock_init(&idio24gpio->lock); -- cgit v1.2.3 From d2d02bcdd52b889ec1bcabf8d0da6f3c2b87e9fc Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 22 Mar 2018 09:00:11 -0400 Subject: gpio: 104-dio-48e: Implement get_multiple callback The ACCES I/O 104-DIO-48E series of devices contain two Programmable Peripheral Interface (PPI) chips of type 82C55, which each feature three 8-bit ports of I/O. Since eight input lines are acquired on a single port input read, the 104-DIO-48E GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the dio48e_gpio_get_multiple function which serves as the respective get_multiple callback. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-dio-48e.c | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index bab3b94c5cbc..31e22c93e844 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -14,6 +14,7 @@ * This driver supports the following ACCES devices: 104-DIO-48E and * 104-DIO-24E. */ +#include #include #include #include @@ -182,6 +183,51 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(port_state & mask); } +static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); + size_t i; + const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; + const unsigned int gpio_reg_size = 8; + unsigned int bits_offset; + size_t word_index; + unsigned int word_offset; + unsigned long word_mask; + const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); + unsigned long port_state; + + /* clear bits array to a clean slate */ + bitmap_zero(bits, chip->ngpio); + + /* get bits are evaluated a gpio port register at a time */ + for (i = 0; i < ARRAY_SIZE(ports); i++) { + /* gpio offset in bits array */ + bits_offset = i * gpio_reg_size; + + /* word index for bits array */ + word_index = BIT_WORD(bits_offset); + + /* gpio offset within current word of bits array */ + word_offset = bits_offset % BITS_PER_LONG; + + /* mask of get bits for current gpio within current word */ + word_mask = mask[word_index] & (port_mask << word_offset); + if (!word_mask) { + /* no get bits in this port so skip to next one */ + continue; + } + + /* read bits from current gpio port */ + port_state = inb(dio48egpio->base + ports[i]); + + /* store acquired bits at respective bits array offset */ + bits[word_index] |= port_state << word_offset; + } + + return 0; +} + static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); @@ -384,6 +430,7 @@ static int dio48e_probe(struct device *dev, unsigned int id) dio48egpio->chip.direction_input = dio48e_gpio_direction_input; dio48egpio->chip.direction_output = dio48e_gpio_direction_output; dio48egpio->chip.get = dio48e_gpio_get; + dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple; dio48egpio->chip.set = dio48e_gpio_set; dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple; dio48egpio->base = base[id]; -- cgit v1.2.3 From f72b10713cf5a9f6a425bdbd8da093cb02990d4d Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 22 Mar 2018 09:00:31 -0400 Subject: gpio: 104-idi-48: Implement get_multiple callback The ACCES I/O 104-IDI-48 series of devices provides 48 optically-isolated inputs accessed via six 8-bit ports. Since eight input lines are acquired on a single port input read, the 104-IDI-48 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idi_48_gpio_get_multiple function which serves as the respective get_multiple callback. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-104-idi-48.c | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index add859d59766..f35632609379 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -14,6 +14,7 @@ * This driver supports the following ACCES devices: 104-IDI-48A, * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC. */ +#include #include #include #include @@ -88,6 +89,51 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset) return 0; } +static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); + size_t i; + const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; + const unsigned int gpio_reg_size = 8; + unsigned int bits_offset; + size_t word_index; + unsigned int word_offset; + unsigned long word_mask; + const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); + unsigned long port_state; + + /* clear bits array to a clean slate */ + bitmap_zero(bits, chip->ngpio); + + /* get bits are evaluated a gpio port register at a time */ + for (i = 0; i < ARRAY_SIZE(ports); i++) { + /* gpio offset in bits array */ + bits_offset = i * gpio_reg_size; + + /* word index for bits array */ + word_index = BIT_WORD(bits_offset); + + /* gpio offset within current word of bits array */ + word_offset = bits_offset % BITS_PER_LONG; + + /* mask of get bits for current gpio within current word */ + word_mask = mask[word_index] & (port_mask << word_offset); + if (!word_mask) { + /* no get bits in this port so skip to next one */ + continue; + } + + /* read bits from current gpio port */ + port_state = inb(idi48gpio->base + ports[i]); + + /* store acquired bits at respective bits array offset */ + bits[word_index] |= port_state << word_offset; + } + + return 0; +} + static void idi_48_irq_ack(struct irq_data *data) { } @@ -256,6 +302,7 @@ static int idi_48_probe(struct device *dev, unsigned int id) idi48gpio->chip.get_direction = idi_48_gpio_get_direction; idi48gpio->chip.direction_input = idi_48_gpio_direction_input; idi48gpio->chip.get = idi_48_gpio_get; + idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple; idi48gpio->base = base[id]; raw_spin_lock_init(&idi48gpio->lock); -- cgit v1.2.3 From 41b251318a6359848eef98b630ed578fad2cfbe6 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 22 Mar 2018 09:00:42 -0400 Subject: gpio: gpio-mm: Implement get_multiple callback The Diamond Systems GPIO-MM series of devices contain two 82C55A devices, which each feature three 8-bit ports of I/O. Since eight input lines are acquired on a single port input read, the GPIO-MM GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the gpiomm_gpio_get_multiple function which serves as the respective get_multiple callback. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-gpio-mm.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 11ade5b288f8..d496cc56c2a2 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -14,6 +14,7 @@ * This driver supports the following Diamond Systems devices: GPIO-MM and * GPIO-MM-12. */ +#include #include #include #include @@ -171,6 +172,51 @@ static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) return !!(port_state & mask); } +static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); + size_t i; + const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; + const unsigned int gpio_reg_size = 8; + unsigned int bits_offset; + size_t word_index; + unsigned int word_offset; + unsigned long word_mask; + const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); + unsigned long port_state; + + /* clear bits array to a clean slate */ + bitmap_zero(bits, chip->ngpio); + + /* get bits are evaluated a gpio port register at a time */ + for (i = 0; i < ARRAY_SIZE(ports); i++) { + /* gpio offset in bits array */ + bits_offset = i * gpio_reg_size; + + /* word index for bits array */ + word_index = BIT_WORD(bits_offset); + + /* gpio offset within current word of bits array */ + word_offset = bits_offset % BITS_PER_LONG; + + /* mask of get bits for current gpio within current word */ + word_mask = mask[word_index] & (port_mask << word_offset); + if (!word_mask) { + /* no get bits in this port so skip to next one */ + continue; + } + + /* read bits from current gpio port */ + port_state = inb(gpiommgpio->base + ports[i]); + + /* store acquired bits at respective bits array offset */ + bits[word_index] |= port_state << word_offset; + } + + return 0; +} + static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { @@ -268,6 +314,7 @@ static int gpiomm_probe(struct device *dev, unsigned int id) gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; gpiommgpio->chip.get = gpiomm_gpio_get; + gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple; gpiommgpio->chip.set = gpiomm_gpio_set; gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple; gpiommgpio->base = base[id]; -- cgit v1.2.3 From a8ff510dbc2a4f1e17b97e35f9607c47a1df89a9 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 22 Mar 2018 09:00:59 -0400 Subject: gpio: ws16c48: Implement get_multiple callback The WinSystems WS16C48 device provides 48 lines of digital I/O accessed via six 8-bit ports. Since eight input lines are acquired on a single port input read, the WS16C48 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the ws16c48_gpio_get_multiple function which serves as the respective get_multiple callback. Signed-off-by: William Breathitt Gray Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ws16c48.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index 746648244bf3..c7028eb0b8e1 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -11,6 +11,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ +#include #include #include #include @@ -129,6 +130,51 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(port_state & mask); } +static int ws16c48_gpio_get_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); + const unsigned int gpio_reg_size = 8; + size_t i; + const size_t num_ports = chip->ngpio / gpio_reg_size; + unsigned int bits_offset; + size_t word_index; + unsigned int word_offset; + unsigned long word_mask; + const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); + unsigned long port_state; + + /* clear bits array to a clean slate */ + bitmap_zero(bits, chip->ngpio); + + /* get bits are evaluated a gpio port register at a time */ + for (i = 0; i < num_ports; i++) { + /* gpio offset in bits array */ + bits_offset = i * gpio_reg_size; + + /* word index for bits array */ + word_index = BIT_WORD(bits_offset); + + /* gpio offset within current word of bits array */ + word_offset = bits_offset % BITS_PER_LONG; + + /* mask of get bits for current gpio within current word */ + word_mask = mask[word_index] & (port_mask << word_offset); + if (!word_mask) { + /* no get bits in this port so skip to next one */ + continue; + } + + /* read bits from current gpio port */ + port_state = inb(ws16c48gpio->base + i); + + /* store acquired bits at respective bits array offset */ + bits[word_index] |= port_state << word_offset; + } + + return 0; +} + static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); @@ -383,6 +429,7 @@ static int ws16c48_probe(struct device *dev, unsigned int id) ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input; ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output; ws16c48gpio->chip.get = ws16c48_gpio_get; + ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple; ws16c48gpio->chip.set = ws16c48_gpio_set; ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple; ws16c48gpio->base = base[id]; -- cgit v1.2.3 From 48da181dac478bb517aae2483e69f3eeec24172c Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Fri, 9 Mar 2018 16:10:19 -0800 Subject: gpio: Remove VLA from MAX3191X driver The new challenge is to remove VLAs from the kernel (see https://lkml.org/lkml/2018/3/7/621) This patch replaces several a VLA with an appropriate call to kmalloc_array. Signed-off-by: Laura Abbott Reviewed-and-tested-by: Lukas Wunner Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max3191x.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index f74b1072e84b..b5b9cb1fda50 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -315,12 +315,17 @@ static void gpiod_set_array_single_value_cansleep(unsigned int ndescs, struct gpio_desc **desc, int value) { - int i, values[ndescs]; + int i, *values; + + values = kmalloc_array(ndescs, sizeof(*values), GFP_KERNEL); + if (!values) + return; for (i = 0; i < ndescs; i++) values[i] = value; gpiod_set_array_value_cansleep(ndescs, desc, values); + kfree(values); } static struct gpio_descs *devm_gpiod_get_array_optional_count( -- cgit v1.2.3 From 13b5319e92a94036ce2131f76510e108428daec8 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Fri, 9 Mar 2018 16:10:20 -0800 Subject: gpio: Remove VLA from xra1403 driver The new challenge is to remove VLAs from the kernel (see https://lkml.org/lkml/2018/3/7/621) This patch replaces a VLA with an appropriate call to kmalloc_array. Signed-off-by: Laura Abbott Reviewed-by: Nandor Han Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xra1403.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c index 0230e4b7a2fb..8d4c8e99b251 100644 --- a/drivers/gpio/gpio-xra1403.c +++ b/drivers/gpio/gpio-xra1403.c @@ -126,11 +126,16 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip) { int reg; struct xra1403 *xra = gpiochip_get_data(chip); - int value[xra1403_regmap_cfg.max_register]; + int *value; int i; unsigned int gcr; unsigned int gsr; + value = kmalloc_array(xra1403_regmap_cfg.max_register, sizeof(*value), + GFP_KERNEL); + if (!value) + return; + seq_puts(s, "xra reg:"); for (reg = 0; reg <= xra1403_regmap_cfg.max_register; reg++) seq_printf(s, " %2.2x", reg); @@ -154,6 +159,7 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip) (gcr & BIT(i)) ? "in" : "out", (gsr & BIT(i)) ? "hi" : "lo"); } + kfree(value); } #else #define xra1403_dbg_show NULL -- cgit v1.2.3 From e6bf37736f6495fb87ce5525d1f6fd2adce307f1 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 12 Mar 2018 18:30:56 +0000 Subject: gpio: dwapb: Add support for a bus clock Enable an optional bus clock provided by DT. Signed-off-by: Phil Edworthy Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-dwapb.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index b0704a883513..226977f78482 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -8,8 +8,9 @@ * All enquiries to support@picochip.com */ #include -#include +#include #include +#include #include #include #include @@ -98,6 +99,7 @@ struct dwapb_gpio { struct irq_domain *domain; unsigned int flags; struct reset_control *rst; + struct clk *clk; }; static inline u32 gpio_reg_v2_convert(unsigned int offset) @@ -670,6 +672,16 @@ static int dwapb_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpio->regs)) return PTR_ERR(gpio->regs); + /* Optional bus clock */ + gpio->clk = devm_clk_get(&pdev->dev, "bus"); + if (!IS_ERR(gpio->clk)) { + err = clk_prepare_enable(gpio->clk); + if (err) { + dev_info(&pdev->dev, "Cannot enable clock\n"); + return err; + } + } + gpio->flags = 0; if (dev->of_node) { const struct of_device_id *of_devid; @@ -712,6 +724,7 @@ static int dwapb_gpio_remove(struct platform_device *pdev) dwapb_gpio_unregister(gpio); dwapb_irq_teardown(gpio); reset_control_assert(gpio->rst); + clk_disable_unprepare(gpio->clk); return 0; } @@ -757,6 +770,8 @@ static int dwapb_gpio_suspend(struct device *dev) } spin_unlock_irqrestore(&gc->bgpio_lock, flags); + clk_disable_unprepare(gpio->clk); + return 0; } @@ -768,6 +783,9 @@ static int dwapb_gpio_resume(struct device *dev) unsigned long flags; int i; + if (!IS_ERR(gpio->clk)) + clk_prepare_enable(gpio->clk); + spin_lock_irqsave(&gc->bgpio_lock, flags); for (i = 0; i < gpio->nr_ports; i++) { unsigned int offset; -- cgit v1.2.3 From 3a711e0dd4e68f6b202db3f9e2c0086a8780da25 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Sat, 10 Mar 2018 12:00:01 +0100 Subject: gpio: pca953x: add compatibility for pcal6524 and pcal9555a The Pyra-Handheld originally used the tca6424 but recently we have replaced it by the pin and package compatible pcal6524. So let's add this to the bindings and the driver. And while we are at it, the pcal9555a does not have a compatible entry either but is already supported by the device id table. Signed-off-by: H. Nikolaus Schaller Reviewed-by: Rob Herring Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/gpio-pca953x.txt | 2 ++ drivers/gpio/gpio-pca953x.c | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt index 0d0158728f89..d2a937682836 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt @@ -16,6 +16,8 @@ Required properties: nxp,pca9574 nxp,pca9575 nxp,pca9698 + nxp,pcal6524 + nxp,pcal9555a maxim,max7310 maxim,max7312 maxim,max7313 diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index a0a5f9730aa7..d2ead4b1cf61 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -70,6 +70,7 @@ static const struct i2c_device_id pca953x_id[] = { { "pca9575", 16 | PCA957X_TYPE | PCA_INT, }, { "pca9698", 40 | PCA953X_TYPE, }, + { "pcal6524", 24 | PCA953X_TYPE | PCA_INT | PCA_PCAL, }, { "pcal9555a", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, }, { "max7310", 8 | PCA953X_TYPE, }, @@ -935,6 +936,9 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), }, { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), }, + { .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_INT), }, + { .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_INT), }, + { .compatible = "maxim,max7310", .data = OF_953X( 8, 0), }, { .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), }, { .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), }, -- cgit v1.2.3 From 6cb9215baeb9c1ed336a5e8905f7ad7c4698acc9 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Sun, 4 Mar 2018 13:45:51 +0100 Subject: gpio: mockup: fix a potential crash when creating debugfs entries If we failed to create the top debugfs directory, we must not try to create the child nodes. We currently only check if gpio_mockup_dbg_dir is not NULL, but it can also contain an errno if debugfs is disabled in build options. Use IS_ERR_OR_NULL() instead. Signed-off-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 21422b8e487b..76c2fe91a901 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -314,7 +314,7 @@ static int gpio_mockup_probe(struct platform_device *pdev) if (rv) return rv; - if (gpio_mockup_dbg_dir) + if (!IS_ERR_OR_NULL(gpio_mockup_dbg_dir)) gpio_mockup_debugfs_setup(dev, chip); return 0; -- cgit v1.2.3 From e4371f6e079294369ecb4cfa03aaeb60831e8b91 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 23 Mar 2018 09:34:50 -0700 Subject: gpiolib: Extract mask allocation into subroutine We're going to use similar code to allocate and set all the bits in a mask for valid gpios to use. Extract the code from the irqchip version so it can be reused. Signed-off-by: Stephen Boyd Tested-by: Timur Tabi Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d66de67ef307..cc0e1519da45 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -337,6 +337,20 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc) return 0; } +static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip) +{ + unsigned long *p; + + p = kcalloc(BITS_TO_LONGS(chip->ngpio), sizeof(long), GFP_KERNEL); + if (!p) + return NULL; + + /* Assume by default all GPIOs are valid */ + bitmap_fill(p, chip->ngpio); + + return p; +} + /* * GPIO line handle management */ @@ -1506,14 +1520,10 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) if (!gpiochip->irq.need_valid_mask) return 0; - gpiochip->irq.valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio), - sizeof(long), GFP_KERNEL); + gpiochip->irq.valid_mask = gpiochip_allocate_mask(gpiochip); if (!gpiochip->irq.valid_mask) return -ENOMEM; - /* Assume by default all GPIOs are valid */ - bitmap_fill(gpiochip->irq.valid_mask, gpiochip->ngpio); - return 0; } -- cgit v1.2.3 From ace56935ff48879239d79129c7882ea2ff1b4804 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 23 Mar 2018 09:34:51 -0700 Subject: gpiolib: Change bitmap allocation to kmalloc_array We don't need to clear out these bits when we set them immediately after. Use kmalloc_array() to skip clearing the bits. Suggested-by: Andy Shevchenko Signed-off-by: Stephen Boyd Tested-by: Timur Tabi Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index cc0e1519da45..db3788d17ba0 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -341,7 +341,7 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip) { unsigned long *p; - p = kcalloc(BITS_TO_LONGS(chip->ngpio), sizeof(long), GFP_KERNEL); + p = kmalloc_array(BITS_TO_LONGS(chip->ngpio), sizeof(*p), GFP_KERNEL); if (!p) return NULL; -- cgit v1.2.3 From 726cb3ba49692bdae6caff457755e7cdb432efa4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 23 Mar 2018 09:34:52 -0700 Subject: gpiolib: Support 'gpio-reserved-ranges' property Some qcom platforms make some GPIOs or pins unavailable for use by non-secure operating systems, and thus reading or writing the registers for those pins will cause access control issues. Add support for a DT property to describe the set of GPIOs that are available for use so that higher level OSes are able to know what pins to avoid reading/writing. Non-DT platforms can add support by directly updating the chip->valid_mask. Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd Tested-by: Timur Tabi Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 24 +++++++++++++++++++++++ drivers/gpio/gpiolib.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/gpio/driver.h | 16 ++++++++++++++++ 3 files changed, 86 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 84e5a9df2344..ed81d9a6316f 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -511,6 +511,28 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc) } EXPORT_SYMBOL(of_mm_gpiochip_remove); +static void of_gpiochip_init_valid_mask(struct gpio_chip *chip) +{ + int len, i; + u32 start, count; + struct device_node *np = chip->of_node; + + len = of_property_count_u32_elems(np, "gpio-reserved-ranges"); + if (len < 0 || len % 2 != 0) + return; + + for (i = 0; i < len; i += 2) { + of_property_read_u32_index(np, "gpio-reserved-ranges", + i, &start); + of_property_read_u32_index(np, "gpio-reserved-ranges", + i + 1, &count); + if (start >= chip->ngpio || start + count >= chip->ngpio) + continue; + + bitmap_clear(chip->valid_mask, start, count); + } +}; + #ifdef CONFIG_PINCTRL static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { @@ -615,6 +637,8 @@ int of_gpiochip_add(struct gpio_chip *chip) if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS) return -EINVAL; + of_gpiochip_init_valid_mask(chip); + status = of_gpiochip_add_pin_range(chip); if (status) return status; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index db3788d17ba0..fecbb553e8a4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -351,6 +351,43 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip) return p; } +static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip) +{ +#ifdef CONFIG_OF_GPIO + int size; + struct device_node *np = gpiochip->of_node; + + size = of_property_count_u32_elems(np, "gpio-reserved-ranges"); + if (size > 0 && size % 2 == 0) + gpiochip->need_valid_mask = true; +#endif + + if (!gpiochip->need_valid_mask) + return 0; + + gpiochip->valid_mask = gpiochip_allocate_mask(gpiochip); + if (!gpiochip->valid_mask) + return -ENOMEM; + + return 0; +} + +static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip) +{ + kfree(gpiochip->valid_mask); + gpiochip->valid_mask = NULL; +} + +bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip, + unsigned int offset) +{ + /* No mask means all valid */ + if (likely(!gpiochip->valid_mask)) + return true; + return test_bit(offset, gpiochip->valid_mask); +} +EXPORT_SYMBOL_GPL(gpiochip_line_is_valid); + /* * GPIO line handle management */ @@ -1275,6 +1312,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, if (status) goto err_remove_from_list; + status = gpiochip_init_valid_mask(chip); + if (status) + goto err_remove_irqchip_mask; + status = gpiochip_add_irqchip(chip, lock_key, request_key); if (status) goto err_remove_chip; @@ -1304,6 +1345,8 @@ err_remove_chip: acpi_gpiochip_remove(chip); gpiochip_free_hogs(chip); of_gpiochip_remove(chip); + gpiochip_free_valid_mask(chip); +err_remove_irqchip_mask: gpiochip_irqchip_free_valid_mask(chip); err_remove_from_list: spin_lock_irqsave(&gpio_lock, flags); @@ -1360,6 +1403,7 @@ void gpiochip_remove(struct gpio_chip *chip) acpi_gpiochip_remove(chip); gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); + gpiochip_free_valid_mask(chip); /* * We accept no more calls into the driver from this point, so * NULL the driver data pointer @@ -1536,6 +1580,8 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, unsigned int offset) { + if (!gpiochip_line_is_valid(gpiochip, offset)) + return false; /* No mask means all valid */ if (likely(!gpiochip->irq.valid_mask)) return true; diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 1ba9a331ec51..5382b5183b7e 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -288,6 +288,21 @@ struct gpio_chip { struct gpio_irq_chip irq; #endif + /** + * @need_valid_mask: + * + * If set core allocates @valid_mask with all bits set to one. + */ + bool need_valid_mask; + + /** + * @valid_mask: + * + * If not %NULL holds bitmask of GPIOs which are valid to be used + * from the chip. + */ + unsigned long *valid_mask; + #if defined(CONFIG_OF_GPIO) /* * If CONFIG_OF is enabled, then all GPIO controllers described in the @@ -384,6 +399,7 @@ bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset); /* Sleep persistence inquiry for drivers */ bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset); +bool gpiochip_line_is_valid(const struct gpio_chip *chip, unsigned int offset); /* get driver data */ void *gpiochip_get_data(struct gpio_chip *chip); -- cgit v1.2.3 From 691bf5d5a7bfedc60b7218f4d9b915bf356df767 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 23 Mar 2018 09:34:53 -0700 Subject: pinctrl: qcom: Don't allow protected pins to be requested Some qcom platforms make some GPIOs or pins unavailable for use by non-secure operating systems, and thus reading or writing the registers for those pins will cause access control issues and reset the device. With a DT/ACPI property to describe the set of pins that are available for use, parse the available pins and set the irq valid bits for gpiolib to know what to consider 'valid'. This should avoid any issues with gpiolib. Furthermore, implement the pinmux_ops::request function so that pinmux can also make sure to not use pins that are unavailable. Signed-off-by: Stephen Boyd Signed-off-by: Stephen Boyd Tested-by: Timur Tabi Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-msm.c | 65 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 495432f3341b..e7abc8ba222b 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -105,6 +105,14 @@ static const struct pinctrl_ops msm_pinctrl_ops = { .dt_free_map = pinctrl_utils_free_map, }; +static int msm_pinmux_request(struct pinctrl_dev *pctldev, unsigned offset) +{ + struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct gpio_chip *chip = &pctrl->chip; + + return gpiochip_line_is_valid(chip, offset) ? 0 : -EINVAL; +} + static int msm_get_functions_count(struct pinctrl_dev *pctldev) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); @@ -166,6 +174,7 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev, } static const struct pinmux_ops msm_pinmux_ops = { + .request = msm_pinmux_request, .get_functions_count = msm_get_functions_count, .get_function_name = msm_get_function_name, .get_function_groups = msm_get_function_groups, @@ -506,6 +515,9 @@ static void msm_gpio_dbg_show_one(struct seq_file *s, "pull up" }; + if (!gpiochip_line_is_valid(chip, offset)) + return; + g = &pctrl->soc->groups[offset]; ctl_reg = readl(pctrl->regs + g->ctl_reg); @@ -517,6 +529,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s, seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func); seq_printf(s, " %dmA", msm_regval_to_drive(drive)); seq_printf(s, " %s", pulls[pull]); + seq_puts(s, "\n"); } static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) @@ -524,10 +537,8 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; unsigned i; - for (i = 0; i < chip->ngpio; i++, gpio++) { + for (i = 0; i < chip->ngpio; i++, gpio++) msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); - seq_puts(s, "\n"); - } } #else @@ -808,6 +819,46 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } +static int msm_gpio_init_valid_mask(struct gpio_chip *chip, + struct msm_pinctrl *pctrl) +{ + int ret; + unsigned int len, i; + unsigned int max_gpios = pctrl->soc->ngpios; + u16 *tmp; + + /* The number of GPIOs in the ACPI tables */ + len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0); + if (ret < 0) + return 0; + + if (ret > max_gpios) + return -EINVAL; + + tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len); + if (ret < 0) { + dev_err(pctrl->dev, "could not read list of GPIOs\n"); + goto out; + } + + bitmap_zero(chip->valid_mask, max_gpios); + for (i = 0; i < len; i++) + set_bit(tmp[i], chip->valid_mask); + +out: + kfree(tmp); + return ret; +} + +static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) +{ + return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0; +} + static int msm_gpio_init(struct msm_pinctrl *pctrl) { struct gpio_chip *chip; @@ -824,6 +875,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) chip->parent = pctrl->dev; chip->owner = THIS_MODULE; chip->of_node = pctrl->dev->of_node; + chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl); ret = gpiochip_add_data(&pctrl->chip, pctrl); if (ret) { @@ -831,6 +883,13 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) return ret; } + ret = msm_gpio_init_valid_mask(chip, pctrl); + if (ret) { + dev_err(pctrl->dev, "Failed to setup irq valid bits\n"); + gpiochip_remove(&pctrl->chip); + return ret; + } + ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio); if (ret) { dev_err(pctrl->dev, "Failed to add pin range\n"); -- cgit v1.2.3 From f79b55d9b9e06547a9b9fad0d6948e1ce8d00865 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 25 Mar 2018 00:40:48 +0100 Subject: gpio: ath79: Fix potential NULL dereference in ath79_gpio_probe() platform_get_resource() may return NULL, add proper check to avoid potential NULL dereferencing. 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 [albeu@free.fr: Fixed patch to apply on current tree] Signed-off-by: Alban Bedel Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ath79.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index 3ae7c1876bf4..684e9d6d6623 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -258,6 +258,8 @@ static int ath79_gpio_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; ctrl->base = devm_ioremap_nocache( &pdev->dev, res->start, resource_size(res)); if (!ctrl->base) -- cgit v1.2.3 From 25518e024e3a6e5715d672f1daa91e1d100f7436 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 5 Mar 2018 10:56:51 +0800 Subject: gpio: Add Spreadtrum EIC driver support The Spreadtrum digital-chip EIC controller has 4 sub-modules: debounce EIC, latch EIC, async EIC and sync EIC, and each sub-module can has multiple banks and each bank contains 8 EICs. Each EIC can only be used as input mode, and has the capability to trigger interrupts when detecting input signals. Signed-off-by: Baolin Wang Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 8 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-eic-sprd.c | 606 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 615 insertions(+) create mode 100644 drivers/gpio/gpio-eic-sprd.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6b1ee11295d5..380aa90501ea 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -170,6 +170,14 @@ config GPIO_DWAPB Say Y or M here to build support for the Synopsys DesignWare APB GPIO block. +config GPIO_EIC_SPRD + tristate "Spreadtrum EIC support" + depends on ARCH_SPRD || COMPILE_TEST + depends on OF_GPIO + select GPIOLIB_IRQCHIP + help + Say yes here to support Spreadtrum EIC device. + config GPIO_EM tristate "Emma Mobile GPIO" depends on (ARCH_EMEV2 || COMPILE_TEST) && OF_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 5c1f087c65aa..2437f3596934 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o +obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c new file mode 100644 index 000000000000..de7dd939c043 --- /dev/null +++ b/drivers/gpio/gpio-eic-sprd.c @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Spreadtrum Communications Inc. + * Copyright (C) 2018 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* EIC registers definition */ +#define SPRD_EIC_DBNC_DATA 0x0 +#define SPRD_EIC_DBNC_DMSK 0x4 +#define SPRD_EIC_DBNC_IEV 0x14 +#define SPRD_EIC_DBNC_IE 0x18 +#define SPRD_EIC_DBNC_RIS 0x1c +#define SPRD_EIC_DBNC_MIS 0x20 +#define SPRD_EIC_DBNC_IC 0x24 +#define SPRD_EIC_DBNC_TRIG 0x28 +#define SPRD_EIC_DBNC_CTRL0 0x40 + +#define SPRD_EIC_LATCH_INTEN 0x0 +#define SPRD_EIC_LATCH_INTRAW 0x4 +#define SPRD_EIC_LATCH_INTMSK 0x8 +#define SPRD_EIC_LATCH_INTCLR 0xc +#define SPRD_EIC_LATCH_INTPOL 0x10 +#define SPRD_EIC_LATCH_INTMODE 0x14 + +#define SPRD_EIC_ASYNC_INTIE 0x0 +#define SPRD_EIC_ASYNC_INTRAW 0x4 +#define SPRD_EIC_ASYNC_INTMSK 0x8 +#define SPRD_EIC_ASYNC_INTCLR 0xc +#define SPRD_EIC_ASYNC_INTMODE 0x10 +#define SPRD_EIC_ASYNC_INTBOTH 0x14 +#define SPRD_EIC_ASYNC_INTPOL 0x18 +#define SPRD_EIC_ASYNC_DATA 0x1c + +#define SPRD_EIC_SYNC_INTIE 0x0 +#define SPRD_EIC_SYNC_INTRAW 0x4 +#define SPRD_EIC_SYNC_INTMSK 0x8 +#define SPRD_EIC_SYNC_INTCLR 0xc +#define SPRD_EIC_SYNC_INTMODE 0x10 +#define SPRD_EIC_SYNC_INTBOTH 0x14 +#define SPRD_EIC_SYNC_INTPOL 0x18 +#define SPRD_EIC_SYNC_DATA 0x1c + +/* + * The digital-chip EIC controller can support maximum 3 banks, and each bank + * contains 8 EICs. + */ +#define SPRD_EIC_MAX_BANK 3 +#define SPRD_EIC_PER_BANK_NR 8 +#define SPRD_EIC_DATA_MASK GENMASK(7, 0) +#define SPRD_EIC_BIT(x) ((x) & (SPRD_EIC_PER_BANK_NR - 1)) +#define SPRD_EIC_DBNC_MASK GENMASK(11, 0) + +/* + * The Spreadtrum EIC (external interrupt controller) can be used only in + * input mode to generate interrupts if detecting input signals. + * + * The Spreadtrum digital-chip EIC controller contains 4 sub-modules: + * debounce EIC, latch EIC, async EIC and sync EIC, + * + * The debounce EIC is used to capture the input signals' stable status + * (millisecond resolution) and a single-trigger mechanism is introduced + * into this sub-module to enhance the input event detection reliability. + * The debounce range is from 1ms to 4s with a step size of 1ms. + * + * The latch EIC is used to latch some special power down signals and + * generate interrupts, since the latch EIC does not depend on the APB clock + * to capture signals. + * + * The async EIC uses a 32k clock to capture the short signals (microsecond + * resolution) to generate interrupts by level or edge trigger. + * + * The EIC-sync is similar with GPIO's input function, which is a synchronized + * signal input register. + */ +enum sprd_eic_type { + SPRD_EIC_DEBOUNCE, + SPRD_EIC_LATCH, + SPRD_EIC_ASYNC, + SPRD_EIC_SYNC, + SPRD_EIC_MAX, +}; + +struct sprd_eic { + struct gpio_chip chip; + struct irq_chip intc; + void __iomem *base[SPRD_EIC_MAX_BANK]; + enum sprd_eic_type type; + spinlock_t lock; + int irq; +}; + +struct sprd_eic_variant_data { + enum sprd_eic_type type; + u32 num_eics; +}; + +static const char *sprd_eic_label_name[SPRD_EIC_MAX] = { + "eic-debounce", "eic-latch", "eic-async", + "eic-sync", +}; + +static const struct sprd_eic_variant_data sc9860_eic_dbnc_data = { + .type = SPRD_EIC_DEBOUNCE, + .num_eics = 8, +}; + +static const struct sprd_eic_variant_data sc9860_eic_latch_data = { + .type = SPRD_EIC_LATCH, + .num_eics = 8, +}; + +static const struct sprd_eic_variant_data sc9860_eic_async_data = { + .type = SPRD_EIC_ASYNC, + .num_eics = 8, +}; + +static const struct sprd_eic_variant_data sc9860_eic_sync_data = { + .type = SPRD_EIC_SYNC, + .num_eics = 8, +}; + +static inline void __iomem *sprd_eic_offset_base(struct sprd_eic *sprd_eic, + unsigned int bank) +{ + if (bank >= SPRD_EIC_MAX_BANK) + return NULL; + + return sprd_eic->base[bank]; +} + +static void sprd_eic_update(struct gpio_chip *chip, unsigned int offset, + u16 reg, unsigned int val) +{ + struct sprd_eic *sprd_eic = gpiochip_get_data(chip); + void __iomem *base = + sprd_eic_offset_base(sprd_eic, offset / SPRD_EIC_PER_BANK_NR); + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&sprd_eic->lock, flags); + tmp = readl_relaxed(base + reg); + + if (val) + tmp |= BIT(SPRD_EIC_BIT(offset)); + else + tmp &= ~BIT(SPRD_EIC_BIT(offset)); + + writel_relaxed(tmp, base + reg); + spin_unlock_irqrestore(&sprd_eic->lock, flags); +} + +static int sprd_eic_read(struct gpio_chip *chip, unsigned int offset, u16 reg) +{ + struct sprd_eic *sprd_eic = gpiochip_get_data(chip); + void __iomem *base = + sprd_eic_offset_base(sprd_eic, offset / SPRD_EIC_PER_BANK_NR); + + return !!(readl_relaxed(base + reg) & BIT(SPRD_EIC_BIT(offset))); +} + +static int sprd_eic_request(struct gpio_chip *chip, unsigned int offset) +{ + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_DMSK, 1); + return 0; +} + +static void sprd_eic_free(struct gpio_chip *chip, unsigned int offset) +{ + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_DMSK, 0); +} + +static int sprd_eic_get(struct gpio_chip *chip, unsigned int offset) +{ + return sprd_eic_read(chip, offset, SPRD_EIC_DBNC_DATA); +} + +static int sprd_eic_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + /* EICs are always input, nothing need to do here. */ + return 0; +} + +static void sprd_eic_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + /* EICs are always input, nothing need to do here. */ +} + +static int sprd_eic_set_debounce(struct gpio_chip *chip, unsigned int offset, + unsigned int debounce) +{ + struct sprd_eic *sprd_eic = gpiochip_get_data(chip); + void __iomem *base = + sprd_eic_offset_base(sprd_eic, offset / SPRD_EIC_PER_BANK_NR); + u32 reg = SPRD_EIC_DBNC_CTRL0 + SPRD_EIC_BIT(offset) * 0x4; + u32 value = readl_relaxed(base + reg) & ~SPRD_EIC_DBNC_MASK; + + value |= (debounce / 1000) & SPRD_EIC_DBNC_MASK; + writel_relaxed(value, base + reg); + + return 0; +} + +static int sprd_eic_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + unsigned long param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); + + if (param == PIN_CONFIG_INPUT_DEBOUNCE) + return sprd_eic_set_debounce(chip, offset, arg); + + return -ENOTSUPP; +} + +static void sprd_eic_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct sprd_eic *sprd_eic = gpiochip_get_data(chip); + u32 offset = irqd_to_hwirq(data); + + switch (sprd_eic->type) { + case SPRD_EIC_DEBOUNCE: + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_TRIG, 0); + break; + case SPRD_EIC_LATCH: + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTEN, 0); + break; + case SPRD_EIC_ASYNC: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTIE, 0); + break; + case SPRD_EIC_SYNC: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTIE, 0); + break; + default: + dev_err(chip->parent, "Unsupported EIC type.\n"); + } +} + +static void sprd_eic_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct sprd_eic *sprd_eic = gpiochip_get_data(chip); + u32 offset = irqd_to_hwirq(data); + + switch (sprd_eic->type) { + case SPRD_EIC_DEBOUNCE: + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IE, 1); + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_TRIG, 1); + break; + case SPRD_EIC_LATCH: + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTEN, 1); + break; + case SPRD_EIC_ASYNC: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTIE, 1); + break; + case SPRD_EIC_SYNC: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTIE, 1); + break; + default: + dev_err(chip->parent, "Unsupported EIC type.\n"); + } +} + +static void sprd_eic_irq_ack(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct sprd_eic *sprd_eic = gpiochip_get_data(chip); + u32 offset = irqd_to_hwirq(data); + + switch (sprd_eic->type) { + case SPRD_EIC_DEBOUNCE: + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1); + break; + case SPRD_EIC_LATCH: + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1); + break; + case SPRD_EIC_ASYNC: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); + break; + case SPRD_EIC_SYNC: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); + break; + default: + dev_err(chip->parent, "Unsupported EIC type.\n"); + } +} + +static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct sprd_eic *sprd_eic = gpiochip_get_data(chip); + u32 offset = irqd_to_hwirq(data); + + switch (sprd_eic->type) { + case SPRD_EIC_DEBOUNCE: + switch (flow_type) { + case IRQ_TYPE_LEVEL_HIGH: + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1); + break; + case IRQ_TYPE_LEVEL_LOW: + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0); + break; + default: + return -ENOTSUPP; + } + + irq_set_handler_locked(data, handle_level_irq); + break; + case SPRD_EIC_LATCH: + switch (flow_type) { + case IRQ_TYPE_LEVEL_HIGH: + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0); + break; + case IRQ_TYPE_LEVEL_LOW: + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1); + break; + default: + return -ENOTSUPP; + } + + irq_set_handler_locked(data, handle_level_irq); + break; + case SPRD_EIC_ASYNC: + switch (flow_type) { + case IRQ_TYPE_EDGE_RISING: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_FALLING: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_BOTH: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_HIGH: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); + irq_set_handler_locked(data, handle_level_irq); + break; + case IRQ_TYPE_LEVEL_LOW: + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); + irq_set_handler_locked(data, handle_level_irq); + break; + default: + return -ENOTSUPP; + } + break; + case SPRD_EIC_SYNC: + switch (flow_type) { + case IRQ_TYPE_EDGE_RISING: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_FALLING: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_EDGE_BOTH: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 1); + irq_set_handler_locked(data, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_HIGH: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); + irq_set_handler_locked(data, handle_level_irq); + break; + case IRQ_TYPE_LEVEL_LOW: + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); + irq_set_handler_locked(data, handle_level_irq); + break; + default: + return -ENOTSUPP; + } + default: + dev_err(chip->parent, "Unsupported EIC type.\n"); + return -ENOTSUPP; + } + + return 0; +} + +static int sprd_eic_match_chip_by_type(struct gpio_chip *chip, void *data) +{ + enum sprd_eic_type type = *(enum sprd_eic_type *)data; + + return !strcmp(chip->label, sprd_eic_label_name[type]); +} + +static void sprd_eic_handle_one_type(struct gpio_chip *chip) +{ + struct sprd_eic *sprd_eic = gpiochip_get_data(chip); + u32 bank, n, girq; + + for (bank = 0; bank * SPRD_EIC_PER_BANK_NR < chip->ngpio; bank++) { + void __iomem *base = sprd_eic_offset_base(sprd_eic, bank); + unsigned long reg; + + switch (sprd_eic->type) { + case SPRD_EIC_DEBOUNCE: + reg = readl_relaxed(base + SPRD_EIC_DBNC_MIS) & + SPRD_EIC_DATA_MASK; + break; + case SPRD_EIC_LATCH: + reg = readl_relaxed(base + SPRD_EIC_LATCH_INTMSK) & + SPRD_EIC_DATA_MASK; + break; + case SPRD_EIC_ASYNC: + reg = readl_relaxed(base + SPRD_EIC_ASYNC_INTMSK) & + SPRD_EIC_DATA_MASK; + break; + case SPRD_EIC_SYNC: + reg = readl_relaxed(base + SPRD_EIC_SYNC_INTMSK) & + SPRD_EIC_DATA_MASK; + break; + default: + dev_err(chip->parent, "Unsupported EIC type.\n"); + return; + } + + for_each_set_bit(n, ®, SPRD_EIC_PER_BANK_NR) { + girq = irq_find_mapping(chip->irq.domain, + bank * SPRD_EIC_PER_BANK_NR + n); + + generic_handle_irq(girq); + } + } +} + +static void sprd_eic_irq_handler(struct irq_desc *desc) +{ + struct irq_chip *ic = irq_desc_get_chip(desc); + struct gpio_chip *chip; + enum sprd_eic_type type; + + chained_irq_enter(ic, desc); + + /* + * Since the digital-chip EIC 4 sub-modules (debounce, latch, async + * and sync) share one same interrupt line, we should iterate each + * EIC module to check if there are EIC interrupts were triggered. + */ + for (type = SPRD_EIC_DEBOUNCE; type < SPRD_EIC_MAX; type++) { + chip = gpiochip_find(&type, sprd_eic_match_chip_by_type); + if (!chip) + continue; + + sprd_eic_handle_one_type(chip); + } + + chained_irq_exit(ic, desc); +} + +static int sprd_eic_probe(struct platform_device *pdev) +{ + const struct sprd_eic_variant_data *pdata; + struct gpio_irq_chip *irq; + struct sprd_eic *sprd_eic; + struct resource *res; + int ret, i; + + pdata = of_device_get_match_data(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "No matching driver data found.\n"); + return -EINVAL; + } + + sprd_eic = devm_kzalloc(&pdev->dev, sizeof(*sprd_eic), GFP_KERNEL); + if (!sprd_eic) + return -ENOMEM; + + spin_lock_init(&sprd_eic->lock); + sprd_eic->type = pdata->type; + + sprd_eic->irq = platform_get_irq(pdev, 0); + if (sprd_eic->irq < 0) { + dev_err(&pdev->dev, "Failed to get EIC interrupt.\n"); + return sprd_eic->irq; + } + + for (i = 0; i < SPRD_EIC_MAX_BANK; i++) { + /* + * We can have maximum 3 banks EICs, and each EIC has + * its own base address. But some platform maybe only + * have one bank EIC, thus base[1] and base[2] can be + * optional. + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) + continue; + + sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(sprd_eic->base[i])) + return PTR_ERR(sprd_eic->base[i]); + } + + sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type]; + sprd_eic->chip.ngpio = pdata->num_eics; + sprd_eic->chip.base = -1; + sprd_eic->chip.parent = &pdev->dev; + sprd_eic->chip.of_node = pdev->dev.of_node; + sprd_eic->chip.direction_input = sprd_eic_direction_input; + switch (sprd_eic->type) { + case SPRD_EIC_DEBOUNCE: + sprd_eic->chip.request = sprd_eic_request; + sprd_eic->chip.free = sprd_eic_free; + sprd_eic->chip.set_config = sprd_eic_set_config; + sprd_eic->chip.set = sprd_eic_set; + /* fall-through */ + case SPRD_EIC_ASYNC: + /* fall-through */ + case SPRD_EIC_SYNC: + sprd_eic->chip.get = sprd_eic_get; + break; + case SPRD_EIC_LATCH: + /* fall-through */ + default: + break; + } + + sprd_eic->intc.name = dev_name(&pdev->dev); + sprd_eic->intc.irq_ack = sprd_eic_irq_ack; + sprd_eic->intc.irq_mask = sprd_eic_irq_mask; + sprd_eic->intc.irq_unmask = sprd_eic_irq_unmask; + sprd_eic->intc.irq_set_type = sprd_eic_irq_set_type; + sprd_eic->intc.flags = IRQCHIP_SKIP_SET_WAKE; + + irq = &sprd_eic->chip.irq; + irq->chip = &sprd_eic->intc; + irq->handler = handle_bad_irq; + irq->default_type = IRQ_TYPE_NONE; + irq->parent_handler = sprd_eic_irq_handler; + irq->parent_handler_data = sprd_eic; + irq->num_parents = 1; + irq->parents = &sprd_eic->irq; + + ret = devm_gpiochip_add_data(&pdev->dev, &sprd_eic->chip, sprd_eic); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip %d.\n", ret); + return ret; + } + + platform_set_drvdata(pdev, sprd_eic); + return 0; +} + +static const struct of_device_id sprd_eic_of_match[] = { + { + .compatible = "sprd,sc9860-eic-debounce", + .data = &sc9860_eic_dbnc_data, + }, + { + .compatible = "sprd,sc9860-eic-latch", + .data = &sc9860_eic_latch_data, + }, + { + .compatible = "sprd,sc9860-eic-async", + .data = &sc9860_eic_async_data, + }, + { + .compatible = "sprd,sc9860-eic-sync", + .data = &sc9860_eic_sync_data, + }, + { + /* end of list */ + } +}; +MODULE_DEVICE_TABLE(of, sprd_eic_of_match); + +static struct platform_driver sprd_eic_driver = { + .probe = sprd_eic_probe, + .driver = { + .name = "sprd-eic", + .of_match_table = sprd_eic_of_match, + }, +}; + +module_platform_driver(sprd_eic_driver); + +MODULE_DESCRIPTION("Spreadtrum EIC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 348f3cde84ab5b1f53cd3c0eaac1ca99a4dcb148 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 5 Mar 2018 10:56:52 +0800 Subject: gpio: Add Spreadtrum PMIC EIC driver support The Spreadtrum PMIC EIC controller contains only one bank of debounce EIC, and this bank contains 16 EICs. Each EIC can only be used as input mode, as well as supporting the debounce and the capability to trigger interrupts when detecting input signals. Signed-off-by: Baolin Wang Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 8 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-pmic-eic-sprd.c | 330 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 drivers/gpio/gpio-pmic-eic-sprd.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 380aa90501ea..7201cb508870 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -400,6 +400,14 @@ config GPIO_PL061 help Say yes here to support the PrimeCell PL061 GPIO device +config GPIO_PMIC_EIC_SPRD + tristate "Spreadtrum PMIC EIC support" + depends on MFD_SC27XX_PMIC || COMPILE_TEST + depends on OF_GPIO + select GPIOLIB_IRQCHIP + help + Say yes here to support Spreadtrum PMIC EIC device. + config GPIO_PXA bool "PXA GPIO support" depends on ARCH_PXA || ARCH_MMP diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 2437f3596934..684141a96c3f 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o +obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o diff --git a/drivers/gpio/gpio-pmic-eic-sprd.c b/drivers/gpio/gpio-pmic-eic-sprd.c new file mode 100644 index 000000000000..66d68d991162 --- /dev/null +++ b/drivers/gpio/gpio-pmic-eic-sprd.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Spreadtrum Communications Inc. + * Copyright (C) 2018 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* EIC registers definition */ +#define SPRD_PMIC_EIC_DATA 0x0 +#define SPRD_PMIC_EIC_DMSK 0x4 +#define SPRD_PMIC_EIC_IEV 0x14 +#define SPRD_PMIC_EIC_IE 0x18 +#define SPRD_PMIC_EIC_RIS 0x1c +#define SPRD_PMIC_EIC_MIS 0x20 +#define SPRD_PMIC_EIC_IC 0x24 +#define SPRD_PMIC_EIC_TRIG 0x28 +#define SPRD_PMIC_EIC_CTRL0 0x40 + +/* + * The PMIC EIC controller only has one bank, and each bank now can contain + * 16 EICs. + */ +#define SPRD_PMIC_EIC_PER_BANK_NR 16 +#define SPRD_PMIC_EIC_NR SPRD_PMIC_EIC_PER_BANK_NR +#define SPRD_PMIC_EIC_DATA_MASK GENMASK(15, 0) +#define SPRD_PMIC_EIC_BIT(x) ((x) & (SPRD_PMIC_EIC_PER_BANK_NR - 1)) +#define SPRD_PMIC_EIC_DBNC_MASK GENMASK(11, 0) + +/* + * These registers are modified under the irq bus lock and cached to avoid + * unnecessary writes in bus_sync_unlock. + */ +enum { + REG_IEV, + REG_IE, + REG_TRIG, + CACHE_NR_REGS +}; + +/** + * struct sprd_pmic_eic - PMIC EIC controller + * @chip: the gpio_chip structure. + * @intc: the irq_chip structure. + * @regmap: the regmap from the parent device. + * @offset: the EIC controller's offset address of the PMIC. + * @reg: the array to cache the EIC registers. + * @buslock: for bus lock/sync and unlock. + * @irq: the interrupt number of the PMIC EIC conteroller. + */ +struct sprd_pmic_eic { + struct gpio_chip chip; + struct irq_chip intc; + struct regmap *map; + u32 offset; + u8 reg[CACHE_NR_REGS]; + struct mutex buslock; + int irq; +}; + +static void sprd_pmic_eic_update(struct gpio_chip *chip, unsigned int offset, + u16 reg, unsigned int val) +{ + struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + u32 shift = SPRD_PMIC_EIC_BIT(offset); + + regmap_update_bits(pmic_eic->map, pmic_eic->offset + reg, + BIT(shift), val << shift); +} + +static int sprd_pmic_eic_read(struct gpio_chip *chip, unsigned int offset, + u16 reg) +{ + struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + u32 value; + int ret; + + ret = regmap_read(pmic_eic->map, pmic_eic->offset + reg, &value); + if (ret) + return ret; + + return !!(value & BIT(SPRD_PMIC_EIC_BIT(offset))); +} + +static int sprd_pmic_eic_request(struct gpio_chip *chip, unsigned int offset) +{ + sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_DMSK, 1); + return 0; +} + +static void sprd_pmic_eic_free(struct gpio_chip *chip, unsigned int offset) +{ + sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_DMSK, 0); +} + +static int sprd_pmic_eic_get(struct gpio_chip *chip, unsigned int offset) +{ + return sprd_pmic_eic_read(chip, offset, SPRD_PMIC_EIC_DATA); +} + +static int sprd_pmic_eic_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + /* EICs are always input, nothing need to do here. */ + return 0; +} + +static void sprd_pmic_eic_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + /* EICs are always input, nothing need to do here. */ +} + +static int sprd_pmic_eic_set_debounce(struct gpio_chip *chip, + unsigned int offset, + unsigned int debounce) +{ + struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + u32 reg, value; + int ret; + + reg = SPRD_PMIC_EIC_CTRL0 + SPRD_PMIC_EIC_BIT(offset) * 0x4; + ret = regmap_read(pmic_eic->map, pmic_eic->offset + reg, &value); + if (ret) + return ret; + + value &= ~SPRD_PMIC_EIC_DBNC_MASK; + value |= (debounce / 1000) & SPRD_PMIC_EIC_DBNC_MASK; + return regmap_write(pmic_eic->map, pmic_eic->offset + reg, value); +} + +static int sprd_pmic_eic_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + unsigned long param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); + + if (param == PIN_CONFIG_INPUT_DEBOUNCE) + return sprd_pmic_eic_set_debounce(chip, offset, arg); + + return -ENOTSUPP; +} + +static void sprd_pmic_eic_irq_mask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + + pmic_eic->reg[REG_IE] = 0; + pmic_eic->reg[REG_TRIG] = 0; +} + +static void sprd_pmic_eic_irq_unmask(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + + pmic_eic->reg[REG_IE] = 1; + pmic_eic->reg[REG_TRIG] = 1; +} + +static int sprd_pmic_eic_irq_set_type(struct irq_data *data, + unsigned int flow_type) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + + switch (flow_type) { + case IRQ_TYPE_LEVEL_HIGH: + pmic_eic->reg[REG_IEV] = 1; + break; + case IRQ_TYPE_LEVEL_LOW: + pmic_eic->reg[REG_IEV] = 0; + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static void sprd_pmic_eic_bus_lock(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + + mutex_lock(&pmic_eic->buslock); +} + +static void sprd_pmic_eic_bus_sync_unlock(struct irq_data *data) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + u32 offset = irqd_to_hwirq(data); + + /* Set irq type */ + sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, + pmic_eic->reg[REG_IEV]); + /* Set irq unmask */ + sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IE, + pmic_eic->reg[REG_IE]); + /* Generate trigger start pulse for debounce EIC */ + sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_TRIG, + pmic_eic->reg[REG_TRIG]); + + mutex_unlock(&pmic_eic->buslock); +} + +static irqreturn_t sprd_pmic_eic_irq_handler(int irq, void *data) +{ + struct sprd_pmic_eic *pmic_eic = data; + struct gpio_chip *chip = &pmic_eic->chip; + unsigned long status; + u32 n, girq, val; + int ret; + + ret = regmap_read(pmic_eic->map, pmic_eic->offset + SPRD_PMIC_EIC_MIS, + &val); + if (ret) + return IRQ_RETVAL(ret); + + status = val & SPRD_PMIC_EIC_DATA_MASK; + + for_each_set_bit(n, &status, chip->ngpio) { + /* Clear the interrupt */ + sprd_pmic_eic_update(chip, n, SPRD_PMIC_EIC_IC, 1); + + girq = irq_find_mapping(chip->irq.domain, n); + handle_nested_irq(girq); + } + + return IRQ_HANDLED; +} + +static int sprd_pmic_eic_probe(struct platform_device *pdev) +{ + struct gpio_irq_chip *irq; + struct sprd_pmic_eic *pmic_eic; + int ret; + + pmic_eic = devm_kzalloc(&pdev->dev, sizeof(*pmic_eic), GFP_KERNEL); + if (!pmic_eic) + return -ENOMEM; + + mutex_init(&pmic_eic->buslock); + + pmic_eic->irq = platform_get_irq(pdev, 0); + if (pmic_eic->irq < 0) { + dev_err(&pdev->dev, "Failed to get PMIC EIC interrupt.\n"); + return pmic_eic->irq; + } + + pmic_eic->map = dev_get_regmap(pdev->dev.parent, NULL); + if (!pmic_eic->map) + return -ENODEV; + + ret = of_property_read_u32(pdev->dev.of_node, "reg", &pmic_eic->offset); + if (ret) { + dev_err(&pdev->dev, "Failed to get PMIC EIC base address.\n"); + return ret; + } + + ret = devm_request_threaded_irq(&pdev->dev, pmic_eic->irq, NULL, + sprd_pmic_eic_irq_handler, + IRQF_TRIGGER_LOW | + IRQF_ONESHOT | IRQF_NO_SUSPEND, + dev_name(&pdev->dev), pmic_eic); + if (ret) { + dev_err(&pdev->dev, "Failed to request PMIC EIC IRQ.\n"); + return ret; + } + + pmic_eic->chip.label = dev_name(&pdev->dev); + pmic_eic->chip.ngpio = SPRD_PMIC_EIC_NR; + pmic_eic->chip.base = -1; + pmic_eic->chip.parent = &pdev->dev; + pmic_eic->chip.of_node = pdev->dev.of_node; + pmic_eic->chip.direction_input = sprd_pmic_eic_direction_input; + pmic_eic->chip.request = sprd_pmic_eic_request; + pmic_eic->chip.free = sprd_pmic_eic_free; + pmic_eic->chip.set_config = sprd_pmic_eic_set_config; + pmic_eic->chip.set = sprd_pmic_eic_set; + pmic_eic->chip.get = sprd_pmic_eic_get; + + pmic_eic->intc.name = dev_name(&pdev->dev); + pmic_eic->intc.irq_mask = sprd_pmic_eic_irq_mask; + pmic_eic->intc.irq_unmask = sprd_pmic_eic_irq_unmask; + pmic_eic->intc.irq_set_type = sprd_pmic_eic_irq_set_type; + pmic_eic->intc.irq_bus_lock = sprd_pmic_eic_bus_lock; + pmic_eic->intc.irq_bus_sync_unlock = sprd_pmic_eic_bus_sync_unlock; + pmic_eic->intc.flags = IRQCHIP_SKIP_SET_WAKE; + + irq = &pmic_eic->chip.irq; + irq->chip = &pmic_eic->intc; + irq->threaded = true; + + ret = devm_gpiochip_add_data(&pdev->dev, &pmic_eic->chip, pmic_eic); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip %d.\n", ret); + return ret; + } + + platform_set_drvdata(pdev, pmic_eic); + return 0; +} + +static const struct of_device_id sprd_pmic_eic_of_match[] = { + { .compatible = "sprd,sc27xx-eic", }, + { /* end of list */ } +}; +MODULE_DEVICE_TABLE(of, sprd_pmic_eic_of_match); + +static struct platform_driver sprd_pmic_eic_driver = { + .probe = sprd_pmic_eic_probe, + .driver = { + .name = "sprd-pmic-eic", + .of_match_table = sprd_pmic_eic_of_match, + }, +}; + +module_platform_driver(sprd_pmic_eic_driver); + +MODULE_DESCRIPTION("Spreadtrum PMIC EIC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3