diff options
Diffstat (limited to 'drivers/gpio')
67 files changed, 1609 insertions, 373 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7ef68e65918..50cc557abe4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -110,7 +110,7 @@ comment "Memory mapped GPIO drivers:" config GPIO_CLPS711X tristate "CLPS711X GPIO support" - depends on ARCH_CLPS711X + depends on ARCH_CLPS711X || COMPILE_TEST select GPIO_GENERIC help Say yes here to support GPIO on CLPS711X SoCs. @@ -156,6 +156,13 @@ config GPIO_F7188X To compile this driver as a module, choose M here: the module will be called f7188x-gpio. +config GPIO_MOXART + bool "MOXART GPIO support" + depends on ARCH_MOXART + help + Select this option to enable GPIO driver for + MOXA ART SoC devices. + config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx @@ -237,6 +244,15 @@ config GPIO_SAMSUNG Legacy GPIO support. Use only for platforms without support for pinctrl. +config GPIO_SCH311X + tristate "SMSC SCH311x SuperI/O GPIO" + help + Driver to enable the GPIOs found on SMSC SMSC SCH3112, SCH3114 and + SCH3116 "Super I/O" chipsets. + + To compile this driver as a module, choose M here: the module will + be called gpio-sch311x. + config GPIO_SPEAR_SPICS bool "ST SPEAr13xx SPI Chip Select as GPIO support" depends on PLAT_SPEAR @@ -281,6 +297,15 @@ config GPIO_XILINX help Say yes here to support the Xilinx FPGA GPIO device +config GPIO_XTENSA + bool "Xtensa GPIO32 support" + depends on XTENSA + depends on HAVE_XTENSA_GPIO32 + depends on !SMP + help + Say yes here to support the Xtensa internal GPIO32 IMPWIRE (input) + and EXPSTATE (output) ports + config GPIO_VR41XX tristate "NEC VR4100 series General-purpose I/O Uint support" depends on CPU_VR41XX @@ -353,7 +378,7 @@ config GPIO_GE_FPGA board computers. config GPIO_LYNXPOINT - bool "Intel Lynxpoint GPIO support" + tristate "Intel Lynxpoint GPIO support" depends on ACPI && X86 select IRQ_DOMAIN help @@ -700,11 +725,13 @@ config GPIO_MAX7301 config GPIO_MCP23S08 tristate "Microchip MCP23xxx I/O expander" + depends on OF_GPIO depends on (SPI_MASTER && !I2C) || I2C help SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 I/O expanders. This provides a GPIO interface supporting inputs and outputs. + The I2C versions of the chips can be used as interrupt-controller. config GPIO_MC33880 tristate "Freescale MC33880 high-side/low-side switch" @@ -715,10 +742,10 @@ config GPIO_MC33880 config GPIO_74X164 tristate "74x164 serial-in/parallel-out 8-bits shift register" - depends on SPI_MASTER + depends on SPI_MASTER && OF help - Platform driver for 74x164 compatible serial-in/parallel-out - 8-outputs shift registers. This driver can be used to provide access + Driver for 74x164 compatible serial-in/parallel-out 8-outputs + shift registers. This driver can be used to provide access to more gpio outputs. comment "AC97 GPIO expanders:" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 95927b61c20..0248471402e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o +obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o @@ -68,6 +69,7 @@ obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o obj-$(CONFIG_GPIO_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o 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_STA2X11) += gpio-sta2x11.o @@ -96,3 +98,4 @@ obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o +obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 1e04bf91328..e4ae29824c3 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/mutex.h> #include <linux/spi/spi.h> -#include <linux/spi/74x164.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/slab.h> @@ -21,7 +20,6 @@ #define GEN_74X164_NUMBER_GPIOS 8 struct gen_74x164_chip { - struct spi_device *spi; u8 *buffer; struct gpio_chip gpio_chip; struct mutex lock; @@ -35,6 +33,7 @@ static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc) static int __gen_74x164_write_config(struct gen_74x164_chip *chip) { + struct spi_device *spi = to_spi_device(chip->gpio_chip.dev); struct spi_message message; struct spi_transfer *msg_buf; int i, ret = 0; @@ -55,12 +54,12 @@ static int __gen_74x164_write_config(struct gen_74x164_chip *chip) * byte of the buffer will end up in the last register. */ for (i = chip->registers - 1; i >= 0; i--) { - msg_buf[i].tx_buf = chip->buffer +i; + msg_buf[i].tx_buf = chip->buffer + i; msg_buf[i].len = sizeof(u8); spi_message_add_tail(msg_buf + i, &message); } - ret = spi_sync(chip->spi, &message); + ret = spi_sync(spi, &message); kfree(msg_buf); @@ -108,14 +107,8 @@ static int gen_74x164_direction_output(struct gpio_chip *gc, static int gen_74x164_probe(struct spi_device *spi) { struct gen_74x164_chip *chip; - struct gen_74x164_chip_platform_data *pdata; int ret; - if (!spi->dev.of_node) { - dev_err(&spi->dev, "No device tree data available.\n"); - return -EINVAL; - } - /* * bits_per_word cannot be configured in platform data */ @@ -129,40 +122,32 @@ static int gen_74x164_probe(struct spi_device *spi) if (!chip) return -ENOMEM; - pdata = dev_get_platdata(&spi->dev); - if (pdata && pdata->base) - chip->gpio_chip.base = pdata->base; - else - chip->gpio_chip.base = -1; - - mutex_init(&chip->lock); - spi_set_drvdata(spi, chip); - chip->spi = spi; - chip->gpio_chip.label = spi->modalias; chip->gpio_chip.direction_output = gen_74x164_direction_output; chip->gpio_chip.get = gen_74x164_get_value; chip->gpio_chip.set = gen_74x164_set_value; + chip->gpio_chip.base = -1; - if (of_property_read_u32(spi->dev.of_node, "registers-number", &chip->registers)) { - dev_err(&spi->dev, "Missing registers-number property in the DT.\n"); - ret = -EINVAL; - goto exit_destroy; + if (of_property_read_u32(spi->dev.of_node, "registers-number", + &chip->registers)) { + dev_err(&spi->dev, + "Missing registers-number property in the DT.\n"); + return -EINVAL; } chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers; chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL); - if (!chip->buffer) { - ret = -ENOMEM; - goto exit_destroy; - } + if (!chip->buffer) + return -ENOMEM; - chip->gpio_chip.can_sleep = 1; + chip->gpio_chip.can_sleep = true; chip->gpio_chip.dev = &spi->dev; chip->gpio_chip.owner = THIS_MODULE; + mutex_init(&chip->lock); + ret = __gen_74x164_write_config(chip); if (ret) { dev_err(&spi->dev, "Failed writing: %d\n", ret); @@ -170,31 +155,23 @@ static int gen_74x164_probe(struct spi_device *spi) } ret = gpiochip_add(&chip->gpio_chip); - if (ret) - goto exit_destroy; - - return ret; + if (!ret) + return 0; exit_destroy: mutex_destroy(&chip->lock); + return ret; } static int gen_74x164_remove(struct spi_device *spi) { - struct gen_74x164_chip *chip; + struct gen_74x164_chip *chip = spi_get_drvdata(spi); int ret; - chip = spi_get_drvdata(spi); - if (chip == NULL) - return -ENODEV; - ret = gpiochip_remove(&chip->gpio_chip); if (!ret) mutex_destroy(&chip->lock); - else - dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n", - ret); return ret; } diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index b204033acae..6fc6206b38b 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -260,7 +260,7 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) chip->direction_output = adnp_gpio_direction_output; chip->get = adnp_gpio_get; chip->set = adnp_gpio_set; - chip->can_sleep = 1; + chip->can_sleep = true; if (IS_ENABLED(CONFIG_DEBUG_FS)) chip->dbg_show = adnp_gpio_dbg_show; @@ -408,6 +408,27 @@ static void adnp_irq_bus_unlock(struct irq_data *data) mutex_unlock(&adnp->irq_lock); } +static unsigned int adnp_irq_startup(struct irq_data *data) +{ + struct adnp *adnp = irq_data_get_irq_chip_data(data); + + if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) + dev_err(adnp->gpio.dev, + "unable to lock HW IRQ %lu for IRQ\n", + data->hwirq); + /* Satisfy the .enable semantics by unmasking the line */ + adnp_irq_unmask(data); + return 0; +} + +static void adnp_irq_shutdown(struct irq_data *data) +{ + struct adnp *adnp = irq_data_get_irq_chip_data(data); + + adnp_irq_mask(data); + gpio_unlock_as_irq(&adnp->gpio, data->hwirq); +} + static struct irq_chip adnp_irq_chip = { .name = "gpio-adnp", .irq_mask = adnp_irq_mask, @@ -415,6 +436,8 @@ static struct irq_chip adnp_irq_chip = { .irq_set_type = adnp_irq_set_type, .irq_bus_lock = adnp_irq_bus_lock, .irq_bus_sync_unlock = adnp_irq_bus_unlock, + .irq_startup = adnp_irq_startup, + .irq_shutdown = adnp_irq_shutdown, }; static int adnp_irq_map(struct irq_domain *domain, unsigned int irq, diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index 084337d5514..613265944e2 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -127,7 +127,7 @@ static int adp5520_gpio_probe(struct platform_device *pdev) gc->direction_output = adp5520_gpio_direction_output; gc->get = adp5520_gpio_get_value; gc->set = adp5520_gpio_set_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = pdata->gpio_start; gc->ngpio = gpios; diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 90fc4c99c02..3f190e68f97 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -380,7 +380,7 @@ static int adp5588_gpio_probe(struct i2c_client *client, gc->direction_output = adp5588_gpio_direction_output; gc->get = adp5588_gpio_get_value; gc->set = adp5588_gpio_set_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = pdata->gpio_start; gc->ngpio = ADP5588_MAXGPIO; diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index 710fafcdd1b..94e9992f890 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -60,7 +60,7 @@ * register a pci_driver, because someone else might one day * want to register another driver on the same PCI id. */ -static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = { +static const struct pci_device_id pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS), 0 }, { 0, }, /* terminate list */ }; diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index dceb5dcf9d1..29bdff55898 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -91,7 +91,7 @@ static struct gpio_chip template_chip = { .get = arizona_gpio_get, .direction_output = arizona_gpio_direction_out, .set = arizona_gpio_set, - .can_sleep = 1, + .can_sleep = true, }; static int arizona_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 54c18c220a6..233d088ac59 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -449,12 +449,34 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } +static unsigned int bcm_kona_gpio_irq_startup(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) + dev_err(kona_gpio->gpio_chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + bcm_kona_gpio_irq_unmask(d); + return 0; +} + +static void bcm_kona_gpio_irq_shutdown(struct irq_data *d) +{ + struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); + + bcm_kona_gpio_irq_mask(d); + gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq); +} + static struct irq_chip bcm_gpio_irq_chip = { .name = "bcm-kona-gpio", .irq_ack = bcm_kona_gpio_irq_ack, .irq_mask = bcm_kona_gpio_irq_mask, .irq_unmask = bcm_kona_gpio_irq_unmask, .irq_set_type = bcm_kona_gpio_irq_set_type, + .irq_startup = bcm_kona_gpio_irq_startup, + .irq_shutdown = bcm_kona_gpio_irq_shutdown, }; static struct __initconst of_device_id bcm_kona_gpio_of_match[] = { diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index 9dfe36fd8ba..ecb3ca2d1d1 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -169,7 +169,7 @@ static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg) c->dbg_show = NULL; c->base = modparam_gpiobase; c->ngpio = BT8XXGPIO_NR_GPIOS; - c->can_sleep = 0; + c->can_sleep = false; } static int bt8xxgpio_probe(struct pci_dev *dev, @@ -308,7 +308,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev) #define bt8xxgpio_resume NULL #endif /* CONFIG_PM */ -static DEFINE_PCI_DEVICE_TABLE(bt8xxgpio_pci_tbl) = { +static const struct pci_device_id bt8xxgpio_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) }, { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) }, { PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) }, diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index 0924f20fa47..d3550274b8f 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -77,7 +77,7 @@ static int clps711x_gpio_remove(struct platform_device *pdev) return bgpio_remove(bgc); } -static const struct of_device_id clps711x_gpio_ids[] = { +static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = { { .compatible = "cirrus,clps711x-gpio" }, { } }; @@ -87,7 +87,7 @@ static struct platform_driver clps711x_gpio_driver = { .driver = { .name = "clps711x-gpio", .owner = THIS_MODULE, - .of_match_table = clps711x_gpio_ids, + .of_match_table = of_match_ptr(clps711x_gpio_ids), }, .probe = clps711x_gpio_probe, .remove = clps711x_gpio_remove, diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 9b77dc05d4a..416cdf786b0 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -200,7 +200,7 @@ static struct gpio_chip reference_gp = { .direction_input = da9052_gpio_direction_input, .direction_output = da9052_gpio_direction_output, .to_irq = da9052_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, .ngpio = 16, .base = -1, }; diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index 7ef0820032b..f992997bc30 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -134,7 +134,7 @@ static struct gpio_chip reference_gp = { .direction_input = da9055_gpio_direction_input, .direction_output = da9055_gpio_direction_output, .to_irq = da9055_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, .ngpio = 3, .base = -1, }; diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index ec190361bf2..1e98a987396 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -99,6 +99,27 @@ static void em_gio_irq_enable(struct irq_data *d) em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d))); } +static unsigned int em_gio_irq_startup(struct irq_data *d) +{ + struct em_gio_priv *p = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) + dev_err(p->gpio_chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + em_gio_irq_enable(d); + return 0; +} + +static void em_gio_irq_shutdown(struct irq_data *d) +{ + struct em_gio_priv *p = irq_data_get_irq_chip_data(d); + + em_gio_irq_disable(d); + gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)); +} + + #define GIO_ASYNC(x) (x + 8) static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = { @@ -328,6 +349,7 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->request = em_gio_request; gpio_chip->free = em_gio_free; gpio_chip->label = name; + gpio_chip->dev = &pdev->dev; gpio_chip->owner = THIS_MODULE; gpio_chip->base = pdata->gpio_base; gpio_chip->ngpio = pdata->number_of_pins; @@ -336,10 +358,10 @@ static int em_gio_probe(struct platform_device *pdev) irq_chip->name = name; irq_chip->irq_mask = em_gio_irq_disable; irq_chip->irq_unmask = em_gio_irq_enable; - irq_chip->irq_enable = em_gio_irq_enable; - irq_chip->irq_disable = em_gio_irq_disable; irq_chip->irq_set_type = em_gio_irq_set_type; - irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; + irq_chip->irq_startup = em_gio_irq_startup; + irq_chip->irq_shutdown = em_gio_irq_shutdown; + irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, pdata->number_of_pins, diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 9cb8320e118..8f73ee09373 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -135,6 +135,7 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value); .set = f7188x_gpio_set, \ .base = _base, \ .ngpio = _ngpio, \ + .can_sleep = true, \ }, \ .regbase = _regbase, \ } diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 814addb62d2..f5bf3c38bca 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -252,7 +252,7 @@ static void ichx_gpiolib_setup(struct gpio_chip *chip) chip->direction_output = ichx_gpio_direction_output; chip->base = modparam_gpiobase; chip->ngpio = ichx_priv.desc->ngpio; - chip->can_sleep = 0; + chip->can_sleep = false; chip->dbg_show = NULL; } diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index be803af658a..d1b50ef5fab 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -235,11 +235,33 @@ static void intel_mid_irq_mask(struct irq_data *d) { } +static unsigned int intel_mid_irq_startup(struct irq_data *d) +{ + struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) + dev_err(priv->chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + intel_mid_irq_unmask(d); + return 0; +} + +static void intel_mid_irq_shutdown(struct irq_data *d) +{ + struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); + + intel_mid_irq_mask(d); + gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d)); +} + static struct irq_chip intel_mid_irqchip = { .name = "INTEL_MID-GPIO", .irq_mask = intel_mid_irq_mask, .irq_unmask = intel_mid_irq_unmask, .irq_set_type = intel_mid_irq_type, + .irq_startup = intel_mid_irq_startup, + .irq_shutdown = intel_mid_irq_shutdown, }; static const struct intel_mid_gpio_ddata gpio_lincroft = { @@ -275,7 +297,7 @@ static const struct intel_mid_gpio_ddata gpio_tangier = { .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, }; -static DEFINE_PCI_DEVICE_TABLE(intel_gpio_ids) = { +static const struct pci_device_id intel_gpio_ids[] = { { /* Lincroft */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), @@ -358,8 +380,7 @@ static int intel_gpio_irq_map(struct irq_domain *d, unsigned int irq, { struct intel_mid_gpio *priv = d->host_data; - irq_set_chip_and_handler_name(irq, &intel_mid_irqchip, - handle_simple_irq, "demux"); + irq_set_chip_and_handler(irq, &intel_mid_irqchip, handle_simple_irq); irq_set_chip_data(irq, priv); irq_set_irq_type(irq, IRQ_TYPE_NONE); @@ -418,6 +439,7 @@ static int intel_gpio_probe(struct pci_dev *pdev, priv->reg_base = pcim_iomap_table(pdev)[0]; priv->chip.label = dev_name(&pdev->dev); + priv->chip.dev = &pdev->dev; priv->chip.request = intel_gpio_request; priv->chip.direction_input = intel_gpio_direction_input; priv->chip.direction_output = intel_gpio_direction_output; @@ -426,7 +448,7 @@ static int intel_gpio_probe(struct pci_dev *pdev, priv->chip.to_irq = intel_gpio_to_irq; priv->chip.base = gpio_base; priv->chip.ngpio = ddata->ngpio; - priv->chip.can_sleep = 0; + priv->chip.can_sleep = false; priv->pdev = pdev; spin_lock_init(&priv->lock); diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index efdc3924d7d..c6d88173f5a 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -167,7 +167,7 @@ static int kempld_gpio_probe(struct platform_device *pdev) chip->label = "gpio-kempld"; chip->owner = THIS_MODULE; chip->dev = dev; - chip->can_sleep = 1; + chip->can_sleep = true; if (pdata && pdata->gpio_base) chip->base = pdata->gpio_base; else diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c index a3ac66ea364..464a83de0d6 100644 --- a/drivers/gpio/gpio-ks8695.c +++ b/drivers/gpio/gpio-ks8695.c @@ -228,7 +228,7 @@ static struct gpio_chip ks8695_gpio_chip = { .to_irq = ks8695_gpio_to_irq, .base = 0, .ngpio = 16, - .can_sleep = 0, + .can_sleep = false, }; /* Register the GPIOs */ diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 2d5555decf0..225344d6640 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -25,10 +25,10 @@ #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/platform_data/gpio-lpc32xx.h> #include <mach/hardware.h> #include <mach/platform.h> -#include <mach/gpio-lpc32xx.h> #include <mach/irqs.h> #define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000) @@ -448,7 +448,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P0_GRP, .ngpio = LPC32XX_GPIO_P0_MAX, .names = gpio_p0_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p0, }, @@ -464,7 +464,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P1_GRP, .ngpio = LPC32XX_GPIO_P1_MAX, .names = gpio_p1_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p1, }, @@ -479,7 +479,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P2_GRP, .ngpio = LPC32XX_GPIO_P2_MAX, .names = gpio_p2_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p2, }, @@ -495,7 +495,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P3_GRP, .ngpio = LPC32XX_GPIO_P3_MAX, .names = gpio_p3_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p3, }, @@ -509,7 +509,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPI_P3_GRP, .ngpio = LPC32XX_GPI_P3_MAX, .names = gpi_p3_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p3, }, @@ -523,7 +523,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPO_P3_GRP, .ngpio = LPC32XX_GPO_P3_MAX, .names = gpo_p3_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p3, }, diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index a0804740a0b..66b18535b5a 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -301,6 +301,26 @@ static void lp_irq_disable(struct irq_data *d) spin_unlock_irqrestore(&lg->lock, flags); } +static unsigned int lp_irq_startup(struct irq_data *d) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) + dev_err(lg->chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + lp_irq_enable(d); + return 0; +} + +static void lp_irq_shutdown(struct irq_data *d) +{ + struct lp_gpio *lg = irq_data_get_irq_chip_data(d); + + lp_irq_disable(d); + gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d)); +} + static struct irq_chip lp_irqchip = { .name = "LP-GPIO", .irq_mask = lp_irq_mask, @@ -308,6 +328,8 @@ static struct irq_chip lp_irqchip = { .irq_enable = lp_irq_enable, .irq_disable = lp_irq_disable, .irq_set_type = lp_irq_type, + .irq_startup = lp_irq_startup, + .irq_shutdown = lp_irq_shutdown, .flags = IRQCHIP_SKIP_SET_WAKE, }; @@ -331,8 +353,7 @@ static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq, { struct lp_gpio *lg = d->host_data; - irq_set_chip_and_handler_name(irq, &lp_irqchip, handle_simple_irq, - "demux"); + irq_set_chip_and_handler(irq, &lp_irqchip, handle_simple_irq); irq_set_chip_data(irq, lg); irq_set_irq_type(irq, IRQ_TYPE_NONE); @@ -392,7 +413,7 @@ static int lp_gpio_probe(struct platform_device *pdev) gc->set = lp_gpio_set; gc->base = -1; gc->ngpio = LP_NUM_GPIO; - gc->can_sleep = 0; + gc->can_sleep = false; gc->dev = dev; /* set up interrupts */ @@ -438,6 +459,7 @@ static const struct dev_pm_ops lp_gpio_pm_ops = { static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { { "INT33C7", 0 }, + { "INT3437", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); @@ -469,4 +491,15 @@ static int __init lp_gpio_init(void) return platform_driver_register(&lp_gpio_driver); } +static void __exit lp_gpio_exit(void) +{ + platform_driver_unregister(&lp_gpio_driver); +} + subsys_initcall(lp_gpio_init); +module_exit(lp_gpio_exit); + +MODULE_AUTHOR("Mathias Nyman (Intel)"); +MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp_gpio"); diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index f4f4ed19bdc..8672755f95c 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -188,7 +188,7 @@ int __max730x_probe(struct max7301 *ts) ts->chip.set = max7301_set; ts->chip.ngpio = PIN_NUMBER; - ts->chip.can_sleep = 1; + ts->chip.can_sleep = true; ts->chip.dev = dev; ts->chip.owner = THIS_MODULE; @@ -220,7 +220,6 @@ int __max730x_probe(struct max7301 *ts) return ret; exit_destroy: - dev_set_drvdata(dev, NULL); mutex_destroy(&ts->lock); return ret; } @@ -234,8 +233,6 @@ int __max730x_remove(struct device *dev) if (ts == NULL) return -ENODEV; - dev_set_drvdata(dev, NULL); - /* Power down the chip and disable IRQ output */ ts->write(dev, 0x04, 0x00); diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 91ad74dea8c..36cb290764b 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -564,7 +564,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip, gc->set = max732x_gpio_set_value; } gc->get = max732x_gpio_get_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = gpio_start; gc->ngpio = port; diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index c0b7835f513..553a80a5eaf 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -115,7 +115,7 @@ static int mc33880_probe(struct spi_device *spi) mc->chip.set = mc33880_set; mc->chip.base = pdata->base; mc->chip.ngpio = PIN_NUMBER; - mc->chip.can_sleep = 1; + mc->chip.can_sleep = true; mc->chip.dev = &spi->dev; mc->chip.owner = THIS_MODULE; diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c index 0ab700046a2..dce35ff00db 100644 --- a/drivers/gpio/gpio-mc9s08dz60.c +++ b/drivers/gpio/gpio-mc9s08dz60.c @@ -102,7 +102,7 @@ static int mc9s08dz60_probe(struct i2c_client *client, mc9s->chip.dev = &client->dev; mc9s->chip.owner = THIS_MODULE; mc9s->chip.ngpio = GPIO_NUM; - mc9s->chip.can_sleep = 1; + mc9s->chip.can_sleep = true; mc9s->chip.get = mc9s08dz60_get_value; mc9s->chip.set = mc9s08dz60_set_value; mc9s->chip.direction_output = mc9s08dz60_direction_output; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 2deb0c5e54a..1ac288ea810 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -1,5 +1,13 @@ /* - * MCP23S08 SPI/GPIO gpio expander driver + * MCP23S08 SPI/I2C GPIO gpio expander driver + * + * The inputs and outputs of the mcp23s08, mcp23s17, mcp23008 and mcp23017 are + * supported. + * For the I2C versions of the chips (mcp23008 and mcp23017) generation of + * interrupts is also supported. + * The hardware of the SPI versions of the chips (mcp23s08 and mcp23s17) is + * also capable of generating interrupts, but the linux driver does not + * support that yet. */ #include <linux/kernel.h> @@ -12,7 +20,8 @@ #include <linux/spi/mcp23s08.h> #include <linux/slab.h> #include <asm/byteorder.h> -#include <linux/of.h> +#include <linux/interrupt.h> +#include <linux/of_irq.h> #include <linux/of_device.h> /** @@ -34,6 +43,7 @@ #define MCP_DEFVAL 0x03 #define MCP_INTCON 0x04 #define MCP_IOCON 0x05 +# define IOCON_MIRROR (1 << 6) # define IOCON_SEQOP (1 << 5) # define IOCON_HAEN (1 << 3) # define IOCON_ODR (1 << 2) @@ -57,8 +67,14 @@ struct mcp23s08 { u8 addr; u16 cache[11]; + u16 irq_rise; + u16 irq_fall; + int irq; + bool irq_controller; /* lock protects the cached values */ struct mutex lock; + struct mutex irq_lock; + struct irq_domain *irq_domain; struct gpio_chip chip; @@ -77,6 +93,11 @@ struct mcp23s08_driver_data { struct mcp23s08 chip[]; }; +/* This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + /*----------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_I2C) @@ -316,6 +337,195 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) } /*----------------------------------------------------------------------*/ +static irqreturn_t mcp23s08_irq(int irq, void *data) +{ + struct mcp23s08 *mcp = data; + int intcap, intf, i; + unsigned int child_irq; + + mutex_lock(&mcp->lock); + intf = mcp->ops->read(mcp, MCP_INTF); + if (intf < 0) { + mutex_unlock(&mcp->lock); + return IRQ_HANDLED; + } + + mcp->cache[MCP_INTF] = intf; + + intcap = mcp->ops->read(mcp, MCP_INTCAP); + if (intcap < 0) { + mutex_unlock(&mcp->lock); + return IRQ_HANDLED; + } + + mcp->cache[MCP_INTCAP] = intcap; + mutex_unlock(&mcp->lock); + + + for (i = 0; i < mcp->chip.ngpio; i++) { + if ((BIT(i) & mcp->cache[MCP_INTF]) && + ((BIT(i) & intcap & mcp->irq_rise) || + (mcp->irq_fall & ~intcap & BIT(i)))) { + child_irq = irq_find_mapping(mcp->irq_domain, i); + handle_nested_irq(child_irq); + } + } + + return IRQ_HANDLED; +} + +static int mcp23s08_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); + + return irq_find_mapping(mcp->irq_domain, offset); +} + +static void mcp23s08_irq_mask(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + unsigned int pos = data->hwirq; + + mcp->cache[MCP_GPINTEN] &= ~BIT(pos); +} + +static void mcp23s08_irq_unmask(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + unsigned int pos = data->hwirq; + + mcp->cache[MCP_GPINTEN] |= BIT(pos); +} + +static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + unsigned int pos = data->hwirq; + int status = 0; + + if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + mcp->cache[MCP_INTCON] &= ~BIT(pos); + mcp->irq_rise |= BIT(pos); + mcp->irq_fall |= BIT(pos); + } else if (type & IRQ_TYPE_EDGE_RISING) { + mcp->cache[MCP_INTCON] &= ~BIT(pos); + mcp->irq_rise |= BIT(pos); + mcp->irq_fall &= ~BIT(pos); + } else if (type & IRQ_TYPE_EDGE_FALLING) { + mcp->cache[MCP_INTCON] &= ~BIT(pos); + mcp->irq_rise &= ~BIT(pos); + mcp->irq_fall |= BIT(pos); + } else + return -EINVAL; + + return status; +} + +static void mcp23s08_irq_bus_lock(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + + mutex_lock(&mcp->irq_lock); +} + +static void mcp23s08_irq_bus_unlock(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + + mutex_lock(&mcp->lock); + mcp->ops->write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]); + mcp->ops->write(mcp, MCP_DEFVAL, mcp->cache[MCP_DEFVAL]); + mcp->ops->write(mcp, MCP_INTCON, mcp->cache[MCP_INTCON]); + mutex_unlock(&mcp->lock); + mutex_unlock(&mcp->irq_lock); +} + +static unsigned int mcp23s08_irq_startup(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + + if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) + dev_err(mcp->chip.dev, + "unable to lock HW IRQ %lu for IRQ usage\n", + data->hwirq); + + mcp23s08_irq_unmask(data); + return 0; +} + +static void mcp23s08_irq_shutdown(struct irq_data *data) +{ + struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); + + mcp23s08_irq_mask(data); + gpio_unlock_as_irq(&mcp->chip, data->hwirq); +} + +static struct irq_chip mcp23s08_irq_chip = { + .name = "gpio-mcp23xxx", + .irq_mask = mcp23s08_irq_mask, + .irq_unmask = mcp23s08_irq_unmask, + .irq_set_type = mcp23s08_irq_set_type, + .irq_bus_lock = mcp23s08_irq_bus_lock, + .irq_bus_sync_unlock = mcp23s08_irq_bus_unlock, + .irq_startup = mcp23s08_irq_startup, + .irq_shutdown = mcp23s08_irq_shutdown, +}; + +static int mcp23s08_irq_setup(struct mcp23s08 *mcp) +{ + struct gpio_chip *chip = &mcp->chip; + int err, irq, j; + + mutex_init(&mcp->irq_lock); + + mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio, + &irq_domain_simple_ops, mcp); + if (!mcp->irq_domain) + return -ENODEV; + + err = devm_request_threaded_irq(chip->dev, mcp->irq, NULL, mcp23s08_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + dev_name(chip->dev), mcp); + if (err != 0) { + dev_err(chip->dev, "unable to request IRQ#%d: %d\n", + mcp->irq, err); + return err; + } + + chip->to_irq = mcp23s08_gpio_to_irq; + + for (j = 0; j < mcp->chip.ngpio; j++) { + irq = irq_create_mapping(mcp->irq_domain, j); + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_data(irq, mcp); + irq_set_chip(irq, &mcp23s08_irq_chip); + irq_set_nested_thread(irq, true); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + } + return 0; +} + +static void mcp23s08_irq_teardown(struct mcp23s08 *mcp) +{ + unsigned int irq, i; + + free_irq(mcp->irq, mcp); + + for (i = 0; i < mcp->chip.ngpio; i++) { + irq = irq_find_mapping(mcp->irq_domain, i); + if (irq > 0) + irq_dispose_mapping(irq); + } + + irq_domain_remove(mcp->irq_domain); +} + +/*----------------------------------------------------------------------*/ #ifdef CONFIG_DEBUG_FS @@ -370,10 +580,11 @@ done: /*----------------------------------------------------------------------*/ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, - void *data, unsigned addr, - unsigned type, unsigned base, unsigned pullups) + void *data, unsigned addr, unsigned type, + unsigned base, unsigned pullups) { int status; + bool mirror = false; mutex_init(&mcp->lock); @@ -425,20 +636,32 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, } mcp->chip.base = base; - mcp->chip.can_sleep = 1; + mcp->chip.can_sleep = true; mcp->chip.dev = dev; mcp->chip.owner = THIS_MODULE; /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, * and MCP_IOCON.HAEN = 1, so we work with all chips. */ + status = mcp->ops->read(mcp, MCP_IOCON); if (status < 0) goto fail; - if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) { + + mcp->irq_controller = of_property_read_bool(mcp->chip.of_node, + "interrupt-controller"); + if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017)) + mirror = of_property_read_bool(mcp->chip.of_node, + "microchip,irq-mirror"); + + if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) { /* mcp23s17 has IOCON twice, make sure they are in sync */ status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8)); status |= IOCON_HAEN | (IOCON_HAEN << 8); + status &= ~(IOCON_INTPOL | (IOCON_INTPOL << 8)); + if (mirror) + status |= IOCON_MIRROR | (IOCON_MIRROR << 8); + status = mcp->ops->write(mcp, MCP_IOCON, status); if (status < 0) goto fail; @@ -470,6 +693,16 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, } status = gpiochip_add(&mcp->chip); + if (status < 0) + goto fail; + + if (mcp->irq && mcp->irq_controller) { + status = mcp23s08_irq_setup(mcp); + if (status) { + mcp23s08_irq_teardown(mcp); + goto fail; + } + } fail: if (status < 0) dev_dbg(dev, "can't setup chip %d, --> %d\n", @@ -546,6 +779,7 @@ static int mcp230xx_probe(struct i2c_client *client, if (match || !pdata) { base = -1; pullups = 0; + client->irq = irq_of_parse_and_map(client->dev.of_node, 0); } else { if (!gpio_is_valid(pdata->base)) { dev_dbg(&client->dev, "invalid platform data\n"); @@ -559,6 +793,7 @@ static int mcp230xx_probe(struct i2c_client *client, if (!mcp) return -ENOMEM; + mcp->irq = client->irq; status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr, id->driver_data, base, pullups); if (status) @@ -579,6 +814,9 @@ static int mcp230xx_remove(struct i2c_client *client) struct mcp23s08 *mcp = i2c_get_clientdata(client); int status; + if (client->irq && mcp->irq_controller) + mcp23s08_irq_teardown(mcp); + status = gpiochip_remove(&mcp->chip); if (status == 0) kfree(mcp); @@ -640,7 +878,7 @@ static int mcp23s08_probe(struct spi_device *spi) match = of_match_device(of_match_ptr(mcp23s08_spi_of_match), &spi->dev); if (match) { - type = (int)match->data; + type = (int)(uintptr_t)match->data; status = of_property_read_u32(spi->dev.of_node, "microchip,spi-present-mask", &spi_present_mask); if (status) { diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 6da6d7667c6..d51329d23d3 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -242,7 +242,7 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port) gpio->dbg_show = NULL; gpio->base = -1; gpio->ngpio = num_port; - gpio->can_sleep = 0; + gpio->can_sleep = false; gpio->to_irq = ioh_gpio_to_irq; } @@ -596,7 +596,7 @@ static int ioh_gpio_resume(struct pci_dev *pdev) #define ioh_gpio_resume NULL #endif -static DEFINE_PCI_DEVICE_TABLE(ioh_gpio_pcidev_id) = { +static const struct pci_device_id ioh_gpio_pcidev_id[] = { { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) }, { 0, } }; diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c new file mode 100644 index 00000000000..2af990022cc --- /dev/null +++ b/drivers/gpio/gpio-moxart.c @@ -0,0 +1,156 @@ +/* + * MOXA ART SoCs GPIO driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen <jonas.jensen@gmail.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/bitops.h> + +#define GPIO_DATA_OUT 0x00 +#define GPIO_DATA_IN 0x04 +#define GPIO_PIN_DIRECTION 0x08 + +struct moxart_gpio_chip { + struct gpio_chip gpio; + void __iomem *base; +}; + +static inline struct moxart_gpio_chip *to_moxart_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct moxart_gpio_chip, gpio); +} + +static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(offset); +} + +static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(offset); +} + +static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; + + writel(readl(ioaddr) & ~BIT(offset), ioaddr); + return 0; +} + +static int moxart_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; + + writel(readl(ioaddr) | BIT(offset), ioaddr); + return 0; +} + +static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_DATA_OUT; + u32 reg = readl(ioaddr); + + if (value) + reg = reg | BIT(offset); + else + reg = reg & ~BIT(offset); + + + writel(reg, ioaddr); +} + +static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + u32 ret = readl(gc->base + GPIO_PIN_DIRECTION); + + if (ret & BIT(offset)) + return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset)); + else + return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset)); +} + +static struct gpio_chip moxart_template_chip = { + .label = "moxart-gpio", + .request = moxart_gpio_request, + .free = moxart_gpio_free, + .direction_input = moxart_gpio_direction_input, + .direction_output = moxart_gpio_direction_output, + .set = moxart_gpio_set, + .get = moxart_gpio_get, + .ngpio = 32, + .owner = THIS_MODULE, +}; + +static int moxart_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct moxart_gpio_chip *mgc; + int ret; + + mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL); + if (!mgc) { + dev_err(dev, "can't allocate GPIO chip container\n"); + return -ENOMEM; + } + mgc->gpio = moxart_template_chip; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mgc->base = devm_ioremap_resource(dev, res); + if (IS_ERR(mgc->base)) + return PTR_ERR(mgc->base); + + mgc->gpio.dev = dev; + + ret = gpiochip_add(&mgc->gpio); + if (ret) { + dev_err(dev, "%s: gpiochip_add failed\n", + dev->of_node->full_name); + return ret; + } + + return 0; +} + +static const struct of_device_id moxart_gpio_match[] = { + { .compatible = "moxa,moxart-gpio" }, + { } +}; + +static struct platform_driver moxart_gpio_driver = { + .driver = { + .name = "moxart-gpio", + .owner = THIS_MODULE, + .of_match_table = moxart_gpio_match, + }, + .probe = moxart_gpio_probe, +}; +module_platform_driver(moxart_gpio_driver); + +MODULE_DESCRIPTION("MOXART GPIO chip driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>"); diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c index d75eaa3a1dc..8f70ded82a2 100644 --- a/drivers/gpio/gpio-msic.c +++ b/drivers/gpio/gpio-msic.c @@ -292,7 +292,7 @@ static int platform_msic_gpio_probe(struct platform_device *pdev) mg->chip.to_irq = msic_gpio_to_irq; mg->chip.base = pdata->gpio_base; mg->chip.ngpio = MSIC_NUM_GPIO; - mg->chip.can_sleep = 1; + mg->chip.can_sleep = true; mg->chip.dev = dev; mutex_init(&mg->buslock); @@ -305,10 +305,9 @@ static int platform_msic_gpio_probe(struct platform_device *pdev) for (i = 0; i < mg->chip.ngpio; i++) { irq_set_chip_data(i + mg->irq_base, mg); - irq_set_chip_and_handler_name(i + mg->irq_base, - &msic_irqchip, - handle_simple_irq, - "demux"); + irq_set_chip_and_handler(i + mg->irq_base, + &msic_irqchip, + handle_simple_irq); } irq_set_chained_handler(mg->irq, msic_gpio_irq_handler); irq_set_handler_data(mg->irq, mg); diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 2baf0ddf7e0..a3351acd496 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -430,10 +430,11 @@ static int msm_gpio_probe(struct platform_device *pdev) return 0; } -static struct of_device_id msm_gpio_of_match[] = { +static const struct of_device_id msm_gpio_of_match[] = { { .compatible = "qcom,msm-gpio", }, { }, }; +MODULE_DEVICE_TABLE(of, msm_gpio_of_match); static int msm_gpio_remove(struct platform_device *dev) { diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index db3129043e6..3b1fd1ce460 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -600,7 +600,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.to_irq = mvebu_gpio_to_irq; mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK; mvchip->chip.ngpio = ngpios; - mvchip->chip.can_sleep = 0; + mvchip->chip.can_sleep = false; mvchip->chip.of_node = np; mvchip->chip.dbg_show = mvebu_gpio_dbg_show; @@ -676,7 +676,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); if (mvchip->irqbase < 0) { dev_err(&pdev->dev, "no irqs\n"); - return -ENOMEM; + return mvchip->irqbase; } gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase, diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 3307f6db3a9..db83b3c0a44 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -422,7 +422,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) port->irq_high = platform_get_irq(pdev, 1); port->irq = platform_get_irq(pdev, 0); if (port->irq < 0) - return -EINVAL; + return port->irq; /* disable the interrupt and clear the status */ writel(0, port->base + GPIO_IMR); diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c index 71a4a318315..dbb08546b9e 100644 --- a/drivers/gpio/gpio-octeon.c +++ b/drivers/gpio/gpio-octeon.c @@ -111,7 +111,7 @@ static int octeon_gpio_probe(struct platform_device *pdev) chip->dev = &pdev->dev; chip->owner = THIS_MODULE; chip->base = 0; - chip->can_sleep = 0; + chip->can_sleep = false; chip->ngpio = 20; chip->direction_input = octeon_gpio_dir_in; chip->get = octeon_gpio_get; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f319c9ffd4a..424319061e0 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -108,12 +108,12 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) u32 l; reg += bank->regs->direction; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (is_input) l |= 1 << gpio; else l &= ~(1 << gpio); - __raw_writel(l, reg); + writel_relaxed(l, reg); bank->context.oe = l; } @@ -132,7 +132,7 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable) bank->context.dataout &= ~l; } - __raw_writel(l, reg); + writel_relaxed(l, reg); } /* set data out value using mask register */ @@ -142,12 +142,12 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable) u32 gpio_bit = GPIO_BIT(bank, gpio); u32 l; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (enable) l |= gpio_bit; else l &= ~gpio_bit; - __raw_writel(l, reg); + writel_relaxed(l, reg); bank->context.dataout = l; } @@ -155,26 +155,26 @@ static int _get_gpio_datain(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->datain; - return (__raw_readl(reg) & (1 << offset)) != 0; + return (readl_relaxed(reg) & (1 << offset)) != 0; } static int _get_gpio_dataout(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->dataout; - return (__raw_readl(reg) & (1 << offset)) != 0; + return (readl_relaxed(reg) & (1 << offset)) != 0; } static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) { - int l = __raw_readl(base + reg); + int l = readl_relaxed(base + reg); if (set) l |= mask; else l &= ~mask; - __raw_writel(l, base + reg); + writel_relaxed(l, base + reg); } static inline void _gpio_dbck_enable(struct gpio_bank *bank) @@ -183,7 +183,7 @@ static inline void _gpio_dbck_enable(struct gpio_bank *bank) clk_enable(bank->dbck); bank->dbck_enabled = true; - __raw_writel(bank->dbck_enable_mask, + writel_relaxed(bank->dbck_enable_mask, bank->base + bank->regs->debounce_en); } } @@ -196,7 +196,7 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank) * enabled but the clock is not, GPIO module seems to be unable * to detect events and generate interrupts at least on OMAP3. */ - __raw_writel(0, bank->base + bank->regs->debounce_en); + writel_relaxed(0, bank->base + bank->regs->debounce_en); clk_disable(bank->dbck); bank->dbck_enabled = false; @@ -233,10 +233,10 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, clk_enable(bank->dbck); reg = bank->base + bank->regs->debounce; - __raw_writel(debounce, reg); + writel_relaxed(debounce, reg); reg = bank->base + bank->regs->debounce_en; - val = __raw_readl(reg); + val = readl_relaxed(reg); if (debounce) val |= l; @@ -244,7 +244,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, val &= ~l; bank->dbck_enable_mask = val; - __raw_writel(val, reg); + writel_relaxed(val, reg); clk_disable(bank->dbck); /* * Enable debounce clock per module. @@ -283,12 +283,12 @@ static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio) bank->dbck_enable_mask &= ~gpio_bit; bank->context.debounce_en &= ~gpio_bit; - __raw_writel(bank->context.debounce_en, + writel_relaxed(bank->context.debounce_en, bank->base + bank->regs->debounce_en); if (!bank->dbck_enable_mask) { bank->context.debounce = 0; - __raw_writel(bank->context.debounce, bank->base + + writel_relaxed(bank->context.debounce, bank->base + bank->regs->debounce); clk_disable(bank->dbck); bank->dbck_enabled = false; @@ -311,18 +311,18 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, trigger & IRQ_TYPE_EDGE_FALLING); bank->context.leveldetect0 = - __raw_readl(bank->base + bank->regs->leveldetect0); + readl_relaxed(bank->base + bank->regs->leveldetect0); bank->context.leveldetect1 = - __raw_readl(bank->base + bank->regs->leveldetect1); + readl_relaxed(bank->base + bank->regs->leveldetect1); bank->context.risingdetect = - __raw_readl(bank->base + bank->regs->risingdetect); + readl_relaxed(bank->base + bank->regs->risingdetect); bank->context.fallingdetect = - __raw_readl(bank->base + bank->regs->fallingdetect); + readl_relaxed(bank->base + bank->regs->fallingdetect); if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { _gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0); bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); + readl_relaxed(bank->base + bank->regs->wkup_en); } /* This part needs to be executed always for OMAP{34xx, 44xx} */ @@ -347,8 +347,8 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, exit: bank->level_mask = - __raw_readl(bank->base + bank->regs->leveldetect0) | - __raw_readl(bank->base + bank->regs->leveldetect1); + readl_relaxed(bank->base + bank->regs->leveldetect0) | + readl_relaxed(bank->base + bank->regs->leveldetect1); } #ifdef CONFIG_ARCH_OMAP1 @@ -366,13 +366,13 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) reg += bank->regs->irqctrl; - l = __raw_readl(reg); + l = readl_relaxed(reg); if ((l >> gpio) & 1) l &= ~(1 << gpio); else l |= 1 << gpio; - __raw_writel(l, reg); + writel_relaxed(l, reg); } #else static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {} @@ -390,7 +390,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, } else if (bank->regs->irqctrl) { reg += bank->regs->irqctrl; - l = __raw_readl(reg); + l = readl_relaxed(reg); if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) bank->toggle_mask |= 1 << gpio; if (trigger & IRQ_TYPE_EDGE_RISING) @@ -400,7 +400,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, else return -EINVAL; - __raw_writel(l, reg); + writel_relaxed(l, reg); } else if (bank->regs->edgectrl1) { if (gpio & 0x08) reg += bank->regs->edgectrl2; @@ -408,7 +408,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, reg += bank->regs->edgectrl1; gpio &= 0x07; - l = __raw_readl(reg); + l = readl_relaxed(reg); l &= ~(3 << (gpio << 1)); if (trigger & IRQ_TYPE_EDGE_RISING) l |= 2 << (gpio << 1); @@ -418,8 +418,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, /* Enable wake-up during idle for dynamic tick */ _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger); bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); - __raw_writel(l, reg); + readl_relaxed(bank->base + bank->regs->wkup_en); + writel_relaxed(l, reg); } return 0; } @@ -430,17 +430,17 @@ static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset) void __iomem *reg = bank->base + bank->regs->pinctrl; /* Claim the pin for MPU */ - __raw_writel(__raw_readl(reg) | (1 << offset), reg); + writel_relaxed(readl_relaxed(reg) | (1 << offset), reg); } if (bank->regs->ctrl && !BANK_USED(bank)) { void __iomem *reg = bank->base + bank->regs->ctrl; u32 ctrl; - ctrl = __raw_readl(reg); + ctrl = readl_relaxed(reg); /* Module is enabled, clocks are not gated */ ctrl &= ~GPIO_MOD_CTRL_BIT; - __raw_writel(ctrl, reg); + writel_relaxed(ctrl, reg); bank->context.ctrl = ctrl; } } @@ -455,17 +455,17 @@ static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset) /* Disable wake-up during idle for dynamic tick */ _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0); bank->context.wake_en = - __raw_readl(bank->base + bank->regs->wkup_en); + readl_relaxed(bank->base + bank->regs->wkup_en); } if (bank->regs->ctrl && !BANK_USED(bank)) { void __iomem *reg = bank->base + bank->regs->ctrl; u32 ctrl; - ctrl = __raw_readl(reg); + ctrl = readl_relaxed(reg); /* Module is disabled, clocks are gated */ ctrl |= GPIO_MOD_CTRL_BIT; - __raw_writel(ctrl, reg); + writel_relaxed(ctrl, reg); bank->context.ctrl = ctrl; } } @@ -474,7 +474,7 @@ static int gpio_is_input(struct gpio_bank *bank, int mask) { void __iomem *reg = bank->base + bank->regs->direction; - return __raw_readl(reg) & mask; + return readl_relaxed(reg) & mask; } static int gpio_irq_type(struct irq_data *d, unsigned type) @@ -538,16 +538,16 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) void __iomem *reg = bank->base; reg += bank->regs->irqstatus; - __raw_writel(gpio_mask, reg); + writel_relaxed(gpio_mask, reg); /* Workaround for clearing DSP GPIO interrupts to allow retention */ if (bank->regs->irqstatus2) { reg = bank->base + bank->regs->irqstatus2; - __raw_writel(gpio_mask, reg); + writel_relaxed(gpio_mask, reg); } /* Flush posted write for the irq status to avoid spurious interrupts */ - __raw_readl(reg); + readl_relaxed(reg); } static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) @@ -562,7 +562,7 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) u32 mask = (1 << bank->width) - 1; reg += bank->regs->irqenable; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (bank->regs->irqenable_inv) l = ~l; l &= mask; @@ -580,7 +580,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 |= gpio_mask; } else { reg += bank->regs->irqenable; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (bank->regs->irqenable_inv) l &= ~gpio_mask; else @@ -588,7 +588,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 = l; } - __raw_writel(l, reg); + writel_relaxed(l, reg); } static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) @@ -602,7 +602,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 &= ~gpio_mask; } else { reg += bank->regs->irqenable; - l = __raw_readl(reg); + l = readl_relaxed(reg); if (bank->regs->irqenable_inv) l |= gpio_mask; else @@ -610,7 +610,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) bank->context.irqenable1 = l; } - __raw_writel(l, reg); + writel_relaxed(l, reg); } static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) @@ -646,7 +646,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) else bank->context.wake_en &= ~gpio_bit; - __raw_writel(bank->context.wake_en, bank->base + bank->regs->wkup_en); + writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -748,7 +748,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) u32 enabled; enabled = _get_gpio_irqbank_mask(bank); - isr_saved = isr = __raw_readl(isr_reg) & enabled; + isr_saved = isr = readl_relaxed(isr_reg) & enabled; if (bank->level_mask) level_mask = bank->level_mask & enabled; @@ -883,7 +883,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - __raw_writel(0xffff & ~bank->context.wake_en, mask_reg); + writel_relaxed(0xffff & ~bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -898,7 +898,7 @@ static int omap_mpuio_resume_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - __raw_writel(bank->context.wake_en, mask_reg); + writel_relaxed(bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -1011,7 +1011,7 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank) if (called || bank->regs->revision == USHRT_MAX) return; - rev = __raw_readw(bank->base + bank->regs->revision); + rev = readw_relaxed(bank->base + bank->regs->revision); pr_info("OMAP GPIO hardware version %d.%d\n", (rev >> 4) & 0x0f, rev & 0x0f); @@ -1032,20 +1032,20 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) l = 0xffff; if (bank->is_mpuio) { - __raw_writel(l, bank->base + bank->regs->irqenable); + writel_relaxed(l, bank->base + bank->regs->irqenable); return; } _gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv); _gpio_rmw(base, bank->regs->irqstatus, l, !bank->regs->irqenable_inv); if (bank->regs->debounce_en) - __raw_writel(0, base + bank->regs->debounce_en); + writel_relaxed(0, base + bank->regs->debounce_en); /* Save OE default value (0xffffffff) in the context */ - bank->context.oe = __raw_readl(bank->base + bank->regs->direction); + bank->context.oe = readl_relaxed(bank->base + bank->regs->direction); /* Initialize interface clk ungated, module enabled */ if (bank->regs->ctrl) - __raw_writel(0, base + bank->regs->ctrl); + writel_relaxed(0, base + bank->regs->ctrl); bank->dbck = clk_get(bank->dev, "dbclk"); if (IS_ERR(bank->dbck)) @@ -1282,11 +1282,11 @@ static int omap_gpio_runtime_suspend(struct device *dev) */ wake_low = bank->context.leveldetect0 & bank->context.wake_en; if (wake_low) - __raw_writel(wake_low | bank->context.fallingdetect, + writel_relaxed(wake_low | bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); wake_hi = bank->context.leveldetect1 & bank->context.wake_en; if (wake_hi) - __raw_writel(wake_hi | bank->context.risingdetect, + writel_relaxed(wake_hi | bank->context.risingdetect, bank->base + bank->regs->risingdetect); if (!bank->enabled_non_wakeup_gpios) @@ -1301,7 +1301,7 @@ static int omap_gpio_runtime_suspend(struct device *dev) * non-wakeup GPIOs. Otherwise spurious IRQs will be * generated. See OMAP2420 Errata item 1.101. */ - bank->saved_datain = __raw_readl(bank->base + + bank->saved_datain = readl_relaxed(bank->base + bank->regs->datain); l1 = bank->context.fallingdetect; l2 = bank->context.risingdetect; @@ -1309,8 +1309,8 @@ static int omap_gpio_runtime_suspend(struct device *dev) l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; - __raw_writel(l1, bank->base + bank->regs->fallingdetect); - __raw_writel(l2, bank->base + bank->regs->risingdetect); + writel_relaxed(l1, bank->base + bank->regs->fallingdetect); + writel_relaxed(l2, bank->base + bank->regs->risingdetect); bank->workaround_enabled = true; @@ -1358,9 +1358,9 @@ static int omap_gpio_runtime_resume(struct device *dev) * generate a PRCM wakeup. Here we restore the * pre-runtime_suspend() values for edge triggering. */ - __raw_writel(bank->context.fallingdetect, + writel_relaxed(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); - __raw_writel(bank->context.risingdetect, + writel_relaxed(bank->context.risingdetect, bank->base + bank->regs->risingdetect); if (bank->loses_context) { @@ -1382,7 +1382,7 @@ static int omap_gpio_runtime_resume(struct device *dev) return 0; } - l = __raw_readl(bank->base + bank->regs->datain); + l = readl_relaxed(bank->base + bank->regs->datain); /* * Check if any of the non-wakeup interrupt GPIOs have changed @@ -1412,24 +1412,24 @@ static int omap_gpio_runtime_resume(struct device *dev) if (gen) { u32 old0, old1; - old0 = __raw_readl(bank->base + bank->regs->leveldetect0); - old1 = __raw_readl(bank->base + bank->regs->leveldetect1); + old0 = readl_relaxed(bank->base + bank->regs->leveldetect0); + old1 = readl_relaxed(bank->base + bank->regs->leveldetect1); if (!bank->regs->irqstatus_raw0) { - __raw_writel(old0 | gen, bank->base + + writel_relaxed(old0 | gen, bank->base + bank->regs->leveldetect0); - __raw_writel(old1 | gen, bank->base + + writel_relaxed(old1 | gen, bank->base + bank->regs->leveldetect1); } if (bank->regs->irqstatus_raw0) { - __raw_writel(old0 | l, bank->base + + writel_relaxed(old0 | l, bank->base + bank->regs->leveldetect0); - __raw_writel(old1 | l, bank->base + + writel_relaxed(old1 | l, bank->base + bank->regs->leveldetect1); } - __raw_writel(old0, bank->base + bank->regs->leveldetect0); - __raw_writel(old1, bank->base + bank->regs->leveldetect1); + writel_relaxed(old0, bank->base + bank->regs->leveldetect0); + writel_relaxed(old1, bank->base + bank->regs->leveldetect1); } bank->workaround_enabled = false; @@ -1471,55 +1471,55 @@ static void omap_gpio_init_context(struct gpio_bank *p) struct omap_gpio_reg_offs *regs = p->regs; void __iomem *base = p->base; - p->context.ctrl = __raw_readl(base + regs->ctrl); - p->context.oe = __raw_readl(base + regs->direction); - p->context.wake_en = __raw_readl(base + regs->wkup_en); - p->context.leveldetect0 = __raw_readl(base + regs->leveldetect0); - p->context.leveldetect1 = __raw_readl(base + regs->leveldetect1); - p->context.risingdetect = __raw_readl(base + regs->risingdetect); - p->context.fallingdetect = __raw_readl(base + regs->fallingdetect); - p->context.irqenable1 = __raw_readl(base + regs->irqenable); - p->context.irqenable2 = __raw_readl(base + regs->irqenable2); + p->context.ctrl = readl_relaxed(base + regs->ctrl); + p->context.oe = readl_relaxed(base + regs->direction); + p->context.wake_en = readl_relaxed(base + regs->wkup_en); + p->context.leveldetect0 = readl_relaxed(base + regs->leveldetect0); + p->context.leveldetect1 = readl_relaxed(base + regs->leveldetect1); + p->context.risingdetect = readl_relaxed(base + regs->risingdetect); + p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect); + p->context.irqenable1 = readl_relaxed(base + regs->irqenable); + p->context.irqenable2 = readl_relaxed(base + regs->irqenable2); if (regs->set_dataout && p->regs->clr_dataout) - p->context.dataout = __raw_readl(base + regs->set_dataout); + p->context.dataout = readl_relaxed(base + regs->set_dataout); else - p->context.dataout = __raw_readl(base + regs->dataout); + p->context.dataout = readl_relaxed(base + regs->dataout); p->context_valid = true; } static void omap_gpio_restore_context(struct gpio_bank *bank) { - __raw_writel(bank->context.wake_en, + writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); - __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl); - __raw_writel(bank->context.leveldetect0, + writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl); + writel_relaxed(bank->context.leveldetect0, bank->base + bank->regs->leveldetect0); - __raw_writel(bank->context.leveldetect1, + writel_relaxed(bank->context.leveldetect1, bank->base + bank->regs->leveldetect1); - __raw_writel(bank->context.risingdetect, + writel_relaxed(bank->context.risingdetect, bank->base + bank->regs->risingdetect); - __raw_writel(bank->context.fallingdetect, + writel_relaxed(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); if (bank->regs->set_dataout && bank->regs->clr_dataout) - __raw_writel(bank->context.dataout, + writel_relaxed(bank->context.dataout, bank->base + bank->regs->set_dataout); else - __raw_writel(bank->context.dataout, + writel_relaxed(bank->context.dataout, bank->base + bank->regs->dataout); - __raw_writel(bank->context.oe, bank->base + bank->regs->direction); + writel_relaxed(bank->context.oe, bank->base + bank->regs->direction); if (bank->dbck_enable_mask) { - __raw_writel(bank->context.debounce, bank->base + + writel_relaxed(bank->context.debounce, bank->base + bank->regs->debounce); - __raw_writel(bank->context.debounce_en, + writel_relaxed(bank->context.debounce_en, bank->base + bank->regs->debounce_en); } - __raw_writel(bank->context.irqenable1, + writel_relaxed(bank->context.irqenable1, bank->base + bank->regs->irqenable); - __raw_writel(bank->context.irqenable2, + writel_relaxed(bank->context.irqenable2, bank->base + bank->regs->irqenable2); } #endif /* CONFIG_PM_RUNTIME */ diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 11801e986dd..da9d33252e5 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -182,7 +182,7 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio->gpio_chip.owner = THIS_MODULE; palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); palmas_gpio->gpio_chip.ngpio = dev_data->ngpio; - palmas_gpio->gpio_chip.can_sleep = 1; + palmas_gpio->gpio_chip.can_sleep = true; palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 6e48c07e3d8..019b23b955a 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -354,7 +354,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->direction_output = pca953x_gpio_direction_output; gc->get = pca953x_gpio_get_value; gc->set = pca953x_gpio_set_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = chip->gpio_start; gc->ngpio = gpios; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 1535686e74e..82735822bc9 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -305,7 +305,7 @@ static int pcf857x_probe(struct i2c_client *client, spin_lock_init(&gpio->slock); gpio->chip.base = pdata ? pdata->gpio_base : -1; - gpio->chip.can_sleep = 1; + gpio->chip.can_sleep = true; gpio->chip.dev = &client->dev; gpio->chip.owner = THIS_MODULE; gpio->chip.get = pcf857x_get; diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 0fec097e838..9656c196772 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -224,7 +224,7 @@ static void pch_gpio_setup(struct pch_gpio *chip) gpio->dbg_show = NULL; gpio->base = -1; gpio->ngpio = gpio_pins[chip->ioh]; - gpio->can_sleep = 0; + gpio->can_sleep = false; gpio->to_irq = pch_gpio_to_irq; } @@ -518,7 +518,7 @@ static int pch_gpio_resume(struct pci_dev *pdev) #endif #define PCI_VENDOR_ID_ROHM 0x10DB -static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = { +static const struct pci_device_id pch_gpio_pcidev_id[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) }, { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) }, { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) }, diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index cc13d1b74fa..42e6e64f212 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -263,7 +263,8 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip, static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) { - return readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset); + u32 gplr = readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET); + return !!(gplr & (1 << offset)); } static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index e63d6a397e1..122b776fdc0 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -133,7 +133,7 @@ static int rc5t583_gpio_probe(struct platform_device *pdev) rc5t583_gpio->gpio_chip.get = rc5t583_gpio_get, rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq, rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO, - rc5t583_gpio->gpio_chip.can_sleep = 1, + rc5t583_gpio->gpio_chip.can_sleep = true, rc5t583_gpio->gpio_chip.dev = &pdev->dev; rc5t583_gpio->gpio_chip.base = -1; rc5t583_gpio->rc5t583 = rc5t583; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 8b7e719a68c..ca76ce75154 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -285,7 +285,34 @@ static struct irq_domain_ops gpio_rcar_irq_domain_ops = { .map = gpio_rcar_irq_domain_map, }; -static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) +struct gpio_rcar_info { + bool has_both_edge_trigger; +}; + +static const struct of_device_id gpio_rcar_of_table[] = { + { + .compatible = "renesas,gpio-r8a7790", + .data = (void *)&(const struct gpio_rcar_info) { + .has_both_edge_trigger = true, + }, + }, { + .compatible = "renesas,gpio-r8a7791", + .data = (void *)&(const struct gpio_rcar_info) { + .has_both_edge_trigger = true, + }, + }, { + .compatible = "renesas,gpio-rcar", + .data = (void *)&(const struct gpio_rcar_info) { + .has_both_edge_trigger = false, + }, + }, { + /* Terminator */ + }, +}; + +MODULE_DEVICE_TABLE(of, gpio_rcar_of_table); + +static int gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) { struct gpio_rcar_config *pdata = dev_get_platdata(&p->pdev->dev); struct device_node *np = p->pdev->dev.of_node; @@ -295,11 +322,21 @@ static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) if (pdata) { p->config = *pdata; } else if (IS_ENABLED(CONFIG_OF) && np) { + const struct of_device_id *match; + const struct gpio_rcar_info *info; + + match = of_match_node(gpio_rcar_of_table, np); + if (!match) + return -EINVAL; + + info = match->data; + ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args); p->config.number_of_pins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; p->config.gpio_base = -1; + p->config.has_both_edge_trigger = info->has_both_edge_trigger; } if (p->config.number_of_pins == 0 || @@ -309,6 +346,8 @@ static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) p->config.number_of_pins, RCAR_MAX_GPIO_PER_BANK); p->config.number_of_pins = RCAR_MAX_GPIO_PER_BANK; } + + return 0; } static int gpio_rcar_probe(struct platform_device *pdev) @@ -331,7 +370,9 @@ static int gpio_rcar_probe(struct platform_device *pdev) spin_lock_init(&p->lock); /* Get device configuration from DT node or platform data. */ - gpio_rcar_parse_pdata(p); + ret = gpio_rcar_parse_pdata(p); + if (ret < 0) + return ret; platform_set_drvdata(pdev, p); @@ -370,10 +411,9 @@ static int gpio_rcar_probe(struct platform_device *pdev) irq_chip->name = name; irq_chip->irq_mask = gpio_rcar_irq_disable; irq_chip->irq_unmask = gpio_rcar_irq_enable; - irq_chip->irq_enable = gpio_rcar_irq_enable; - irq_chip->irq_disable = gpio_rcar_irq_disable; irq_chip->irq_set_type = gpio_rcar_irq_set_type; - irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED; + irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED + | IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, p->config.number_of_pins, @@ -436,17 +476,6 @@ static int gpio_rcar_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF -static const struct of_device_id gpio_rcar_of_table[] = { - { - .compatible = "renesas,gpio-rcar", - }, - { }, -}; - -MODULE_DEVICE_TABLE(of, gpio_rcar_of_table); -#endif - static struct platform_driver gpio_rcar_device_driver = { .probe = gpio_rcar_probe, .remove = gpio_rcar_remove, diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 76e02b9460e..a85e00bf983 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -30,10 +30,13 @@ #include <asm/irq.h> -#include <mach/hardware.h> #include <mach/map.h> #include <mach/regs-gpio.h> +#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX) +#include <mach/gpio-samsung.h> +#endif + #include <plat/cpu.h> #include <plat/gpio-core.h> #include <plat/gpio-cfg.h> @@ -1053,7 +1056,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = { .base = S3C2410_GPA(0), .owner = THIS_MODULE, .label = "GPIOA", - .ngpio = 24, + .ngpio = 27, .direction_input = s3c24xx_gpiolib_banka_input, .direction_output = s3c24xx_gpiolib_banka_output, }, @@ -1062,7 +1065,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = { .base = S3C2410_GPB(0), .owner = THIS_MODULE, .label = "GPIOB", - .ngpio = 16, + .ngpio = 11, }, }, { .chip = { @@ -1107,7 +1110,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = { .base = S3C2410_GPH(0), .owner = THIS_MODULE, .label = "GPIOH", - .ngpio = 11, + .ngpio = 15, }, }, /* GPIOS for the S3C2443 and later devices. */ diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c new file mode 100644 index 00000000000..0357387b364 --- /dev/null +++ b/drivers/gpio/gpio-sch311x.c @@ -0,0 +1,432 @@ +/* + * GPIO driver for the SMSC SCH311x Super-I/O chips + * + * Copyright (C) 2013 Bruno Randolf <br1@einfach.org> + * + * SuperIO functions and chip detection: + * (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/bitops.h> +#include <linux/io.h> + +#define DRV_NAME "gpio-sch311x" + +#define SCH311X_GPIO_CONF_OUT 0x00 +#define SCH311X_GPIO_CONF_IN 0x01 +#define SCH311X_GPIO_CONF_INVERT 0x02 +#define SCH311X_GPIO_CONF_OPEN_DRAIN 0x80 + +#define SIO_CONFIG_KEY_ENTER 0x55 +#define SIO_CONFIG_KEY_EXIT 0xaa + +#define GP1 0x4b + +static int sch311x_ioports[] = { 0x2e, 0x4e, 0x162e, 0x164e }; + +static struct platform_device *sch311x_gpio_pdev; + +struct sch311x_pdev_data { /* platform device data */ + unsigned short runtime_reg; /* runtime register base address */ +}; + +struct sch311x_gpio_block { /* one GPIO block runtime data */ + struct gpio_chip chip; + unsigned short data_reg; /* from definition below */ + unsigned short *config_regs; /* pointer to definition below */ + unsigned short runtime_reg; /* runtime register */ + spinlock_t lock; /* lock for this GPIO block */ +}; + +struct sch311x_gpio_priv { /* driver private data */ + struct sch311x_gpio_block blocks[6]; +}; + +struct sch311x_gpio_block_def { /* register address definitions */ + unsigned short data_reg; + unsigned short config_regs[8]; + unsigned short base; +}; + +/* Note: some GPIOs are not available, these are marked with 0x00 */ + +static struct sch311x_gpio_block_def sch311x_gpio_blocks[] = { + { + .data_reg = 0x4b, /* GP1 */ + .config_regs = {0x23, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2a, 0x2b}, + .base = 10, + }, + { + .data_reg = 0x4c, /* GP2 */ + .config_regs = {0x00, 0x2c, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x32}, + .base = 20, + }, + { + .data_reg = 0x4d, /* GP3 */ + .config_regs = {0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x39, 0x3a}, + .base = 30, + }, + { + .data_reg = 0x4e, /* GP4 */ + .config_regs = {0x3b, 0x00, 0x3d, 0x00, 0x6e, 0x6f, 0x72, 0x73}, + .base = 40, + }, + { + .data_reg = 0x4f, /* GP5 */ + .config_regs = {0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}, + .base = 50, + }, + { + .data_reg = 0x50, /* GP6 */ + .config_regs = {0x47, 0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59}, + .base = 60, + }, +}; + +static inline struct sch311x_gpio_block * +to_sch311x_gpio_block(struct gpio_chip *chip) +{ + return container_of(chip, struct sch311x_gpio_block, chip); +} + + +/* + * Super-IO functions + */ + +static inline int sch311x_sio_enter(int sio_config_port) +{ + /* Don't step on other drivers' I/O space by accident. */ + if (!request_muxed_region(sio_config_port, 2, DRV_NAME)) { + pr_err(DRV_NAME "I/O address 0x%04x already in use\n", + sio_config_port); + return -EBUSY; + } + + outb(SIO_CONFIG_KEY_ENTER, sio_config_port); + return 0; +} + +static inline void sch311x_sio_exit(int sio_config_port) +{ + outb(SIO_CONFIG_KEY_EXIT, sio_config_port); + release_region(sio_config_port, 2); +} + +static inline int sch311x_sio_inb(int sio_config_port, int reg) +{ + outb(reg, sio_config_port); + return inb(sio_config_port + 1); +} + +static inline void sch311x_sio_outb(int sio_config_port, int reg, int val) +{ + outb(reg, sio_config_port); + outb(val, sio_config_port + 1); +} + + +/* + * GPIO functions + */ + +static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + if (block->config_regs[offset] == 0) /* GPIO is not available */ + return -ENODEV; + + if (!request_region(block->runtime_reg + block->config_regs[offset], + 1, DRV_NAME)) { + dev_err(chip->dev, "Failed to request region 0x%04x.\n", + block->runtime_reg + block->config_regs[offset]); + return -EBUSY; + } + return 0; +} + +static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + if (block->config_regs[offset] == 0) /* GPIO is not available */ + return; + + release_region(block->runtime_reg + block->config_regs[offset], 1); +} + +static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + unsigned char data; + + spin_lock(&block->lock); + data = inb(block->runtime_reg + block->data_reg); + spin_unlock(&block->lock); + + return !!(data & BIT(offset)); +} + +static void __sch311x_gpio_set(struct sch311x_gpio_block *block, + unsigned offset, int value) +{ + unsigned char data = inb(block->runtime_reg + block->data_reg); + if (value) + data |= BIT(offset); + else + data &= ~BIT(offset); + outb(data, block->runtime_reg + block->data_reg); +} + +static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + spin_lock(&block->lock); + __sch311x_gpio_set(block, offset, value); + spin_unlock(&block->lock); +} + +static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + spin_lock(&block->lock); + outb(SCH311X_GPIO_CONF_IN, block->runtime_reg + + block->config_regs[offset]); + spin_unlock(&block->lock); + + return 0; +} + +static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip); + + spin_lock(&block->lock); + + outb(SCH311X_GPIO_CONF_OUT, block->runtime_reg + + block->config_regs[offset]); + + __sch311x_gpio_set(block, offset, value); + + spin_unlock(&block->lock); + return 0; +} + +static int sch311x_gpio_probe(struct platform_device *pdev) +{ + struct sch311x_pdev_data *pdata = pdev->dev.platform_data; + struct sch311x_gpio_priv *priv; + struct sch311x_gpio_block *block; + int err, i; + + /* we can register all GPIO data registers at once */ + if (!request_region(pdata->runtime_reg + GP1, 6, DRV_NAME)) { + dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n", + pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5); + return -EBUSY; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) { + block = &priv->blocks[i]; + + spin_lock_init(&block->lock); + + block->chip.label = DRV_NAME; + block->chip.owner = THIS_MODULE; + block->chip.request = sch311x_gpio_request; + block->chip.free = sch311x_gpio_free; + block->chip.direction_input = sch311x_gpio_direction_in; + block->chip.direction_output = sch311x_gpio_direction_out; + block->chip.get = sch311x_gpio_get; + block->chip.set = sch311x_gpio_set; + block->chip.ngpio = 8; + block->chip.dev = &pdev->dev; + block->chip.base = sch311x_gpio_blocks[i].base; + block->config_regs = sch311x_gpio_blocks[i].config_regs; + block->data_reg = sch311x_gpio_blocks[i].data_reg; + block->runtime_reg = pdata->runtime_reg; + + err = gpiochip_add(&block->chip); + if (err < 0) { + dev_err(&pdev->dev, + "Could not register gpiochip, %d\n", err); + goto exit_err; + } + dev_info(&pdev->dev, + "SMSC SCH311x GPIO block %d registered.\n", i); + } + + return 0; + +exit_err: + release_region(pdata->runtime_reg + GP1, 6); + /* release already registered chips */ + for (--i; i >= 0; i--) + gpiochip_remove(&priv->blocks[i].chip); + return err; +} + +static int sch311x_gpio_remove(struct platform_device *pdev) +{ + struct sch311x_pdev_data *pdata = pdev->dev.platform_data; + struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev); + int err, i; + + release_region(pdata->runtime_reg + GP1, 6); + + for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) { + err = gpiochip_remove(&priv->blocks[i].chip); + if (err) + return err; + dev_info(&pdev->dev, + "SMSC SCH311x GPIO block %d unregistered.\n", i); + } + return 0; +} + +static struct platform_driver sch311x_gpio_driver = { + .driver.name = DRV_NAME, + .driver.owner = THIS_MODULE, + .probe = sch311x_gpio_probe, + .remove = sch311x_gpio_remove, +}; + + +/* + * Init & exit routines + */ + +static int __init sch311x_detect(int sio_config_port, unsigned short *addr) +{ + int err = 0, reg; + unsigned short base_addr; + unsigned char dev_id; + + err = sch311x_sio_enter(sio_config_port); + if (err) + return err; + + /* Check device ID. We currently know about: + * SCH3112 (0x7c), SCH3114 (0x7d), and SCH3116 (0x7f). */ + reg = sch311x_sio_inb(sio_config_port, 0x20); + if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) { + err = -ENODEV; + goto exit; + } + dev_id = reg == 0x7c ? 2 : reg == 0x7d ? 4 : 6; + + /* Select logical device A (runtime registers) */ + sch311x_sio_outb(sio_config_port, 0x07, 0x0a); + + /* Check if Logical Device Register is currently active */ + if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0) + pr_info("Seems that LDN 0x0a is not active...\n"); + + /* Get the base address of the runtime registers */ + base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) | + sch311x_sio_inb(sio_config_port, 0x61); + if (!base_addr) { + pr_err("Base address not set\n"); + err = -ENODEV; + goto exit; + } + *addr = base_addr; + + pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr); + +exit: + sch311x_sio_exit(sio_config_port); + return err; +} + +static int __init sch311x_gpio_pdev_add(const unsigned short addr) +{ + struct sch311x_pdev_data pdata; + int err; + + pdata.runtime_reg = addr; + + sch311x_gpio_pdev = platform_device_alloc(DRV_NAME, -1); + if (!sch311x_gpio_pdev) + return -ENOMEM; + + err = platform_device_add_data(sch311x_gpio_pdev, + &pdata, sizeof(pdata)); + if (err) { + pr_err(DRV_NAME "Platform data allocation failed\n"); + goto err; + } + + err = platform_device_add(sch311x_gpio_pdev); + if (err) { + pr_err(DRV_NAME "Device addition failed\n"); + goto err; + } + return 0; + +err: + platform_device_put(sch311x_gpio_pdev); + return err; +} + +static int __init sch311x_gpio_init(void) +{ + int err, i; + unsigned short addr = 0; + + for (i = 0; i < ARRAY_SIZE(sch311x_ioports); i++) + if (sch311x_detect(sch311x_ioports[i], &addr) == 0) + break; + + if (!addr) + return -ENODEV; + + err = platform_driver_register(&sch311x_gpio_driver); + if (err) + return err; + + err = sch311x_gpio_pdev_add(addr); + if (err) + goto unreg_platform_driver; + + return 0; + +unreg_platform_driver: + platform_driver_unregister(&sch311x_gpio_driver); + return err; +} + +static void __exit sch311x_gpio_exit(void) +{ + platform_device_unregister(sch311x_gpio_pdev); + platform_driver_unregister(&sch311x_gpio_driver); +} + +module_init(sch311x_gpio_init); +module_exit(sch311x_gpio_exit); + +MODULE_AUTHOR("Bruno Randolf <br1@einfach.org>"); +MODULE_DESCRIPTION("SMSC SCH311x GPIO Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gpio-sch311x"); diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index 88f374ac775..7c6c518929b 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -176,8 +176,10 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, sd->id = irq_domain_add_legacy(pdev->dev.of_node, SDV_NUM_PUB_GPIOS, sd->irq_base, 0, &irq_domain_sdv_ops, sd); - if (!sd->id) + if (!sd->id) { + ret = -ENODEV; goto out_free_irq; + } return 0; out_free_irq: free_irq(pdev->irq, sd); @@ -212,8 +214,10 @@ static int sdv_gpio_probe(struct pci_dev *pdev, } addr = pci_resource_start(pdev, GPIO_BAR); - if (!addr) + if (!addr) { + ret = -ENODEV; goto release_reg; + } sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR)); prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len); @@ -270,7 +274,7 @@ static void sdv_gpio_remove(struct pci_dev *pdev) kfree(sd); } -static DEFINE_PCI_DEVICE_TABLE(sdv_gpio_pci_ids) = { +static const struct pci_device_id sdv_gpio_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) }, { 0, }, }; diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index f2fb12c18da..68e3fcb1ace 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -146,7 +146,7 @@ static void gsta_gpio_setup(struct gsta_gpio *chip) /* called from probe */ gpio->dbg_show = NULL; gpio->base = gpio_base; gpio->ngpio = GSTA_NR_GPIO; - gpio->can_sleep = 0; + gpio->can_sleep = false; gpio->to_irq = gsta_gpio_to_irq; /* diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 2647e243d47..2776a09bee5 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -129,7 +129,7 @@ static struct gpio_chip template_chip = { .set = stmpe_gpio_set, .to_irq = stmpe_gpio_to_irq, .request = stmpe_gpio_request, - .can_sleep = 1, + .can_sleep = true, }; static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index d2983e9ad6a..13d73fb2b5e 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -436,7 +436,7 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->gpio_chip.set = sx150x_gpio_set; chip->gpio_chip.to_irq = sx150x_gpio_to_irq; chip->gpio_chip.base = pdata->gpio_base; - chip->gpio_chip.can_sleep = 1; + chip->gpio_chip.can_sleep = true; chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; if (pdata->oscio_is_gpo) ++chip->gpio_chip.ngpio; diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index da071ddbad9..07bce97647a 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -222,7 +222,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev) tb10x_gpio->gc.free = tb10x_gpio_free; tb10x_gpio->gc.base = -1; tb10x_gpio->gc.ngpio = ngpio; - tb10x_gpio->gc.can_sleep = 0; + tb10x_gpio->gc.can_sleep = false; ret = gpiochip_add(&tb10x_gpio->gc); @@ -318,7 +318,7 @@ static struct platform_driver tb10x_gpio_driver = { .remove = tb10x_gpio_remove, .driver = { .name = "tb10x-gpio", - .of_match_table = of_match_ptr(tb10x_gpio_dt_ids), + .of_match_table = tb10x_gpio_dt_ids, .owner = THIS_MODULE, } }; diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index ddb5fefaa71..1019320984d 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -127,7 +127,7 @@ static struct gpio_chip template_chip = { .direction_output = tc3589x_gpio_direction_output, .set = tc3589x_gpio_set, .to_irq = tc3589x_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, }; static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index cfd3b9037bc..2b49f878b56 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -425,6 +425,7 @@ static int tegra_gpio_probe(struct platform_device *pdev) struct tegra_gpio_soc_config *config; struct resource *res; struct tegra_gpio_bank *bank; + int ret; int gpio; int i; int j; @@ -494,7 +495,11 @@ static int tegra_gpio_probe(struct platform_device *pdev) tegra_gpio_chip.of_node = pdev->dev.of_node; - gpiochip_add(&tegra_gpio_chip); + ret = gpiochip_add(&tegra_gpio_chip); + if (ret < 0) { + irq_domain_remove(irq_domain); + return ret; + } for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { int irq = irq_create_mapping(irq_domain, gpio); diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 7a0e956ef1e..f9a8fbde108 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -275,7 +275,7 @@ static int timbgpio_probe(struct platform_device *pdev) gc->dbg_show = NULL; gc->base = pdata->gpio_base; gc->ngpio = pdata->nr_pins; - gc->can_sleep = 0; + gc->can_sleep = false; err = gpiochip_add(gc); if (err) @@ -290,8 +290,8 @@ static int timbgpio_probe(struct platform_device *pdev) return 0; for (i = 0; i < pdata->nr_pins; i++) { - irq_set_chip_and_handler_name(tgpio->irq_base + i, - &timbgpio_irqchip, handle_simple_irq, "mux"); + irq_set_chip_and_handler(tgpio->irq_base + i, + &timbgpio_irqchip, handle_simple_irq); irq_set_chip_data(tgpio->irq_base + i, tgpio); #ifdef CONFIG_ARM set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); diff --git a/drivers/gpio/gpio-tnetv107x.c b/drivers/gpio/gpio-tnetv107x.c index 58445bb6910..4aa481579a0 100644 --- a/drivers/gpio/gpio-tnetv107x.c +++ b/drivers/gpio/gpio-tnetv107x.c @@ -176,7 +176,7 @@ static int __init tnetv107x_gpio_setup(void) ctlr = &chips[i]; ctlr->chip.label = "tnetv107x"; - ctlr->chip.can_sleep = 0; + ctlr->chip.can_sleep = false; ctlr->chip.base = base; ctlr->chip.ngpio = ngpio - base; if (ctlr->chip.ngpio > 32) diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index 29e8e750bd4..8994dfa1349 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -108,7 +108,7 @@ static int tps6586x_gpio_probe(struct platform_device *pdev) tps6586x_gpio->gpio_chip.label = pdev->name; tps6586x_gpio->gpio_chip.dev = &pdev->dev; tps6586x_gpio->gpio_chip.ngpio = 4; - tps6586x_gpio->gpio_chip.can_sleep = 1; + tps6586x_gpio->gpio_chip.can_sleep = true; /* FIXME: add handling of GPIOs as dedicated inputs */ tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output; diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 06146219d9d..b6e818e6800 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -143,7 +143,7 @@ static int tps65910_gpio_probe(struct platform_device *pdev) default: return -EINVAL; } - tps65910_gpio->gpio_chip.can_sleep = 1; + tps65910_gpio->gpio_chip.can_sleep = true; tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input; tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output; tps65910_gpio->gpio_chip.set = tps65910_gpio_set; diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 276a4229b03..59ee486cb8b 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -79,7 +79,7 @@ static struct gpio_chip template_chip = { .direction_output = tps65912_gpio_output, .get = tps65912_gpio_get, .set = tps65912_gpio_set, - .can_sleep = 1, + .can_sleep = true, .ngpio = 5, .base = -1, }; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index f9996899c1f..8b88ca2eda9 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -396,7 +396,7 @@ static struct gpio_chip template_chip = { .direction_output = twl_direction_out, .set = twl_set, .to_irq = twl_to_irq, - .can_sleep = 1, + .can_sleep = true, }; /*----------------------------------------------------------------------*/ diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index d420d30b86e..0caf5cd1b47 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -77,7 +77,7 @@ static struct gpio_chip twl6040gpo_chip = { .get = twl6040gpo_get, .direction_output = twl6040gpo_direction_out, .set = twl6040gpo_set, - .can_sleep = 1, + .can_sleep = true, }; /*----------------------------------------------------------------------*/ diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index 06fb5cf99de..2445fe77117 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c @@ -64,7 +64,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) ucb->gc.direction_output = ucb1400_gpio_dir_out; ucb->gc.get = ucb1400_gpio_get; ucb->gc.set = ucb1400_gpio_set; - ucb->gc.can_sleep = 1; + ucb->gc.can_sleep = true; err = gpiochip_add(&ucb->gc); if (err) diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index 5ac2919197f..79e3b583671 100644 --- a/drivers/gpio/gpio-viperboard.c +++ b/drivers/gpio/gpio-viperboard.c @@ -413,7 +413,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev) vb_gpio->gpioa.owner = THIS_MODULE; vb_gpio->gpioa.base = -1; vb_gpio->gpioa.ngpio = 16; - vb_gpio->gpioa.can_sleep = 1; + vb_gpio->gpioa.can_sleep = true; vb_gpio->gpioa.set = vprbrd_gpioa_set; vb_gpio->gpioa.get = vprbrd_gpioa_get; vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input; @@ -430,7 +430,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev) vb_gpio->gpiob.owner = THIS_MODULE; vb_gpio->gpiob.base = -1; vb_gpio->gpiob.ngpio = 16; - vb_gpio->gpiob.can_sleep = 1; + vb_gpio->gpiob.can_sleep = true; vb_gpio->gpiob.set = vprbrd_gpiob_set; vb_gpio->gpiob.get = vprbrd_gpiob_get; vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input; diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index cddfa22edb4..0fd23b6a753 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -214,7 +214,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg) c->dbg_show = NULL; c->base = 0; c->ngpio = NR_VX855_GP; - c->can_sleep = 0; + c->can_sleep = false; c->names = vx855gpio_names; } diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 456000c5c45..b18a1a26425 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -240,7 +240,7 @@ static struct gpio_chip template_chip = { .to_irq = wm831x_gpio_to_irq, .set_debounce = wm831x_gpio_set_debounce, .dbg_show = wm831x_gpio_dbg_show, - .can_sleep = 1, + .can_sleep = true, }; static int wm831x_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index fc49154be7b..2487f9d575d 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -106,7 +106,7 @@ static struct gpio_chip template_chip = { .direction_output = wm8350_gpio_direction_out, .set = wm8350_gpio_set, .to_irq = wm8350_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, }; static int wm8350_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index a53dbdefc7e..d93b6b58167 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -242,7 +242,7 @@ static struct gpio_chip template_chip = { .set = wm8994_gpio_set, .to_irq = wm8994_gpio_to_irq, .dbg_show = wm8994_gpio_dbg_show, - .can_sleep = 1, + .can_sleep = true, }; static int wm8994_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c new file mode 100644 index 00000000000..1d136eceda6 --- /dev/null +++ b/drivers/gpio/gpio-xtensa.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2013 TangoTec Ltd. + * Author: Baruch Siach <baruch@tkos.co.il> + * + * 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. + * + * Driver for the Xtensa LX4 GPIO32 Option + * + * Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22 + * + * GPIO32 is a standard optional extension to the Xtensa architecture core that + * provides preconfigured output and input ports for intra SoC signaling. The + * GPIO32 option is implemented as 32bit Tensilica Instruction Extension (TIE) + * output state called EXPSTATE, and 32bit input wire called IMPWIRE. This + * driver treats input and output states as two distinct devices. + * + * Access to GPIO32 specific instructions is controlled by the CPENABLE + * (Coprocessor Enable Bits) register. By default Xtensa Linux startup code + * disables access to all coprocessors. This driver sets the CPENABLE bit + * corresponding to GPIO32 before any GPIO32 specific instruction, and restores + * CPENABLE state after that. + * + * This driver is currently incompatible with SMP. The GPIO32 extension is not + * guaranteed to be available in all cores. Moreover, each core controls a + * different set of IO wires. A theoretical SMP aware version of this driver + * would need to have a per core workqueue to do the actual GPIO manipulation. + */ + +#include <linux/err.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/bitops.h> +#include <linux/platform_device.h> + +#include <asm/coprocessor.h> /* CPENABLE read/write macros */ + +#ifndef XCHAL_CP_ID_XTIOP +#error GPIO32 option is not enabled for your xtensa core variant +#endif + +static inline unsigned long enable_cp(unsigned long *cpenable) +{ + unsigned long flags; + + local_irq_save(flags); + RSR_CPENABLE(*cpenable); + WSR_CPENABLE(*cpenable | BIT(XCHAL_CP_ID_XTIOP)); + + return flags; +} + +static inline void disable_cp(unsigned long flags, unsigned long cpenable) +{ + WSR_CPENABLE(cpenable); + local_irq_restore(flags); +} + +static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset) +{ + return 1; /* input only */ +} + +static int xtensa_impwire_get_value(struct gpio_chip *gc, unsigned offset) +{ + unsigned long flags, saved_cpenable; + u32 impwire; + + flags = enable_cp(&saved_cpenable); + __asm__ __volatile__("read_impwire %0" : "=a" (impwire)); + disable_cp(flags, saved_cpenable); + + return !!(impwire & BIT(offset)); +} + +static void xtensa_impwire_set_value(struct gpio_chip *gc, unsigned offset, + int value) +{ + BUG(); /* output only; should never be called */ +} + +static int xtensa_expstate_get_direction(struct gpio_chip *gc, unsigned offset) +{ + return 0; /* output only */ +} + +static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset) +{ + unsigned long flags, saved_cpenable; + u32 expstate; + + flags = enable_cp(&saved_cpenable); + __asm__ __volatile__("rur.expstate %0" : "=a" (expstate)); + disable_cp(flags, saved_cpenable); + + return !!(expstate & BIT(offset)); +} + +static void xtensa_expstate_set_value(struct gpio_chip *gc, unsigned offset, + int value) +{ + unsigned long flags, saved_cpenable; + u32 mask = BIT(offset); + u32 val = value ? BIT(offset) : 0; + + flags = enable_cp(&saved_cpenable); + __asm__ __volatile__("wrmsk_expstate %0, %1" + :: "a" (val), "a" (mask)); + disable_cp(flags, saved_cpenable); +} + +static struct gpio_chip impwire_chip = { + .label = "impwire", + .base = -1, + .ngpio = 32, + .get_direction = xtensa_impwire_get_direction, + .get = xtensa_impwire_get_value, + .set = xtensa_impwire_set_value, +}; + +static struct gpio_chip expstate_chip = { + .label = "expstate", + .base = -1, + .ngpio = 32, + .get_direction = xtensa_expstate_get_direction, + .get = xtensa_expstate_get_value, + .set = xtensa_expstate_set_value, +}; + +static int xtensa_gpio_probe(struct platform_device *pdev) +{ + int ret; + + ret = gpiochip_add(&impwire_chip); + if (ret) + return ret; + return gpiochip_add(&expstate_chip); +} + +static struct platform_driver xtensa_gpio_driver = { + .driver = { + .name = "xtensa-gpio", + .owner = THIS_MODULE, + }, + .probe = xtensa_gpio_probe, +}; + +static int __init xtensa_gpio_init(void) +{ + struct platform_device *pdev; + + pdev = platform_device_register_simple("xtensa-gpio", 0, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return platform_driver_register(&xtensa_gpio_driver); +} +device_initcall(xtensa_gpio_init); + +MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); +MODULE_DESCRIPTION("Xtensa LX4 GPIO32 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index ae0ffdce8bd..716ee984311 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -12,11 +12,13 @@ #include <linux/errno.h> #include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> #include <linux/export.h> -#include <linux/acpi_gpio.h> #include <linux/acpi.h> #include <linux/interrupt.h> +#include "gpiolib.h" + struct acpi_gpio_evt_pin { struct list_head node; acpi_handle *evt_handle; @@ -94,7 +96,7 @@ static void acpi_gpio_evt_dh(acpi_handle handle, void *data) * gpio pins have acpi event methods and assigns interrupt handlers that calls * the acpi event methods for those pins. */ -void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) +static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_resource *res; @@ -192,7 +194,6 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) irq); } } -EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); /** * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. @@ -203,7 +204,7 @@ EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); * The remaining ACPI event interrupts associated with the chip are freed * automatically. */ -void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) +static void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { acpi_handle handle; acpi_status status; @@ -230,7 +231,6 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) acpi_detach_data(handle, acpi_gpio_evt_dh); kfree(evt_pins); } -EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); struct acpi_gpio_lookup { struct acpi_gpio_info info; @@ -307,6 +307,15 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, if (lookup.desc && info) *info = lookup.info; - return lookup.desc ? lookup.desc : ERR_PTR(-ENODEV); + return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); +} + +void acpi_gpiochip_add(struct gpio_chip *chip) +{ + acpi_gpiochip_request_interrupts(chip); +} + +void acpi_gpiochip_remove(struct gpio_chip *chip) +{ + acpi_gpiochip_free_interrupts(chip); } -EXPORT_SYMBOL_GPL(acpi_get_gpiod_by_index); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 85f772c0b26..50c4922fe53 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -10,12 +10,13 @@ #include <linux/seq_file.h> #include <linux/gpio.h> #include <linux/of_gpio.h> -#include <linux/acpi_gpio.h> #include <linux/idr.h> #include <linux/slab.h> #include <linux/acpi.h> #include <linux/gpio/driver.h> +#include "gpiolib.h" + #define CREATE_TRACE_POINTS #include <trace/events/gpio.h> @@ -84,40 +85,57 @@ static DEFINE_IDR(dirent_idr); static int gpiod_request(struct gpio_desc *desc, const char *label); static void gpiod_free(struct gpio_desc *desc); +/* With descriptor prefix */ + #ifdef CONFIG_DEBUG_FS -#define gpiod_emerg(desc, fmt, ...) \ - pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_emerg(desc, fmt, ...) \ + pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\ ##__VA_ARGS__) -#define gpiod_crit(desc, fmt, ...) \ - pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_crit(desc, fmt, ...) \ + pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ ##__VA_ARGS__) -#define gpiod_err(desc, fmt, ...) \ - pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_err(desc, fmt, ...) \ + pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ ##__VA_ARGS__) -#define gpiod_warn(desc, fmt, ...) \ - pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_warn(desc, fmt, ...) \ + pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ ##__VA_ARGS__) -#define gpiod_info(desc, fmt, ...) \ - pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_info(desc, fmt, ...) \ + pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \ ##__VA_ARGS__) -#define gpiod_dbg(desc, fmt, ...) \ - pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_dbg(desc, fmt, ...) \ + pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\ ##__VA_ARGS__) #else -#define gpiod_emerg(desc, fmt, ...) \ +#define gpiod_emerg(desc, fmt, ...) \ pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_crit(desc, fmt, ...) \ +#define gpiod_crit(desc, fmt, ...) \ pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_err(desc, fmt, ...) \ +#define gpiod_err(desc, fmt, ...) \ pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_warn(desc, fmt, ...) \ +#define gpiod_warn(desc, fmt, ...) \ pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_info(desc, fmt, ...) \ +#define gpiod_info(desc, fmt, ...) \ pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_dbg(desc, fmt, ...) \ +#define gpiod_dbg(desc, fmt, ...) \ pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) #endif +/* With chip prefix */ + +#define chip_emerg(chip, fmt, ...) \ + pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_crit(chip, fmt, ...) \ + pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_err(chip, fmt, ...) \ + pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_warn(chip, fmt, ...) \ + pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_info(chip, fmt, ...) \ + pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_dbg(chip, fmt, ...) \ + pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) + static inline void desc_set_label(struct gpio_desc *d, const char *label) { #ifdef CONFIG_DEBUG_FS @@ -151,9 +169,10 @@ EXPORT_SYMBOL_GPL(gpio_to_desc); static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip, unsigned int offset) { - unsigned int gpio = chip->base + offset; + if (offset >= chip->ngpio) + return ERR_PTR(-EINVAL); - return gpio_to_desc(gpio); + return &chip->desc[offset]; } /** @@ -187,7 +206,8 @@ static int gpio_ensure_requested(struct gpio_desc *desc) if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0, "autorequest GPIO-%d\n", gpio)) { if (!try_module_get(chip->owner)) { - pr_err("GPIO-%d: module can't be gotten \n", gpio); + gpiod_err(desc, "%s: module can't be gotten\n", + __func__); clear_bit(FLAG_REQUESTED, &desc->flags); /* lose */ return -EIO; @@ -393,7 +413,7 @@ static const DEVICE_ATTR(value, 0644, static irqreturn_t gpio_sysfs_irq(int irq, void *priv) { - struct sysfs_dirent *value_sd = priv; + struct kernfs_node *value_sd = priv; sysfs_notify_dirent(value_sd); return IRQ_HANDLED; @@ -402,7 +422,7 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv) static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, unsigned long gpio_flags) { - struct sysfs_dirent *value_sd; + struct kernfs_node *value_sd; unsigned long irq_flags; int ret, irq, id; @@ -808,8 +828,8 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) if (!test_bit(FLAG_REQUESTED, &desc->flags) || test_bit(FLAG_EXPORT, &desc->flags)) { spin_unlock_irqrestore(&gpio_lock, flags); - pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", - __func__, desc_to_gpio(desc), + gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n", + __func__, test_bit(FLAG_REQUESTED, &desc->flags), test_bit(FLAG_EXPORT, &desc->flags)); status = -EPERM; @@ -857,8 +877,7 @@ fail_unregister_device: device_unregister(dev); fail_unlock: mutex_unlock(&sysfs_lock); - pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), - status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } EXPORT_SYMBOL_GPL(gpiod_export); @@ -906,8 +925,7 @@ int gpiod_export_link(struct device *dev, const char *name, mutex_unlock(&sysfs_lock); if (status) - pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), - status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } @@ -951,8 +969,7 @@ unlock: mutex_unlock(&sysfs_lock); if (status) - pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), - status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } @@ -994,8 +1011,7 @@ void gpiod_unexport(struct gpio_desc *desc) } if (status) - pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), - status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); } EXPORT_SYMBOL_GPL(gpiod_unexport); @@ -1034,8 +1050,7 @@ static int gpiochip_export(struct gpio_chip *chip) chip->desc[gpio++].chip = NULL; spin_unlock_irqrestore(&gpio_lock, flags); - pr_debug("%s: chip %s status %d\n", __func__, - chip->label, status); + chip_dbg(chip, "%s: status %d\n", __func__, status); } return status; @@ -1051,15 +1066,14 @@ static void gpiochip_unexport(struct gpio_chip *chip) if (dev) { put_device(dev); device_unregister(dev); - chip->exported = 0; + chip->exported = false; status = 0; } else status = -ENODEV; mutex_unlock(&sysfs_lock); if (status) - pr_debug("%s: chip %s status %d\n", __func__, - chip->label, status); + chip_dbg(chip, "%s: status %d\n", __func__, status); } static int __init gpiolib_sysfs_init(void) @@ -1213,6 +1227,7 @@ int gpiochip_add(struct gpio_chip *chip) #endif of_gpiochip_add(chip); + acpi_gpiochip_add(chip); if (status) goto fail; @@ -1221,7 +1236,7 @@ int gpiochip_add(struct gpio_chip *chip) if (status) goto fail; - pr_debug("gpiochip_add: registered GPIOs %d to %d on device: %s\n", + pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__, chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); @@ -1231,7 +1246,7 @@ unlock: spin_unlock_irqrestore(&gpio_lock, flags); fail: /* failures here can mean systems won't boot... */ - pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", + pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); return status; @@ -1254,6 +1269,7 @@ int gpiochip_remove(struct gpio_chip *chip) gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); + acpi_gpiochip_remove(chip); for (id = 0; id < chip->ngpio; id++) { if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { @@ -1339,8 +1355,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip, pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); if (!pin_range) { - pr_err("%s: GPIO chip: failed to allocate pin ranges\n", - chip->label); + chip_err(chip, "failed to allocate pin ranges\n"); return -ENOMEM; } @@ -1361,9 +1376,8 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip, pinctrl_add_gpio_range(pctldev, &pin_range->range); - pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PINGRP %s\n", - chip->label, gpio_offset, - gpio_offset + pin_range->range.npins - 1, + chip_dbg(chip, "created GPIO range %d->%d ==> %s PINGRP %s\n", + gpio_offset, gpio_offset + pin_range->range.npins - 1, pinctrl_dev_get_devname(pctldev), pin_group); list_add_tail(&pin_range->node, &chip->pin_ranges); @@ -1390,8 +1404,7 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); if (!pin_range) { - pr_err("%s: GPIO chip: failed to allocate pin ranges\n", - chip->label); + chip_err(chip, "failed to allocate pin ranges\n"); return -ENOMEM; } @@ -1406,13 +1419,12 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, &pin_range->range); if (IS_ERR(pin_range->pctldev)) { ret = PTR_ERR(pin_range->pctldev); - pr_err("%s: GPIO chip: could not create pin range\n", - chip->label); + chip_err(chip, "could not create pin range\n"); kfree(pin_range); return ret; } - pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PIN %d->%d\n", - chip->label, gpio_offset, gpio_offset + npins - 1, + chip_dbg(chip, "created GPIO range %d->%d ==> %s PIN %d->%d\n", + gpio_offset, gpio_offset + npins - 1, pinctl_name, pin_offset, pin_offset + npins - 1); @@ -1499,8 +1511,7 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) } done: if (status) - pr_debug("_gpio_request: gpio-%d (%s) status %d\n", - desc_to_gpio(desc), label ? : "?", status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); spin_unlock_irqrestore(&gpio_lock, flags); return status; } @@ -1701,7 +1712,7 @@ int gpiod_direction_input(struct gpio_desc *desc) if (!chip->get || !chip->direction_input) { gpiod_warn(desc, "%s: missing get() or direction_input() operations\n", - __func__); + __func__); return -EIO; } @@ -1721,7 +1732,8 @@ int gpiod_direction_input(struct gpio_desc *desc) if (status) { status = chip->request(chip, offset); if (status < 0) { - gpiod_dbg(desc, "chip request fail, %d\n", status); + gpiod_dbg(desc, "%s: chip request fail, %d\n", + __func__, status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1739,7 +1751,7 @@ lose: fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - gpiod_dbg(desc, "%s status %d\n", __func__, status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } EXPORT_SYMBOL_GPL(gpiod_direction_input); @@ -1806,7 +1818,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) if (status) { status = chip->request(chip, offset); if (status < 0) { - gpiod_dbg(desc, "chip request fail, %d\n", status); + gpiod_dbg(desc, "%s: chip request fail, %d\n", + __func__, status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -2259,18 +2272,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); /** - * gpiod_add_table() - register GPIO device consumers - * @table: array of consumers to register - * @num: number of consumers in table + * gpiod_add_lookup_table() - register GPIO device consumers + * @table: table of consumers to register */ -void gpiod_add_table(struct gpiod_lookup *table, size_t size) +void gpiod_add_lookup_table(struct gpiod_lookup_table *table) { mutex_lock(&gpio_lookup_lock); - while (size--) { - list_add_tail(&table->list, &gpio_lookup_list); - table++; - } + list_add_tail(&table->list, &gpio_lookup_list); mutex_unlock(&gpio_lookup_lock); } @@ -2326,76 +2335,92 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, return desc; } -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, - unsigned int idx, - enum gpio_lookup_flags *flags) +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) { const char *dev_id = dev ? dev_name(dev) : NULL; - struct gpio_desc *desc = ERR_PTR(-ENODEV); - unsigned int match, best = 0; - struct gpiod_lookup *p; + struct gpiod_lookup_table *table; mutex_lock(&gpio_lookup_lock); - list_for_each_entry(p, &gpio_lookup_list, list) { - match = 0; + list_for_each_entry(table, &gpio_lookup_list, list) { + if (table->dev_id && dev_id) { + /* + * Valid strings on both ends, must be identical to have + * a match + */ + if (!strcmp(table->dev_id, dev_id)) + goto found; + } else { + /* + * One of the pointers is NULL, so both must be to have + * a match + */ + if (dev_id == table->dev_id) + goto found; + } + } + table = NULL; - if (p->dev_id) { - if (!dev_id || strcmp(p->dev_id, dev_id)) - continue; +found: + mutex_unlock(&gpio_lookup_lock); + return table; +} - match += 2; - } +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, + unsigned int idx, + enum gpio_lookup_flags *flags) +{ + struct gpio_desc *desc = ERR_PTR(-ENOENT); + struct gpiod_lookup_table *table; + struct gpiod_lookup *p; - if (p->con_id) { - if (!con_id || strcmp(p->con_id, con_id)) - continue; + table = gpiod_find_lookup_table(dev); + if (!table) + return desc; - match += 1; - } + for (p = &table->table[0]; p->chip_label; p++) { + struct gpio_chip *chip; + /* idx must always match exactly */ if (p->idx != idx) continue; - if (match > best) { - struct gpio_chip *chip; + /* If the lookup entry has a con_id, require exact match */ + if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) + continue; - chip = find_chip_by_name(p->chip_label); + chip = find_chip_by_name(p->chip_label); - if (!chip) { - dev_warn(dev, "cannot find GPIO chip %s\n", - p->chip_label); - continue; - } + if (!chip) { + dev_err(dev, "cannot find GPIO chip %s\n", + p->chip_label); + return ERR_PTR(-ENODEV); + } - if (chip->ngpio <= p->chip_hwnum) { - dev_warn(dev, "GPIO chip %s has %d GPIOs\n", - chip->label, chip->ngpio); - continue; - } + if (chip->ngpio <= p->chip_hwnum) { + dev_err(dev, + "requested GPIO %d is out of range [0..%d] for chip %s\n", + idx, chip->ngpio, chip->label); + return ERR_PTR(-EINVAL); + } - desc = gpio_to_desc(chip->base + p->chip_hwnum); - *flags = p->flags; + desc = gpiochip_offset_to_desc(chip, p->chip_hwnum); + *flags = p->flags; - if (match != 3) - best = match; - else - break; - } + return desc; } - mutex_unlock(&gpio_lookup_lock); - return desc; } /** * gpio_get - obtain a GPIO for a given GPIO function - * @dev: GPIO consumer + * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer * * Return the GPIO descriptor corresponding to the function con_id of device - * dev, or an IS_ERR() condition if an error occured. + * dev, -ENOENT if no GPIO has been assigned to the requested function, or + * another IS_ERR() code if an error occured while trying to acquire the GPIO. */ struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id) { @@ -2405,14 +2430,16 @@ EXPORT_SYMBOL_GPL(gpiod_get); /** * gpiod_get_index - obtain a GPIO from a multi-index GPIO function - * @dev: GPIO consumer + * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer * @idx: index of the GPIO to obtain in the consumer * * This variant of gpiod_get() allows to access GPIOs other than the first * defined one for functions that define several GPIOs. * - * Return a valid GPIO descriptor, or an IS_ERR() condition in case of error. + * Return a valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the + * requested function and/or index, or another IS_ERR() code if an error + * occured while trying to acquire the GPIO. */ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, const char *con_id, @@ -2437,13 +2464,9 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, * Either we are not using DT or ACPI, or their lookup did not return * a result. In that case, use platform lookup as a fallback. */ - if (!desc || IS_ERR(desc)) { - struct gpio_desc *pdesc; + if (!desc || desc == ERR_PTR(-ENOENT)) { dev_dbg(dev, "using lookup tables for GPIO lookup"); - pdesc = gpiod_find(dev, con_id, idx, &flags); - /* If used as fallback, do not replace the previous error */ - if (!IS_ERR(pdesc) || !desc) - desc = pdesc; + desc = gpiod_find(dev, con_id, idx, &flags); } if (IS_ERR(desc)) { diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h new file mode 100644 index 00000000000..82be586c1f9 --- /dev/null +++ b/drivers/gpio/gpiolib.h @@ -0,0 +1,46 @@ +/* + * Internal GPIO functions. + * + * Copyright (C) 2013, Intel Corporation + * Author: Mika Westerberg <mika.westerberg@linux.intel.com> + * + * 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. + */ + +#ifndef GPIOLIB_H +#define GPIOLIB_H + +#include <linux/err.h> +#include <linux/device.h> + +/** + * struct acpi_gpio_info - ACPI GPIO specific information + * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo + * @active_low: in case of @gpioint, the pin is active low + */ +struct acpi_gpio_info { + bool gpioint; + bool active_low; +}; + +#ifdef CONFIG_ACPI +void acpi_gpiochip_add(struct gpio_chip *chip); +void acpi_gpiochip_remove(struct gpio_chip *chip); + +struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, + struct acpi_gpio_info *info); +#else +static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } +static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } + +static inline struct gpio_desc * +acpi_get_gpiod_by_index(struct device *dev, int index, + struct acpi_gpio_info *info) +{ + return ERR_PTR(-ENOSYS); +} +#endif + +#endif /* GPIOLIB_H */ |