diff options
Diffstat (limited to 'drivers/gpio')
37 files changed, 1639 insertions, 220 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a116609b1914..98dd47a30fc7 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -49,7 +49,7 @@ config GPIO_DEVRES  config OF_GPIO  	def_bool y -	depends on OF || COMPILE_TEST +	depends on OF  config GPIO_ACPI  	def_bool y @@ -250,7 +250,7 @@ config GPIO_LOONGSON  	  driver for GPIO functionality on Loongson-2F/3A/3B processors.  config GPIO_LPC18XX -	bool "NXP LPC18XX/43XX GPIO support" +	tristate "NXP LPC18XX/43XX GPIO support"  	default y if ARCH_LPC18XX  	depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST)  	help @@ -402,9 +402,12 @@ config GPIO_TB10X  	select OF_GPIO  config GPIO_TEGRA -	bool -	default y +	bool "NVIDIA Tegra GPIO support" +	default ARCH_TEGRA  	depends on ARCH_TEGRA || COMPILE_TEST +	depends on OF +	help +	  Say yes here to support GPIO pins on NVIDIA Tegra SoCs.  config GPIO_TS4800  	tristate "TS-4800 DIO blocks and compatibles" @@ -531,7 +534,7 @@ menu "Port-mapped I/O GPIO drivers"  config GPIO_104_DIO_48E  	tristate "ACCES 104-DIO-48E GPIO support" -	depends on ISA +	depends on ISA_BUS_API  	select GPIOLIB_IRQCHIP  	help  	  Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, @@ -541,7 +544,7 @@ config GPIO_104_DIO_48E  config GPIO_104_IDIO_16  	tristate "ACCES 104-IDIO-16 GPIO support" -	depends on ISA +	depends on ISA_BUS_API  	select GPIOLIB_IRQCHIP  	help  	  Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16, @@ -552,7 +555,7 @@ config GPIO_104_IDIO_16  config GPIO_104_IDI_48  	tristate "ACCES 104-IDI-48 GPIO support" -	depends on ISA +	depends on ISA_BUS_API  	select GPIOLIB_IRQCHIP  	help  	  Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A, @@ -628,7 +631,7 @@ config GPIO_TS5500  config GPIO_WS16C48  	tristate "WinSystems WS16C48 GPIO support" -	depends on ISA +	depends on ISA_BUS_API  	select GPIOLIB_IRQCHIP  	help  	  Enables GPIO support for the WinSystems WS16C48. The base port @@ -871,6 +874,15 @@ config GPIO_LP3943  	  LP3943 can be used as a GPIO expander which provides up to 16 GPIOs.  	  Open drain outputs are required for this usage. +config GPIO_MAX77620 +	tristate "GPIO support for PMIC MAX77620 and MAX20024" +	depends on MFD_MAX77620 +	help +	  GPIO driver for MAX77620 and MAX20024 PMIC from Maxim Semiconductor. +	  MAX77620 PMIC has 8 pins that can be configured as GPIOs. The +	  driver also provides interrupt support for each of the gpios. +	  Say yes here to enable the max77620 to be used as gpio controller. +  config GPIO_MSIC  	bool "Intel MSIC mixed signal gpio support"  	depends on MFD_INTEL_MSIC @@ -1026,11 +1038,18 @@ config GPIO_BT8XX  	  If unsure, say N.  config GPIO_INTEL_MID -	bool "Intel Mid GPIO support" -	depends on X86 +	bool "Intel MID GPIO support" +	depends on X86_INTEL_MID +	select GPIOLIB_IRQCHIP +	help +	  Say Y here to support Intel MID GPIO. + +config GPIO_MERRIFIELD +	tristate "Intel Merrifield GPIO support" +	depends on X86_INTEL_MID  	select GPIOLIB_IRQCHIP  	help -	  Say Y here to support Intel Mid GPIO. +	  Say Y here to support Intel Merrifield GPIO.  config GPIO_ML_IOH  	tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 991598ea3fba..2a035ed8f168 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -61,8 +61,10 @@ obj-$(CONFIG_GPIO_MAX730X)	+= gpio-max730x.o  obj-$(CONFIG_GPIO_MAX7300)	+= gpio-max7300.o  obj-$(CONFIG_GPIO_MAX7301)	+= gpio-max7301.o  obj-$(CONFIG_GPIO_MAX732X)	+= gpio-max732x.o +obj-$(CONFIG_GPIO_MAX77620)	+= gpio-max77620.o  obj-$(CONFIG_GPIO_MB86S7X)	+= gpio-mb86s7x.o  obj-$(CONFIG_GPIO_MENZ127)	+= gpio-menz127.o +obj-$(CONFIG_GPIO_MERRIFIELD)	+= gpio-merrifield.o  obj-$(CONFIG_GPIO_MC33880)	+= gpio-mc33880.o  obj-$(CONFIG_GPIO_MC9S08DZ60)	+= gpio-mc9s08dz60.o  obj-$(CONFIG_GPIO_MCP23S08)	+= gpio-mcp23s08.o diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index 6c75c83baf5a..2d2763ea1a68 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -247,6 +247,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)  	idi48gpio->irq = irq[id];  	spin_lock_init(&idi48gpio->lock); +	spin_lock_init(&idi48gpio->ack_lock);  	dev_set_drvdata(dev, idi48gpio); diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 80f9ddf13343..a6607faf2fdf 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -35,13 +35,8 @@ struct gen_74x164_chip {  static int __gen_74x164_write_config(struct gen_74x164_chip *chip)  { -	struct spi_transfer xfer = { -		.tx_buf = chip->buffer, -		.len = chip->registers, -	}; - -	return spi_sync_transfer(to_spi_device(chip->gpio_chip.parent), -				 &xfer, 1); +	return spi_write(to_spi_device(chip->gpio_chip.parent), chip->buffer, +			 chip->registers);  }  static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index 5a690256af9b..52fd63f02134 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -20,8 +20,12 @@ static int clps711x_gpio_probe(struct platform_device *pdev)  	void __iomem *dat, *dir;  	struct gpio_chip *gc;  	struct resource *res; -	int err, id = np ? of_alias_get_id(np, "gpio") : pdev->id; +	int err, id; +	if (!np) +		return -ENODEV; + +	id = of_alias_get_id(np, "gpio");  	if ((id < 0) || (id > 4))  		return -ENODEV; @@ -63,7 +67,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev)  		break;  	} -	gc->base = id * 8; +	gc->base = -1;  	gc->owner = THIS_MODULE;  	platform_set_drvdata(pdev, gc); @@ -71,7 +75,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev)  }  static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = { -	{ .compatible = "cirrus,clps711x-gpio" }, +	{ .compatible = "cirrus,ep7209-gpio" },  	{ }  };  MODULE_DEVICE_TABLE(of, clps711x_gpio_ids); diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 34779bb375de..6193f62c0df4 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -486,6 +486,7 @@ dwapb_gpio_get_pdata(struct device *dev)  		    pp->idx >= DWAPB_MAX_PORTS) {  			dev_err(dev,  				"missing/invalid port index for port%d\n", i); +			fwnode_handle_put(fwnode);  			return ERR_PTR(-EINVAL);  		} diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 05aa538c3767..600be8418707 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -125,6 +125,7 @@ static inline void superio_exit(int base)   * GPIO chip.   */ +static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset);  static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset);  static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset);  static int f7188x_gpio_direction_out(struct gpio_chip *chip, @@ -139,6 +140,7 @@ static int f7188x_gpio_set_single_ended(struct gpio_chip *gc,  		.chip = {						\  			.label            = DRVNAME,			\  			.owner            = THIS_MODULE,		\ +			.get_direction    = f7188x_gpio_get_direction,	\  			.direction_input  = f7188x_gpio_direction_in,	\  			.get              = f7188x_gpio_get,		\  			.direction_output = f7188x_gpio_direction_out,	\ @@ -209,6 +211,26 @@ static struct f7188x_gpio_bank f81866_gpio_bank[] = {  	F7188X_GPIO_BANK(80, 8, 0x88),  }; +static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ +	int err; +	struct f7188x_gpio_bank *bank = +		container_of(chip, struct f7188x_gpio_bank, chip); +	struct f7188x_sio *sio = bank->data->sio; +	u8 dir; + +	err = superio_enter(sio->addr); +	if (err) +		return err; +	superio_select(sio->addr, SIO_LD_GPIO); + +	dir = superio_inb(sio->addr, gpio_dir(bank->regbase)); + +	superio_exit(sio->addr); + +	return !(dir & 1 << offset); +} +  static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)  {  	int err; diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index cdaba13cb8e8..164de64b11fc 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -1,7 +1,7 @@  /*   * Intel MID GPIO driver   * - * Copyright (c) 2008-2014 Intel Corporation. + * Copyright (c) 2008-2014,2016 Intel Corporation.   *   * 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 @@ -17,21 +17,20 @@   * Moorestown platform Langwell chip.   * Medfield platform Penwell chip.   * Clovertrail platform Cloverview chip. - * Merrifield platform Tangier chip.   */ -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/platform_device.h> -#include <linux/kernel.h>  #include <linux/delay.h> -#include <linux/stddef.h> -#include <linux/interrupt.h>  #include <linux/init.h> +#include <linux/interrupt.h>  #include <linux/io.h>  #include <linux/gpio/driver.h> -#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h>  #include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/stddef.h>  #define INTEL_MID_IRQ_TYPE_EDGE		(1 << 0)  #define INTEL_MID_IRQ_TYPE_LEVEL	(1 << 1) @@ -64,10 +63,6 @@ enum GPIO_REG {  /* intel_mid gpio driver data */  struct intel_mid_gpio_ddata {  	u16 ngpio;		/* number of gpio pins */ -	u32 gplr_offset;	/* offset of first GPLR register from base */ -	u32 flis_base;		/* base address of FLIS registers */ -	u32 flis_len;		/* length of FLIS registers */ -	u32 (*get_flis_offset)(int gpio);  	u32 chip_irq_type;	/* chip interrupt type */  }; @@ -252,15 +247,6 @@ static const struct intel_mid_gpio_ddata gpio_cloverview_core = {  	.chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,  }; -static const struct intel_mid_gpio_ddata gpio_tangier = { -	.ngpio = 192, -	.gplr_offset = 4, -	.flis_base = 0xff0c0000, -	.flis_len = 0x8000, -	.get_flis_offset = NULL, -	.chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, -}; -  static const struct pci_device_id intel_gpio_ids[] = {  	{  		/* Lincroft */ @@ -287,11 +273,6 @@ static const struct pci_device_id intel_gpio_ids[] = {  		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7),  		.driver_data = (kernel_ulong_t)&gpio_cloverview_core,  	}, -	{ -		/* Tangier */ -		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199), -		.driver_data = (kernel_ulong_t)&gpio_tangier, -	},  	{ 0 }  };  MODULE_DEVICE_TABLE(pci, intel_gpio_ids); @@ -401,7 +382,7 @@ static int intel_gpio_probe(struct pci_dev *pdev,  	spin_lock_init(&priv->lock);  	pci_set_drvdata(pdev, priv); -	retval = gpiochip_add_data(&priv->chip, priv); +	retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);  	if (retval) {  		dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);  		return retval; diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 9df015e85ad9..fbd393b46ce0 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -383,7 +383,6 @@ static int lp_gpio_probe(struct platform_device *pdev)  					   handle_simple_irq, IRQ_TYPE_NONE);  		if (ret) {  			dev_err(dev, "failed to add irqchip\n"); -			gpiochip_remove(gc);  			return ret;  		} diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c new file mode 100644 index 000000000000..b46b436cb97f --- /dev/null +++ b/drivers/gpio/gpio-max77620.c @@ -0,0 +1,315 @@ +/* + * MAXIM MAX77620 GPIO driver + * + * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/gpio/driver.h> +#include <linux/interrupt.h> +#include <linux/mfd/max77620.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#define GPIO_REG_ADDR(offset) (MAX77620_REG_GPIO0 + offset) + +struct max77620_gpio { +	struct gpio_chip	gpio_chip; +	struct regmap		*rmap; +	struct device		*dev; +	int			gpio_irq; +	int			irq_base; +	int			gpio_base; +}; + +static const struct regmap_irq max77620_gpio_irqs[] = { +	[0] = { +		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE0, +		.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, +		.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, +		.reg_offset = 0, +		.type_reg_offset = 0, +	}, +	[1] = { +		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE1, +		.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, +		.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, +		.reg_offset = 0, +		.type_reg_offset = 1, +	}, +	[2] = { +		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE2, +		.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, +		.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, +		.reg_offset = 0, +		.type_reg_offset = 2, +	}, +	[3] = { +		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE3, +		.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, +		.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, +		.reg_offset = 0, +		.type_reg_offset = 3, +	}, +	[4] = { +		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE4, +		.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, +		.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, +		.reg_offset = 0, +		.type_reg_offset = 4, +	}, +	[5] = { +		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE5, +		.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, +		.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, +		.reg_offset = 0, +		.type_reg_offset = 5, +	}, +	[6] = { +		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE6, +		.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, +		.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, +		.reg_offset = 0, +		.type_reg_offset = 6, +	}, +	[7] = { +		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE7, +		.type_rising_mask = MAX77620_CNFG_GPIO_INT_RISING, +		.type_falling_mask = MAX77620_CNFG_GPIO_INT_FALLING, +		.reg_offset = 0, +		.type_reg_offset = 7, +	}, +}; + +static struct regmap_irq_chip max77620_gpio_irq_chip = { +	.name = "max77620-gpio", +	.irqs = max77620_gpio_irqs, +	.num_irqs = ARRAY_SIZE(max77620_gpio_irqs), +	.num_regs = 1, +	.num_type_reg = 8, +	.irq_reg_stride = 1, +	.type_reg_stride = 1, +	.status_base = MAX77620_REG_IRQ_LVL2_GPIO, +	.type_base = MAX77620_REG_GPIO0, +}; + +static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset) +{ +	struct max77620_gpio *mgpio = gpiochip_get_data(gc); +	int ret; + +	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), +				 MAX77620_CNFG_GPIO_DIR_MASK, +				 MAX77620_CNFG_GPIO_DIR_INPUT); +	if (ret < 0) +		dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret); + +	return ret; +} + +static int max77620_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ +	struct max77620_gpio *mgpio = gpiochip_get_data(gc); +	unsigned int val; +	int ret; + +	ret = regmap_read(mgpio->rmap, GPIO_REG_ADDR(offset), &val); +	if (ret < 0) { +		dev_err(mgpio->dev, "CNFG_GPIOx read failed: %d\n", ret); +		return ret; +	} + +	if  (val & MAX77620_CNFG_GPIO_DIR_MASK) +		return !!(val & MAX77620_CNFG_GPIO_INPUT_VAL_MASK); +	else +		return !!(val & MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK); +} + +static int max77620_gpio_dir_output(struct gpio_chip *gc, unsigned int offset, +				    int value) +{ +	struct max77620_gpio *mgpio = gpiochip_get_data(gc); +	u8 val; +	int ret; + +	val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH : +				MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW; + +	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), +				 MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val); +	if (ret < 0) { +		dev_err(mgpio->dev, "CNFG_GPIOx val update failed: %d\n", ret); +		return ret; +	} + +	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), +				 MAX77620_CNFG_GPIO_DIR_MASK, +				 MAX77620_CNFG_GPIO_DIR_OUTPUT); +	if (ret < 0) +		dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d\n", ret); + +	return ret; +} + +static int max77620_gpio_set_debounce(struct gpio_chip *gc, +				      unsigned int offset, +				      unsigned int debounce) +{ +	struct max77620_gpio *mgpio = gpiochip_get_data(gc); +	u8 val; +	int ret; + +	switch (debounce) { +	case 0: +		val = MAX77620_CNFG_GPIO_DBNC_None; +		break; +	case 1 ... 8: +		val = MAX77620_CNFG_GPIO_DBNC_8ms; +		break; +	case 9 ... 16: +		val = MAX77620_CNFG_GPIO_DBNC_16ms; +		break; +	case 17 ... 32: +		val = MAX77620_CNFG_GPIO_DBNC_32ms; +		break; +	default: +		dev_err(mgpio->dev, "Illegal value %u\n", debounce); +		return -EINVAL; +	} + +	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), +				 MAX77620_CNFG_GPIO_DBNC_MASK, val); +	if (ret < 0) +		dev_err(mgpio->dev, "CNFG_GPIOx_DBNC update failed: %d\n", ret); + +	return ret; +} + +static void max77620_gpio_set(struct gpio_chip *gc, unsigned int offset, +			      int value) +{ +	struct max77620_gpio *mgpio = gpiochip_get_data(gc); +	u8 val; +	int ret; + +	val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH : +				MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW; + +	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), +				 MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val); +	if (ret < 0) +		dev_err(mgpio->dev, "CNFG_GPIO_OUT update failed: %d\n", ret); +} + +static int max77620_gpio_set_single_ended(struct gpio_chip *gc, +					  unsigned int offset, +					  enum single_ended_mode mode) +{ +	struct max77620_gpio *mgpio = gpiochip_get_data(gc); + +	switch (mode) { +	case LINE_MODE_OPEN_DRAIN: +		return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), +					  MAX77620_CNFG_GPIO_DRV_MASK, +					  MAX77620_CNFG_GPIO_DRV_OPENDRAIN); +	case LINE_MODE_PUSH_PULL: +		return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset), +					  MAX77620_CNFG_GPIO_DRV_MASK, +					  MAX77620_CNFG_GPIO_DRV_PUSHPULL); +	default: +		break; +	} + +	return -ENOTSUPP; +} + +static int max77620_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) +{ +	struct max77620_gpio *mgpio = gpiochip_get_data(gc); +	struct max77620_chip *chip = dev_get_drvdata(mgpio->dev->parent); + +	return regmap_irq_get_virq(chip->gpio_irq_data, offset); +} + +static int max77620_gpio_probe(struct platform_device *pdev) +{ +	struct max77620_chip *chip =  dev_get_drvdata(pdev->dev.parent); +	struct max77620_gpio *mgpio; +	int gpio_irq; +	int ret; + +	gpio_irq = platform_get_irq(pdev, 0); +	if (gpio_irq <= 0) { +		dev_err(&pdev->dev, "GPIO irq not available %d\n", gpio_irq); +		return -ENODEV; +	} + +	mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL); +	if (!mgpio) +		return -ENOMEM; + +	mgpio->rmap = chip->rmap; +	mgpio->dev = &pdev->dev; +	mgpio->gpio_irq = gpio_irq; + +	mgpio->gpio_chip.label = pdev->name; +	mgpio->gpio_chip.parent = &pdev->dev; +	mgpio->gpio_chip.direction_input = max77620_gpio_dir_input; +	mgpio->gpio_chip.get = max77620_gpio_get; +	mgpio->gpio_chip.direction_output = max77620_gpio_dir_output; +	mgpio->gpio_chip.set_debounce = max77620_gpio_set_debounce; +	mgpio->gpio_chip.set = max77620_gpio_set; +	mgpio->gpio_chip.set_single_ended = max77620_gpio_set_single_ended; +	mgpio->gpio_chip.to_irq = max77620_gpio_to_irq; +	mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR; +	mgpio->gpio_chip.can_sleep = 1; +	mgpio->gpio_chip.base = -1; +	mgpio->irq_base = -1; +#ifdef CONFIG_OF_GPIO +	mgpio->gpio_chip.of_node = pdev->dev.parent->of_node; +#endif + +	platform_set_drvdata(pdev, mgpio); + +	ret = devm_gpiochip_add_data(&pdev->dev, &mgpio->gpio_chip, mgpio); +	if (ret < 0) { +		dev_err(&pdev->dev, "gpio_init: Failed to add max77620_gpio\n"); +		return ret; +	} + +	mgpio->gpio_base = mgpio->gpio_chip.base; +	ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, mgpio->gpio_irq, +				       IRQF_ONESHOT, mgpio->irq_base, +				       &max77620_gpio_irq_chip, +				       &chip->gpio_irq_data); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to add gpio irq_chip %d\n", ret); +		return ret; +	} + +	return 0; +} + +static const struct platform_device_id max77620_gpio_devtype[] = { +	{ .name = "max77620-gpio", }, +	{}, +}; +MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype); + +static struct platform_driver max77620_gpio_driver = { +	.driver.name	= "max77620-gpio", +	.probe		= max77620_gpio_probe, +	.id_table	= max77620_gpio_devtype, +}; + +module_platform_driver(max77620_gpio_driver); + +MODULE_DESCRIPTION("GPIO interface for MAX77620 and MAX20024 PMIC"); +MODULE_AUTHOR("Laxman Dewangan <[email protected]>"); +MODULE_AUTHOR("Chaitanya Bandi <[email protected]>"); +MODULE_ALIAS("platform:max77620-gpio"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c index cc103aff45e4..a1210e330571 100644 --- a/drivers/gpio/gpio-menz127.c +++ b/drivers/gpio/gpio-menz127.c @@ -187,7 +187,6 @@ MODULE_DEVICE_TABLE(mcb, men_z127_ids);  static struct mcb_driver men_z127_driver = {  	.driver = {  		.name = "z127-gpio", -		.owner = THIS_MODULE,  	},  	.probe = men_z127_probe,  	.remove = men_z127_remove, diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c new file mode 100644 index 000000000000..45b51278b8ee --- /dev/null +++ b/drivers/gpio/gpio-merrifield.c @@ -0,0 +1,444 @@ +/* + * Intel Merrifield SoC GPIO driver + * + * Copyright (c) 2016 Intel Corporation. + * Author: Andy Shevchenko <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/bitops.h> +#include <linux/gpio/driver.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/pinctrl/consumer.h> + +#define GCCR		0x000	/* controller configuration */ +#define GPLR		0x004	/* pin level r/o */ +#define GPDR		0x01c	/* pin direction */ +#define GPSR		0x034	/* pin set w/o */ +#define GPCR		0x04c	/* pin clear w/o */ +#define GRER		0x064	/* rising edge detect */ +#define GFER		0x07c	/* falling edge detect */ +#define GFBR		0x094	/* glitch filter bypass */ +#define GIMR		0x0ac	/* interrupt mask */ +#define GISR		0x0c4	/* interrupt source */ +#define GITR		0x300	/* input type */ +#define GLPR		0x318	/* level input polarity */ +#define GWMR		0x400	/* wake mask */ +#define GWSR		0x418	/* wake source */ +#define GSIR		0xc00	/* secure input */ + +/* Intel Merrifield has 192 GPIO pins */ +#define MRFLD_NGPIO	192 + +struct mrfld_gpio_pinrange { +	unsigned int gpio_base; +	unsigned int pin_base; +	unsigned int npins; +}; + +#define GPIO_PINRANGE(gstart, gend, pstart)		\ +	{						\ +		.gpio_base = (gstart),			\ +		.pin_base = (pstart),			\ +		.npins = (gend) - (gstart) + 1,		\ +	} + +struct mrfld_gpio { +	struct gpio_chip	chip; +	void __iomem		*reg_base; +	raw_spinlock_t		lock; +	struct device		*dev; +}; + +static const struct mrfld_gpio_pinrange mrfld_gpio_ranges[] = { +	GPIO_PINRANGE(0, 11, 146), +	GPIO_PINRANGE(12, 13, 144), +	GPIO_PINRANGE(14, 15, 35), +	GPIO_PINRANGE(16, 16, 164), +	GPIO_PINRANGE(17, 18, 105), +	GPIO_PINRANGE(19, 22, 101), +	GPIO_PINRANGE(23, 30, 107), +	GPIO_PINRANGE(32, 43, 67), +	GPIO_PINRANGE(44, 63, 195), +	GPIO_PINRANGE(64, 67, 140), +	GPIO_PINRANGE(68, 69, 165), +	GPIO_PINRANGE(70, 71, 65), +	GPIO_PINRANGE(72, 76, 228), +	GPIO_PINRANGE(77, 86, 37), +	GPIO_PINRANGE(87, 87, 48), +	GPIO_PINRANGE(88, 88, 47), +	GPIO_PINRANGE(89, 96, 49), +	GPIO_PINRANGE(97, 97, 34), +	GPIO_PINRANGE(102, 119, 83), +	GPIO_PINRANGE(120, 123, 79), +	GPIO_PINRANGE(124, 135, 115), +	GPIO_PINRANGE(137, 142, 158), +	GPIO_PINRANGE(154, 163, 24), +	GPIO_PINRANGE(164, 176, 215), +	GPIO_PINRANGE(177, 189, 127), +	GPIO_PINRANGE(190, 191, 178), +}; + +static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset, +			      unsigned int reg_type_offset) +{ +	struct mrfld_gpio *priv = gpiochip_get_data(chip); +	u8 reg = offset / 32; + +	return priv->reg_base + reg_type_offset + reg * 4; +} + +static int mrfld_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ +	void __iomem *gplr = gpio_reg(chip, offset, GPLR); + +	return !!(readl(gplr) & BIT(offset % 32)); +} + +static void mrfld_gpio_set(struct gpio_chip *chip, unsigned int offset, +			   int value) +{ +	struct mrfld_gpio *priv = gpiochip_get_data(chip); +	void __iomem *gpsr, *gpcr; +	unsigned long flags; + +	raw_spin_lock_irqsave(&priv->lock, flags); + +	if (value) { +		gpsr = gpio_reg(chip, offset, GPSR); +		writel(BIT(offset % 32), gpsr); +	} else { +		gpcr = gpio_reg(chip, offset, GPCR); +		writel(BIT(offset % 32), gpcr); +	} + +	raw_spin_unlock_irqrestore(&priv->lock, flags); +} + +static int mrfld_gpio_direction_input(struct gpio_chip *chip, +				      unsigned int offset) +{ +	struct mrfld_gpio *priv = gpiochip_get_data(chip); +	void __iomem *gpdr = gpio_reg(chip, offset, GPDR); +	unsigned long flags; +	u32 value; + +	raw_spin_lock_irqsave(&priv->lock, flags); + +	value = readl(gpdr); +	value &= ~BIT(offset % 32); +	writel(value, gpdr); + +	raw_spin_unlock_irqrestore(&priv->lock, flags); + +	return 0; +} + +static int mrfld_gpio_direction_output(struct gpio_chip *chip, +				       unsigned int offset, int value) +{ +	struct mrfld_gpio *priv = gpiochip_get_data(chip); +	void __iomem *gpdr = gpio_reg(chip, offset, GPDR); +	unsigned long flags; + +	mrfld_gpio_set(chip, offset, value); + +	raw_spin_lock_irqsave(&priv->lock, flags); + +	value = readl(gpdr); +	value |= BIT(offset % 32); +	writel(value, gpdr); + +	raw_spin_unlock_irqrestore(&priv->lock, flags); + +	return 0; +} + +static void mrfld_irq_ack(struct irq_data *d) +{ +	struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d); +	u32 gpio = irqd_to_hwirq(d); +	void __iomem *gisr = gpio_reg(&priv->chip, gpio, GISR); +	unsigned long flags; + +	raw_spin_lock_irqsave(&priv->lock, flags); + +	writel(BIT(gpio % 32), gisr); + +	raw_spin_unlock_irqrestore(&priv->lock, flags); +} + +static void mrfld_irq_unmask_mask(struct irq_data *d, bool unmask) +{ +	struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d); +	u32 gpio = irqd_to_hwirq(d); +	void __iomem *gimr = gpio_reg(&priv->chip, gpio, GIMR); +	unsigned long flags; +	u32 value; + +	raw_spin_lock_irqsave(&priv->lock, flags); + +	if (unmask) +		value = readl(gimr) | BIT(gpio % 32); +	else +		value = readl(gimr) & ~BIT(gpio % 32); +	writel(value, gimr); + +	raw_spin_unlock_irqrestore(&priv->lock, flags); +} + +static void mrfld_irq_mask(struct irq_data *d) +{ +	mrfld_irq_unmask_mask(d, false); +} + +static void mrfld_irq_unmask(struct irq_data *d) +{ +	mrfld_irq_unmask_mask(d, true); +} + +static int mrfld_irq_set_type(struct irq_data *d, unsigned int type) +{ +	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); +	struct mrfld_gpio *priv = gpiochip_get_data(gc); +	u32 gpio = irqd_to_hwirq(d); +	void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); +	void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); +	void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR); +	void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR); +	unsigned long flags; +	u32 value; + +	raw_spin_lock_irqsave(&priv->lock, flags); + +	if (type & IRQ_TYPE_EDGE_RISING) +		value = readl(grer) | BIT(gpio % 32); +	else +		value = readl(grer) & ~BIT(gpio % 32); +	writel(value, grer); + +	if (type & IRQ_TYPE_EDGE_FALLING) +		value = readl(gfer) | BIT(gpio % 32); +	else +		value = readl(gfer) & ~BIT(gpio % 32); +	writel(value, gfer); + +	/* +	 * To prevent glitches from triggering an unintended level interrupt, +	 * configure GLPR register first and then configure GITR. +	 */ +	if (type & IRQ_TYPE_LEVEL_LOW) +		value = readl(glpr) | BIT(gpio % 32); +	else +		value = readl(glpr) & ~BIT(gpio % 32); +	writel(value, glpr); + +	if (type & IRQ_TYPE_LEVEL_MASK) { +		value = readl(gitr) | BIT(gpio % 32); +		writel(value, gitr); + +		irq_set_handler_locked(d, handle_level_irq); +	} else if (type & IRQ_TYPE_EDGE_BOTH) { +		value = readl(gitr) & ~BIT(gpio % 32); +		writel(value, gitr); + +		irq_set_handler_locked(d, handle_edge_irq); +	} + +	raw_spin_unlock_irqrestore(&priv->lock, flags); + +	return 0; +} + +static int mrfld_irq_set_wake(struct irq_data *d, unsigned int on) +{ +	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); +	struct mrfld_gpio *priv = gpiochip_get_data(gc); +	u32 gpio = irqd_to_hwirq(d); +	void __iomem *gwmr = gpio_reg(&priv->chip, gpio, GWMR); +	void __iomem *gwsr = gpio_reg(&priv->chip, gpio, GWSR); +	unsigned long flags; +	u32 value; + +	raw_spin_lock_irqsave(&priv->lock, flags); + +	/* Clear the existing wake status */ +	writel(BIT(gpio % 32), gwsr); + +	if (on) +		value = readl(gwmr) | BIT(gpio % 32); +	else +		value = readl(gwmr) & ~BIT(gpio % 32); +	writel(value, gwmr); + +	raw_spin_unlock_irqrestore(&priv->lock, flags); + +	dev_dbg(priv->dev, "%sable wake for gpio %u\n", on ? "en" : "dis", gpio); +	return 0; +} + +static struct irq_chip mrfld_irqchip = { +	.name		= "gpio-merrifield", +	.irq_ack	= mrfld_irq_ack, +	.irq_mask	= mrfld_irq_mask, +	.irq_unmask	= mrfld_irq_unmask, +	.irq_set_type	= mrfld_irq_set_type, +	.irq_set_wake	= mrfld_irq_set_wake, +}; + +static void mrfld_irq_handler(struct irq_desc *desc) +{ +	struct gpio_chip *gc = irq_desc_get_handler_data(desc); +	struct mrfld_gpio *priv = gpiochip_get_data(gc); +	struct irq_chip *irqchip = irq_desc_get_chip(desc); +	unsigned long base, gpio; + +	chained_irq_enter(irqchip, desc); + +	/* Check GPIO controller to check which pin triggered the interrupt */ +	for (base = 0; base < priv->chip.ngpio; base += 32) { +		void __iomem *gisr = gpio_reg(&priv->chip, base, GISR); +		void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR); +		unsigned long pending, enabled; + +		pending = readl(gisr); +		enabled = readl(gimr); + +		/* Only interrupts that are enabled */ +		pending &= enabled; + +		for_each_set_bit(gpio, &pending, 32) { +			unsigned int irq; + +			irq = irq_find_mapping(gc->irqdomain, base + gpio); +			generic_handle_irq(irq); +		} +	} + +	chained_irq_exit(irqchip, desc); +} + +static void mrfld_irq_init_hw(struct mrfld_gpio *priv) +{ +	void __iomem *reg; +	unsigned int base; + +	for (base = 0; base < priv->chip.ngpio; base += 32) { +		/* Clear the rising-edge detect register */ +		reg = gpio_reg(&priv->chip, base, GRER); +		writel(0, reg); +		/* Clear the falling-edge detect register */ +		reg = gpio_reg(&priv->chip, base, GFER); +		writel(0, reg); +	} +} + +static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ +	const struct mrfld_gpio_pinrange *range; +	struct mrfld_gpio *priv; +	u32 gpio_base, irq_base; +	void __iomem *base; +	unsigned int i; +	int retval; + +	retval = pcim_enable_device(pdev); +	if (retval) +		return retval; + +	retval = pcim_iomap_regions(pdev, BIT(1) | BIT(0), pci_name(pdev)); +	if (retval) { +		dev_err(&pdev->dev, "I/O memory mapping error\n"); +		return retval; +	} + +	base = pcim_iomap_table(pdev)[1]; + +	irq_base = readl(base); +	gpio_base = readl(sizeof(u32) + base); + +	/* Release the IO mapping, since we already get the info from BAR1 */ +	pcim_iounmap_regions(pdev, BIT(1)); + +	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) { +		dev_err(&pdev->dev, "can't allocate chip data\n"); +		return -ENOMEM; +	} + +	priv->dev = &pdev->dev; +	priv->reg_base = pcim_iomap_table(pdev)[0]; + +	priv->chip.label = dev_name(&pdev->dev); +	priv->chip.parent = &pdev->dev; +	priv->chip.request = gpiochip_generic_request; +	priv->chip.free = gpiochip_generic_free; +	priv->chip.direction_input = mrfld_gpio_direction_input; +	priv->chip.direction_output = mrfld_gpio_direction_output; +	priv->chip.get = mrfld_gpio_get; +	priv->chip.set = mrfld_gpio_set; +	priv->chip.base = gpio_base; +	priv->chip.ngpio = MRFLD_NGPIO; +	priv->chip.can_sleep = false; + +	raw_spin_lock_init(&priv->lock); + +	pci_set_drvdata(pdev, priv); +	retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); +	if (retval) { +		dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); +		return retval; +	} + +	for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { +		range = &mrfld_gpio_ranges[i]; +		retval = gpiochip_add_pin_range(&priv->chip, +						"pinctrl-merrifield", +						range->gpio_base, +						range->pin_base, +						range->npins); +		if (retval) { +			dev_err(&pdev->dev, "failed to add GPIO pin range\n"); +			return retval; +		} +	} + +	retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, +				      handle_simple_irq, IRQ_TYPE_NONE); +	if (retval) { +		dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); +		return retval; +	} + +	mrfld_irq_init_hw(priv); + +	gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq, +				     mrfld_irq_handler); + +	return 0; +} + +static const struct pci_device_id mrfld_gpio_ids[] = { +	{ PCI_VDEVICE(INTEL, 0x1199) }, +	{ } +}; +MODULE_DEVICE_TABLE(pci, mrfld_gpio_ids); + +static struct pci_driver mrfld_gpio_driver = { +	.name		= "gpio-merrifield", +	.id_table	= mrfld_gpio_ids, +	.probe		= mrfld_gpio_probe, +}; + +module_pci_driver(mrfld_gpio_driver); + +MODULE_AUTHOR("Andy Shevchenko <[email protected]>"); +MODULE_DESCRIPTION("Intel Merrifield SoC GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 6c1cb3b8c02c..6ec144baeb11 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -61,6 +61,8 @@ o        `                     ~~~~\___/~~~~    ` controller in FPGA is ,.`  #include <linux/bitops.h>  #include <linux/platform_device.h>  #include <linux/mod_devicetable.h> +#include <linux/of.h> +#include <linux/of_device.h>  static void bgpio_write8(void __iomem *reg, unsigned long data)  { @@ -569,6 +571,41 @@ static void __iomem *bgpio_map(struct platform_device *pdev,  	return devm_ioremap_resource(&pdev->dev, r);  } +#ifdef CONFIG_OF +static const struct of_device_id bgpio_of_match[] = { +	{ .compatible = "wd,mbl-gpio" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, bgpio_of_match); + +static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, +					  unsigned long *flags) +{ +	struct bgpio_pdata *pdata; + +	if (!of_match_device(bgpio_of_match, &pdev->dev)) +		return NULL; + +	pdata = devm_kzalloc(&pdev->dev, sizeof(struct bgpio_pdata), +			     GFP_KERNEL); +	if (!pdata) +		return ERR_PTR(-ENOMEM); + +	pdata->base = -1; + +	if (of_property_read_bool(pdev->dev.of_node, "no-output")) +		*flags |= BGPIOF_NO_OUTPUT; + +	return pdata; +} +#else +static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, +					  unsigned long *flags) +{ +	return NULL; +} +#endif /* CONFIG_OF */ +  static int bgpio_pdev_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev; @@ -579,10 +616,19 @@ static int bgpio_pdev_probe(struct platform_device *pdev)  	void __iomem *dirout;  	void __iomem *dirin;  	unsigned long sz; -	unsigned long flags = pdev->id_entry->driver_data; +	unsigned long flags = 0;  	int err;  	struct gpio_chip *gc; -	struct bgpio_pdata *pdata = dev_get_platdata(dev); +	struct bgpio_pdata *pdata; + +	pdata = bgpio_parse_dt(pdev, &flags); +	if (IS_ERR(pdata)) +		return PTR_ERR(pdata); + +	if (!pdata) { +		pdata = dev_get_platdata(dev); +		flags = pdev->id_entry->driver_data; +	}  	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");  	if (!r) @@ -646,6 +692,7 @@ MODULE_DEVICE_TABLE(platform, bgpio_id_table);  static struct platform_driver bgpio_driver = {  	.driver = {  		.name = "basic-mmio-gpio", +		.of_match_table = of_match_ptr(bgpio_of_match),  	},  	.id_table = bgpio_id_table,  	.probe = bgpio_pdev_probe, diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index e248707ca39e..839474430229 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -208,7 +208,6 @@ static int palmas_gpio_probe(struct platform_device *pdev)  static struct platform_driver palmas_gpio_driver = {  	.driver.name	= "palmas-gpio", -	.driver.owner	= THIS_MODULE,  	.driver.of_match_table = of_palmas_gpio_match,  	.probe		= palmas_gpio_probe,  }; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5e3be32ebb8d..02f2a5621bb0 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -44,7 +44,7 @@  #define PCA_GPIO_MASK		0x00FF  #define PCA_INT			0x0100 -#define PCA_PCAL			0x0200 +#define PCA_PCAL		0x0200  #define PCA953X_TYPE		0x1000  #define PCA957X_TYPE		0x2000  #define PCA_TYPE_MASK		0xF000 @@ -67,6 +67,8 @@ static const struct i2c_device_id pca953x_id[] = {  	{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },  	{ "pca9698", 40 | PCA953X_TYPE, }, +	{ "pcal9555a", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, }, +  	{ "max7310", 8  | PCA953X_TYPE, },  	{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },  	{ "max7313", 16 | PCA953X_TYPE | PCA_INT, }, @@ -90,7 +92,7 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);  #define MAX_BANK 5  #define BANK_SZ 8 -#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ) +#define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)  struct pca953x_chip {  	unsigned gpio_start; @@ -135,7 +137,7 @@ static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,  static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,  				int off)  { -	int ret = 0; +	int ret;  	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);  	int offset = off / BANK_SZ; @@ -163,10 +165,13 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)  					NBANK(chip), val);  	} else {  		switch (chip->chip_type) { -		case PCA953X_TYPE: -			ret = i2c_smbus_write_word_data(chip->client, -			    reg << 1, cpu_to_le16(get_unaligned((u16 *)val))); +		case PCA953X_TYPE: { +			__le16 word = cpu_to_le16(get_unaligned((u16 *)val)); + +			ret = i2c_smbus_write_word_data(chip->client, reg << 1, +							(__force u16)word);  			break; +		}  		case PCA957X_TYPE:  			ret = i2c_smbus_write_byte_data(chip->client, reg << 1,  							val[0]); @@ -235,7 +240,6 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)  		goto exit;  	chip->reg_direction[off / BANK_SZ] = reg_val; -	ret = 0;  exit:  	mutex_unlock(&chip->i2c_lock);  	return ret; @@ -286,7 +290,6 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,  		goto exit;  	chip->reg_direction[off / BANK_SZ] = reg_val; -	ret = 0;  exit:  	mutex_unlock(&chip->i2c_lock);  	return ret; @@ -351,7 +354,6 @@ exit:  	mutex_unlock(&chip->i2c_lock);  } -  static void pca953x_gpio_set_multiple(struct gpio_chip *gc,  		unsigned long *mask, unsigned long *bits)  { @@ -820,7 +822,7 @@ static int pca953x_remove(struct i2c_client *client)  {  	struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev);  	struct pca953x_chip *chip = i2c_get_clientdata(client); -	int ret = 0; +	int ret;  	if (pdata && pdata->teardown) {  		ret = pdata->teardown(client, chip->gpio_chip.base, @@ -861,6 +863,7 @@ static const struct of_device_id pca953x_dt_ids[] = {  	{ .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), },  	{ .compatible = "ti,pca6107", .data = OF_953X( 8, PCA_INT), }, +	{ .compatible = "ti,pca9536", .data = OF_953X( 4, 0), },  	{ .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), },  	{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },  	{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), }, diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 169c09aa33c8..d168410e2338 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -440,6 +440,14 @@ static int pcf857x_remove(struct i2c_client *client)  	return status;  } +static void pcf857x_shutdown(struct i2c_client *client) +{ +	struct pcf857x *gpio = i2c_get_clientdata(client); + +	/* Drive all the I/O lines high */ +	gpio->write(gpio->client, BIT(gpio->chip.ngpio) - 1); +} +  static struct i2c_driver pcf857x_driver = {  	.driver = {  		.name	= "pcf857x", @@ -447,6 +455,7 @@ static struct i2c_driver pcf857x_driver = {  	},  	.probe	= pcf857x_probe,  	.remove	= pcf857x_remove, +	.shutdown = pcf857x_shutdown,  	.id_table = pcf857x_id,  }; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 681c93fb9e70..b96e0b466f74 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -335,6 +335,9 @@ static const struct of_device_id gpio_rcar_of_table[] = {  		.compatible = "renesas,gpio-r8a7791",  		.data = &gpio_rcar_info_gen2,  	}, { +		.compatible = "renesas,gpio-r8a7792", +		.data = &gpio_rcar_info_gen2, +	}, {  		.compatible = "renesas,gpio-r8a7793",  		.data = &gpio_rcar_info_gen2,  	}, { diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index ec945b90f54d..cbf0f9e6465b 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -200,7 +200,6 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)  static struct platform_driver rdc321x_gpio_driver = {  	.driver.name	= "rdc321x-gpio", -	.driver.owner	= THIS_MODULE,  	.probe		= rdc321x_gpio_probe,  }; diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index e85e7539cf5d..eb43ae4835c1 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -61,9 +61,8 @@ static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)  	return gpio % 8;  } -static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg) +static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned gpio, unsigned reg)  { -	struct sch_gpio *sch = gpiochip_get_data(gc);  	unsigned short offset, bit;  	u8 reg_val; @@ -75,10 +74,9 @@ static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg)  	return reg_val;  } -static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg, +static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned gpio, unsigned reg,  			     int val)  { -	struct sch_gpio *sch = gpiochip_get_data(gc);  	unsigned short offset, bit;  	u8 reg_val; @@ -98,14 +96,15 @@ static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)  	struct sch_gpio *sch = gpiochip_get_data(gc);  	spin_lock(&sch->lock); -	sch_gpio_reg_set(gc, gpio_num, GIO, 1); +	sch_gpio_reg_set(sch, gpio_num, GIO, 1);  	spin_unlock(&sch->lock);  	return 0;  }  static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)  { -	return sch_gpio_reg_get(gc, gpio_num, GLV); +	struct sch_gpio *sch = gpiochip_get_data(gc); +	return sch_gpio_reg_get(sch, gpio_num, GLV);  }  static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val) @@ -113,7 +112,7 @@ static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)  	struct sch_gpio *sch = gpiochip_get_data(gc);  	spin_lock(&sch->lock); -	sch_gpio_reg_set(gc, gpio_num, GLV, val); +	sch_gpio_reg_set(sch, gpio_num, GLV, val);  	spin_unlock(&sch->lock);  } @@ -123,7 +122,7 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,  	struct sch_gpio *sch = gpiochip_get_data(gc);  	spin_lock(&sch->lock); -	sch_gpio_reg_set(gc, gpio_num, GIO, 0); +	sch_gpio_reg_set(sch, gpio_num, GIO, 0);  	spin_unlock(&sch->lock);  	/* @@ -182,13 +181,13 @@ static int sch_gpio_probe(struct platform_device *pdev)  		 * GPIO7 is configured by the CMC as SLPIOVR  		 * Enable GPIO[9:8] core powered gpios explicitly  		 */ -		sch_gpio_reg_set(&sch->chip, 8, GEN, 1); -		sch_gpio_reg_set(&sch->chip, 9, GEN, 1); +		sch_gpio_reg_set(sch, 8, GEN, 1); +		sch_gpio_reg_set(sch, 9, GEN, 1);  		/*  		 * SUS_GPIO[2:0] enabled by default  		 * Enable SUS_GPIO3 resume powered gpio explicitly  		 */ -		sch_gpio_reg_set(&sch->chip, 13, GEN, 1); +		sch_gpio_reg_set(sch, 13, GEN, 1);  		break;  	case PCI_DEVICE_ID_INTEL_ITC_LPC: diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index a03b38ee2e02..b96990c262a1 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -296,7 +296,6 @@ static int sch311x_gpio_remove(struct platform_device *pdev)  static struct platform_driver sch311x_gpio_driver = {  	.driver.name	= DRV_NAME, -	.driver.owner	= THIS_MODULE,  	.probe		= sch311x_gpio_probe,  	.remove		= sch311x_gpio_remove,  }; diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 6f7af28b8966..f675132de10e 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -68,6 +68,22 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)  		stmpe_reg_write(stmpe, reg, mask);  } +static int stmpe_gpio_get_direction(struct gpio_chip *chip, +				    unsigned offset) +{ +	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip); +	struct stmpe *stmpe = stmpe_gpio->stmpe; +	u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8); +	u8 mask = 1 << (offset % 8); +	int ret; + +	ret = stmpe_reg_read(stmpe, reg); +	if (ret < 0) +		return ret; + +	return !(ret & mask); +} +  static int stmpe_gpio_direction_output(struct gpio_chip *chip,  					 unsigned offset, int val)  { @@ -106,6 +122,7 @@ static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)  static struct gpio_chip template_chip = {  	.label			= "stmpe",  	.owner			= THIS_MODULE, +	.get_direction		= stmpe_gpio_get_direction,  	.direction_input	= stmpe_gpio_direction_input,  	.get			= stmpe_gpio_get,  	.direction_output	= stmpe_gpio_direction_output, @@ -416,7 +433,6 @@ static struct platform_driver stmpe_gpio_driver = {  	.driver = {  		.suppress_bind_attrs	= true,  		.name			= "stmpe-gpio", -		.owner			= THIS_MODULE,  	},  	.probe		= stmpe_gpio_probe,  }; diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index 24b6d643ecdb..537cec7583fc 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -129,7 +129,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)  static const struct syscon_gpio_data clps711x_mctrl_gpio = {  	/* ARM CLPS711X SYSFLG1 Bits 8-10 */ -	.compatible	= "cirrus,clps711x-syscon1", +	.compatible	= "cirrus,ep7209-syscon1",  	.flags		= GPIO_SYSCON_FEAT_IN,  	.bit_count	= 3,  	.dat_bit_offset	= 0x40 * 8 + 8, @@ -168,7 +168,7 @@ static const struct syscon_gpio_data keystone_dsp_gpio = {  static const struct of_device_id syscon_gpio_ids[] = {  	{ -		.compatible	= "cirrus,clps711x-mctrl-gpio", +		.compatible	= "cirrus,ep7209-mctrl-gpio",  		.data		= &clps711x_mctrl_gpio,  	},  	{ diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 2e35ed3abbcf..8b3659352e49 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -343,7 +343,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)  static struct platform_driver tc3589x_gpio_driver = {  	.driver.name	= "tc3589x-gpio", -	.driver.owner	= THIS_MODULE,  	.probe		= tc3589x_gpio_probe,  }; diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index ec891a27952f..661b0e34e067 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -98,7 +98,6 @@ struct tegra_gpio_info {  	const struct tegra_gpio_soc_config	*soc;  	struct gpio_chip			gc;  	struct irq_chip				ic; -	struct lock_class_key			lock_class;  	u32					bank_count;  }; @@ -547,6 +546,12 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {  	SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)  }; +/* + * This lock class tells lockdep that GPIO irqs are in a different category + * than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; +  static int tegra_gpio_probe(struct platform_device *pdev)  {  	const struct tegra_gpio_soc_config *config; @@ -660,7 +665,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)  		bank = &tgi->bank_info[GPIO_BANK(gpio)]; -		irq_set_lockdep_class(irq, &tgi->lock_class); +		irq_set_lockdep_class(irq, &gpio_lock_class);  		irq_set_chip_data(irq, bank);  		irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);  	} diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c index 0eaeac8de9de..1c09a19ae10c 100644 --- a/drivers/gpio/gpio-tps65218.c +++ b/drivers/gpio/gpio-tps65218.c @@ -230,6 +230,12 @@ static const struct of_device_id tps65218_dt_match[] = {  };  MODULE_DEVICE_TABLE(of, tps65218_dt_match); +static const struct platform_device_id tps65218_gpio_id_table[] = { +	{ "tps65218-gpio", }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, tps65218_gpio_id_table); +  static struct platform_driver tps65218_gpio_driver = {  	.driver = {  		.name = "tps65218-gpio", @@ -237,6 +243,7 @@ static struct platform_driver tps65218_gpio_driver = {  	},  	.probe = tps65218_gpio_probe,  	.remove = tps65218_gpio_remove, +	.id_table = tps65218_gpio_id_table,  };  module_platform_driver(tps65218_gpio_driver); diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index 6b15e68a314f..042b9a20781a 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -131,7 +131,6 @@ static int tps6586x_gpio_probe(struct platform_device *pdev)  static struct platform_driver tps6586x_gpio_driver = {  	.driver.name	= "tps6586x-gpio", -	.driver.owner	= THIS_MODULE,  	.probe		= tps6586x_gpio_probe,  }; diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 0ae6a5a54ea8..e63d7dabf78b 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -184,7 +184,6 @@ skip_init:  static struct platform_driver tps65910_gpio_driver = {  	.driver.name    = "tps65910-gpio", -	.driver.owner   = THIS_MODULE,  	.probe		= tps65910_gpio_probe,  }; diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index dec47aafd5cd..e6d1328dddfa 100644 --- a/drivers/gpio/gpio-viperboard.c +++ b/drivers/gpio/gpio-viperboard.c @@ -440,7 +440,6 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)  static struct platform_driver vprbrd_gpio_driver = {  	.driver.name	= "viperboard-gpio", -	.driver.owner	= THIS_MODULE,  	.probe		= vprbrd_gpio_probe,  }; diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 41ec7834059a..21f97bcd0062 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -296,7 +296,6 @@ static int wm831x_gpio_probe(struct platform_device *pdev)  static struct platform_driver wm831x_gpio_driver = {  	.driver.name	= "wm831x-gpio", -	.driver.owner	= THIS_MODULE,  	.probe		= wm831x_gpio_probe,  }; diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index 07d45a3b205a..e9765707d5c1 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -139,7 +139,6 @@ static int wm8350_gpio_probe(struct platform_device *pdev)  static struct platform_driver wm8350_gpio_driver = {  	.driver.name	= "wm8350-gpio", -	.driver.owner	= THIS_MODULE,  	.probe		= wm8350_gpio_probe,  }; diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index 744af388c949..2457aac8592e 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -299,7 +299,6 @@ static int wm8994_gpio_probe(struct platform_device *pdev)  static struct platform_driver wm8994_gpio_driver = {  	.driver.name	= "wm8994-gpio", -	.driver.owner	= THIS_MODULE,  	.probe		= wm8994_gpio_probe,  }; diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index d0fbb7f99523..14b2a62338ea 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -133,6 +133,53 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)  }  /** + * xgpio_set_multiple - Write the specified signals of the GPIO device. + * @gc:     Pointer to gpio_chip device structure. + * @mask:   Mask of the GPIOS to modify. + * @bits:   Value to be wrote on each GPIO + * + * This function writes the specified values into the specified signals of the + * GPIO devices. + */ +static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, +			       unsigned long *bits) +{ +	unsigned long flags; +	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); +	struct xgpio_instance *chip = gpiochip_get_data(gc); +	int index = xgpio_index(chip, 0); +	int offset, i; + +	spin_lock_irqsave(&chip->gpio_lock[index], flags); + +	/* Write to GPIO signals */ +	for (i = 0; i < gc->ngpio; i++) { +		if (*mask == 0) +			break; +		if (index !=  xgpio_index(chip, i)) { +			xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + +				       xgpio_regoffset(chip, i), +				       chip->gpio_state[index]); +			spin_unlock_irqrestore(&chip->gpio_lock[index], flags); +			index =  xgpio_index(chip, i); +			spin_lock_irqsave(&chip->gpio_lock[index], flags); +		} +		if (__test_and_clear_bit(i, mask)) { +			offset =  xgpio_offset(chip, i); +			if (test_bit(i, bits)) +				chip->gpio_state[index] |= BIT(offset); +			else +				chip->gpio_state[index] &= ~BIT(offset); +		} +	} + +	xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + +		       xgpio_regoffset(chip, i), chip->gpio_state[index]); + +	spin_unlock_irqrestore(&chip->gpio_lock[index], flags); +} + +/**   * xgpio_dir_in - Set the direction of the specified GPIO signal as input.   * @gc:     Pointer to gpio_chip device structure.   * @gpio:   GPIO signal number. @@ -306,6 +353,7 @@ static int xgpio_probe(struct platform_device *pdev)  	chip->mmchip.gc.direction_output = xgpio_dir_out;  	chip->mmchip.gc.get = xgpio_get;  	chip->mmchip.gc.set = xgpio_set; +	chip->mmchip.gc.set_multiple = xgpio_set_multiple;  	chip->mmchip.save_regs = xgpio_save_regs; diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 1a33a19d95b9..4620d050e5a8 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -19,6 +19,7 @@  #include <linux/irq.h>  #include <linux/interrupt.h>  #include <linux/irqchip/chained_irq.h> +#include <linux/acpi.h>  /*   * XLP GPIO has multiple 32 bit registers for each feature where each register @@ -299,7 +300,6 @@ static int xlp_gpio_probe(struct platform_device *pdev)  	struct gpio_chip *gc;  	struct resource *iores;  	struct xlp_gpio_priv *priv; -	const struct of_device_id *of_id;  	void __iomem *gpio_base;  	int irq_base, irq, err;  	int ngpio; @@ -321,13 +321,26 @@ static int xlp_gpio_probe(struct platform_device *pdev)  	if (irq < 0)  		return irq; -	of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev); -	if (!of_id) { -		dev_err(&pdev->dev, "Failed to get soc type!\n"); -		return -ENODEV; -	} +	if (pdev->dev.of_node) { +		const struct of_device_id *of_id; -	soc_type = (uintptr_t) of_id->data; +		of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev); +		if (!of_id) { +			dev_err(&pdev->dev, "Unable to match OF ID\n"); +			return -ENODEV; +		} +		soc_type = (uintptr_t) of_id->data; +	} else { +		const struct acpi_device_id *acpi_id; + +		acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table, +						&pdev->dev); +		if (!acpi_id || !acpi_id->driver_data) { +			dev_err(&pdev->dev, "Unable to match ACPI ID\n"); +			return -ENODEV; +		} +		soc_type = (uintptr_t) acpi_id->driver_data; +	}  	switch (soc_type) {  	case XLP_GPIO_VARIANT_XLP832: @@ -388,14 +401,16 @@ static int xlp_gpio_probe(struct platform_device *pdev)  	gc->get = xlp_gpio_get;  	spin_lock_init(&priv->lock); -	/* XLP has fixed IRQ range for GPIO interrupts */ -	if (soc_type == GPIO_VARIANT_VULCAN) -		irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0); -	else + +	/* XLP(MIPS) has fixed range for GPIO IRQs, Vulcan(ARM64) does not */ +	if (soc_type != GPIO_VARIANT_VULCAN) {  		irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0); -	if (irq_base < 0) { -		dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); -		return irq_base; +		if (irq_base < 0) { +			dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); +			return irq_base; +		} +	} else { +		irq_base = 0;  	}  	err = gpiochip_add_data(gc, priv); @@ -423,10 +438,19 @@ out_free_desc:  	return err;  } +#ifdef CONFIG_ACPI +static const struct acpi_device_id xlp_gpio_acpi_match[] = { +	{ "BRCM9006", GPIO_VARIANT_VULCAN }, +	{}, +}; +MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match); +#endif +  static struct platform_driver xlp_gpio_driver = {  	.driver		= {  		.name	= "xlp-gpio",  		.of_match_table = xlp_gpio_of_ids, +		.acpi_match_table = ACPI_PTR(xlp_gpio_acpi_match),  	},  	.probe		= xlp_gpio_probe,  }; diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 2dc52585e3f2..af514618d7fb 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -836,6 +836,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip)  	}  	acpi_gpiochip_request_regions(acpi_gpio); +	acpi_walk_dep_device_list(handle);  }  void acpi_gpiochip_remove(struct gpio_chip *chip) diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c index 3a5c7011ad3b..8b830996fe02 100644 --- a/drivers/gpio/gpiolib-legacy.c +++ b/drivers/gpio/gpiolib-legacy.c @@ -28,6 +28,10 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)  	if (!desc && gpio_is_valid(gpio))  		return -EPROBE_DEFER; +	err = gpiod_request(desc, label); +	if (err) +		return err; +  	if (flags & GPIOF_OPEN_DRAIN)  		set_bit(FLAG_OPEN_DRAIN, &desc->flags); @@ -37,10 +41,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)  	if (flags & GPIOF_ACTIVE_LOW)  		set_bit(FLAG_ACTIVE_LOW, &desc->flags); -	err = gpiod_request(desc, label); -	if (err) -		return err; -  	if (flags & GPIOF_DIR_IN)  		err = gpiod_direction_input(desc);  	else diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 4aabddb38b59..75e7b3919ea7 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -27,38 +27,30 @@  #include "gpiolib.h" -/* Private data structure for of_gpiochip_find_and_xlate */ -struct gg_data { -	enum of_gpio_flags *flags; -	struct of_phandle_args gpiospec; +static int of_gpiochip_match_node(struct gpio_chip *chip, void *data) +{ +	return chip->gpiodev->dev.of_node == data; +} -	struct gpio_desc *out_gpio; -}; +static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np) +{ +	return gpiochip_find(np, of_gpiochip_match_node); +} -/* Private function for resolving node pointer to gpio_chip */ -static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) +static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip, +					struct of_phandle_args *gpiospec, +					enum of_gpio_flags *flags)  { -	struct gg_data *gg_data = data;  	int ret; -	if ((gc->of_node != gg_data->gpiospec.np) || -	    (gc->of_gpio_n_cells != gg_data->gpiospec.args_count) || -	    (!gc->of_xlate)) -		return false; - -	ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags); -	if (ret < 0) { -		/* We've found a gpio chip, but the translation failed. -		 * Store translation error in out_gpio. -		 * Return false to keep looking, as more than one gpio chip -		 * could be registered per of-node. -		 */ -		gg_data->out_gpio = ERR_PTR(ret); -		return false; -	 } - -	gg_data->out_gpio = gpiochip_get_desc(gc, ret); -	return true; +	if (chip->of_gpio_n_cells != gpiospec->args_count) +		return ERR_PTR(-EINVAL); + +	ret = chip->of_xlate(chip, gpiospec, flags); +	if (ret < 0) +		return ERR_PTR(ret); + +	return gpiochip_get_desc(chip, ret);  }  /** @@ -75,34 +67,37 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)  struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,  		     const char *propname, int index, enum of_gpio_flags *flags)  { -	/* Return -EPROBE_DEFER to support probe() functions to be called -	 * later when the GPIO actually becomes available -	 */ -	struct gg_data gg_data = { -		.flags = flags, -		.out_gpio = ERR_PTR(-EPROBE_DEFER) -	}; +	struct of_phandle_args gpiospec; +	struct gpio_chip *chip; +	struct gpio_desc *desc;  	int ret; -	/* .of_xlate might decide to not fill in the flags, so clear it. */ -	if (flags) -		*flags = 0; -  	ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, -					 &gg_data.gpiospec); +					 &gpiospec);  	if (ret) {  		pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n",  			__func__, propname, np->full_name, index);  		return ERR_PTR(ret);  	} -	gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); +	chip = of_find_gpiochip_by_node(gpiospec.np); +	if (!chip) { +		desc = ERR_PTR(-EPROBE_DEFER); +		goto out; +	} + +	desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags); +	if (IS_ERR(desc)) +		goto out; -	of_node_put(gg_data.gpiospec.np);  	pr_debug("%s: parsed '%s' property of node '%s[%d]' - status (%d)\n",  		 __func__, propname, np->full_name, index, -		 PTR_ERR_OR_ZERO(gg_data.out_gpio)); -	return gg_data.out_gpio; +		 PTR_ERR_OR_ZERO(desc)); + +out: +	of_node_put(gpiospec.np); + +	return desc;  }  int of_get_named_gpio_flags(struct device_node *np, const char *list_name, @@ -122,6 +117,7 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);  /**   * of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API   * @np:		device node to get GPIO from + * @chip:	GPIO chip whose hog is parsed   * @name:	GPIO line name   * @lflags:	gpio_lookup_flags - returned from of_find_gpio() or   *		of_parse_own_gpio() @@ -131,19 +127,19 @@ EXPORT_SYMBOL(of_get_named_gpio_flags);   * value on the error condition.   */  static struct gpio_desc *of_parse_own_gpio(struct device_node *np, +					   struct gpio_chip *chip,  					   const char **name,  					   enum gpio_lookup_flags *lflags,  					   enum gpiod_flags *dflags)  {  	struct device_node *chip_np;  	enum of_gpio_flags xlate_flags; -	struct gg_data gg_data = { -		.flags = &xlate_flags, -	}; +	struct of_phandle_args gpiospec; +	struct gpio_desc *desc;  	u32 tmp; -	int i, ret; +	int ret; -	chip_np = np->parent; +	chip_np = chip->of_node;  	if (!chip_np)  		return ERR_PTR(-EINVAL); @@ -155,25 +151,16 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,  	if (ret)  		return ERR_PTR(ret); -	if (tmp > MAX_PHANDLE_ARGS) -		return ERR_PTR(-EINVAL); +	gpiospec.np = chip_np; +	gpiospec.args_count = tmp; -	gg_data.gpiospec.args_count = tmp; -	gg_data.gpiospec.np = chip_np; -	for (i = 0; i < tmp; i++) { -		ret = of_property_read_u32_index(np, "gpios", i, -					   &gg_data.gpiospec.args[i]); -		if (ret) -			return ERR_PTR(ret); -	} +	ret = of_property_read_u32_array(np, "gpios", gpiospec.args, tmp); +	if (ret) +		return ERR_PTR(ret); -	gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); -	if (!gg_data.out_gpio) { -		if (np->parent == np) -			return ERR_PTR(-ENXIO); -		else -			return ERR_PTR(-EINVAL); -	} +	desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, &xlate_flags); +	if (IS_ERR(desc)) +		return desc;  	if (xlate_flags & OF_GPIO_ACTIVE_LOW)  		*lflags |= GPIO_ACTIVE_LOW; @@ -186,14 +173,14 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,  		*dflags |= GPIOD_OUT_HIGH;  	else {  		pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n", -			desc_to_gpio(gg_data.out_gpio), np->name); +			desc_to_gpio(desc), np->name);  		return ERR_PTR(-EINVAL);  	}  	if (name && of_property_read_string(np, "line-name", name))  		*name = np->name; -	return gg_data.out_gpio; +	return desc;  }  /** @@ -262,7 +249,7 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)  		if (!of_property_read_bool(np, "gpio-hog"))  			continue; -		desc = of_parse_own_gpio(np, &name, &lflags, &dflags); +		desc = of_parse_own_gpio(np, chip, &name, &lflags, &dflags);  		if (IS_ERR(desc))  			continue; @@ -410,6 +397,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)  			break;  		pctldev = of_pinctrl_get(pinspec.np); +		of_node_put(pinspec.np);  		if (!pctldev)  			return -EPROBE_DEFER; @@ -487,6 +475,9 @@ int of_gpiochip_add(struct gpio_chip *chip)  		chip->of_xlate = of_gpio_simple_xlate;  	} +	if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS) +		return -EINVAL; +  	status = of_gpiochip_add_pin_range(chip);  	if (status)  		return status; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 58d822d7e8da..53ff25ac66d8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -16,11 +16,14 @@  #include <linux/gpio/driver.h>  #include <linux/gpio/machine.h>  #include <linux/pinctrl/consumer.h> -#include <linux/idr.h>  #include <linux/cdev.h>  #include <linux/fs.h>  #include <linux/uaccess.h>  #include <linux/compat.h> +#include <linux/anon_inodes.h> +#include <linux/kfifo.h> +#include <linux/poll.h> +#include <linux/timekeeping.h>  #include <uapi/linux/gpio.h>  #include "gpiolib.h" @@ -310,6 +313,497 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)  	return 0;  } +/* + * GPIO line handle management + */ + +/** + * struct linehandle_state - contains the state of a userspace handle + * @gdev: the GPIO device the handle pertains to + * @label: consumer label used to tag descriptors + * @descs: the GPIO descriptors held by this handle + * @numdescs: the number of descriptors held in the descs array + */ +struct linehandle_state { +	struct gpio_device *gdev; +	const char *label; +	struct gpio_desc *descs[GPIOHANDLES_MAX]; +	u32 numdescs; +}; + +static long linehandle_ioctl(struct file *filep, unsigned int cmd, +			     unsigned long arg) +{ +	struct linehandle_state *lh = filep->private_data; +	void __user *ip = (void __user *)arg; +	struct gpiohandle_data ghd; +	int i; + +	if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { +		int val; + +		/* TODO: check if descriptors are really input */ +		for (i = 0; i < lh->numdescs; i++) { +			val = gpiod_get_value_cansleep(lh->descs[i]); +			if (val < 0) +				return val; +			ghd.values[i] = val; +		} + +		if (copy_to_user(ip, &ghd, sizeof(ghd))) +			return -EFAULT; + +		return 0; +	} else if (cmd == GPIOHANDLE_SET_LINE_VALUES_IOCTL) { +		int vals[GPIOHANDLES_MAX]; + +		/* TODO: check if descriptors are really output */ +		if (copy_from_user(&ghd, ip, sizeof(ghd))) +			return -EFAULT; + +		/* Clamp all values to [0,1] */ +		for (i = 0; i < lh->numdescs; i++) +			vals[i] = !!ghd.values[i]; + +		/* Reuse the array setting function */ +		gpiod_set_array_value_complex(false, +					      true, +					      lh->numdescs, +					      lh->descs, +					      vals); +		return 0; +	} +	return -EINVAL; +} + +#ifdef CONFIG_COMPAT +static long linehandle_ioctl_compat(struct file *filep, unsigned int cmd, +			     unsigned long arg) +{ +	return linehandle_ioctl(filep, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static int linehandle_release(struct inode *inode, struct file *filep) +{ +	struct linehandle_state *lh = filep->private_data; +	struct gpio_device *gdev = lh->gdev; +	int i; + +	for (i = 0; i < lh->numdescs; i++) +		gpiod_free(lh->descs[i]); +	kfree(lh->label); +	kfree(lh); +	put_device(&gdev->dev); +	return 0; +} + +static const struct file_operations linehandle_fileops = { +	.release = linehandle_release, +	.owner = THIS_MODULE, +	.llseek = noop_llseek, +	.unlocked_ioctl = linehandle_ioctl, +#ifdef CONFIG_COMPAT +	.compat_ioctl = linehandle_ioctl_compat, +#endif +}; + +static int linehandle_create(struct gpio_device *gdev, void __user *ip) +{ +	struct gpiohandle_request handlereq; +	struct linehandle_state *lh; +	int fd, i, ret; + +	if (copy_from_user(&handlereq, ip, sizeof(handlereq))) +		return -EFAULT; +	if ((handlereq.lines == 0) || (handlereq.lines > GPIOHANDLES_MAX)) +		return -EINVAL; + +	lh = kzalloc(sizeof(*lh), GFP_KERNEL); +	if (!lh) +		return -ENOMEM; +	lh->gdev = gdev; +	get_device(&gdev->dev); + +	/* Make sure this is terminated */ +	handlereq.consumer_label[sizeof(handlereq.consumer_label)-1] = '\0'; +	if (strlen(handlereq.consumer_label)) { +		lh->label = kstrdup(handlereq.consumer_label, +				    GFP_KERNEL); +		if (!lh->label) { +			ret = -ENOMEM; +			goto out_free_lh; +		} +	} + +	/* Request each GPIO */ +	for (i = 0; i < handlereq.lines; i++) { +		u32 offset = handlereq.lineoffsets[i]; +		u32 lflags = handlereq.flags; +		struct gpio_desc *desc; + +		desc = &gdev->descs[offset]; +		ret = gpiod_request(desc, lh->label); +		if (ret) +			goto out_free_descs; +		lh->descs[i] = desc; + +		if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW) +			set_bit(FLAG_ACTIVE_LOW, &desc->flags); +		if (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) +			set_bit(FLAG_OPEN_DRAIN, &desc->flags); +		if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) +			set_bit(FLAG_OPEN_SOURCE, &desc->flags); + +		/* +		 * Lines have to be requested explicitly for input +		 * or output, else the line will be treated "as is". +		 */ +		if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { +			int val = !!handlereq.default_values[i]; + +			ret = gpiod_direction_output(desc, val); +			if (ret) +				goto out_free_descs; +		} else if (lflags & GPIOHANDLE_REQUEST_INPUT) { +			ret = gpiod_direction_input(desc); +			if (ret) +				goto out_free_descs; +		} +		dev_dbg(&gdev->dev, "registered chardev handle for line %d\n", +			offset); +	} +	/* Let i point at the last handle */ +	i--; +	lh->numdescs = handlereq.lines; + +	fd = anon_inode_getfd("gpio-linehandle", +			      &linehandle_fileops, +			      lh, +			      O_RDONLY | O_CLOEXEC); +	if (fd < 0) { +		ret = fd; +		goto out_free_descs; +	} + +	handlereq.fd = fd; +	if (copy_to_user(ip, &handlereq, sizeof(handlereq))) { +		ret = -EFAULT; +		goto out_free_descs; +	} + +	dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n", +		lh->numdescs); + +	return 0; + +out_free_descs: +	for (; i >= 0; i--) +		gpiod_free(lh->descs[i]); +	kfree(lh->label); +out_free_lh: +	kfree(lh); +	put_device(&gdev->dev); +	return ret; +} + +/* + * GPIO line event management + */ + +/** + * struct lineevent_state - contains the state of a userspace event + * @gdev: the GPIO device the event pertains to + * @label: consumer label used to tag descriptors + * @desc: the GPIO descriptor held by this event + * @eflags: the event flags this line was requested with + * @irq: the interrupt that trigger in response to events on this GPIO + * @wait: wait queue that handles blocking reads of events + * @events: KFIFO for the GPIO events + * @read_lock: mutex lock to protect reads from colliding with adding + * new events to the FIFO + */ +struct lineevent_state { +	struct gpio_device *gdev; +	const char *label; +	struct gpio_desc *desc; +	u32 eflags; +	int irq; +	wait_queue_head_t wait; +	DECLARE_KFIFO(events, struct gpioevent_data, 16); +	struct mutex read_lock; +}; + +static unsigned int lineevent_poll(struct file *filep, +				   struct poll_table_struct *wait) +{ +	struct lineevent_state *le = filep->private_data; +	unsigned int events = 0; + +	poll_wait(filep, &le->wait, wait); + +	if (!kfifo_is_empty(&le->events)) +		events = POLLIN | POLLRDNORM; + +	return events; +} + + +static ssize_t lineevent_read(struct file *filep, +			      char __user *buf, +			      size_t count, +			      loff_t *f_ps) +{ +	struct lineevent_state *le = filep->private_data; +	unsigned int copied; +	int ret; + +	if (count < sizeof(struct gpioevent_data)) +		return -EINVAL; + +	do { +		if (kfifo_is_empty(&le->events)) { +			if (filep->f_flags & O_NONBLOCK) +				return -EAGAIN; + +			ret = wait_event_interruptible(le->wait, +					!kfifo_is_empty(&le->events)); +			if (ret) +				return ret; +		} + +		if (mutex_lock_interruptible(&le->read_lock)) +			return -ERESTARTSYS; +		ret = kfifo_to_user(&le->events, buf, count, &copied); +		mutex_unlock(&le->read_lock); + +		if (ret) +			return ret; + +		/* +		 * If we couldn't read anything from the fifo (a different +		 * thread might have been faster) we either return -EAGAIN if +		 * the file descriptor is non-blocking, otherwise we go back to +		 * sleep and wait for more data to arrive. +		 */ +		if (copied == 0 && (filep->f_flags & O_NONBLOCK)) +			return -EAGAIN; + +	} while (copied == 0); + +	return copied; +} + +static int lineevent_release(struct inode *inode, struct file *filep) +{ +	struct lineevent_state *le = filep->private_data; +	struct gpio_device *gdev = le->gdev; + +	free_irq(le->irq, le); +	gpiod_free(le->desc); +	kfree(le->label); +	kfree(le); +	put_device(&gdev->dev); +	return 0; +} + +static long lineevent_ioctl(struct file *filep, unsigned int cmd, +			    unsigned long arg) +{ +	struct lineevent_state *le = filep->private_data; +	void __user *ip = (void __user *)arg; +	struct gpiohandle_data ghd; + +	/* +	 * We can get the value for an event line but not set it, +	 * because it is input by definition. +	 */ +	if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { +		int val; + +		val = gpiod_get_value_cansleep(le->desc); +		if (val < 0) +			return val; +		ghd.values[0] = val; + +		if (copy_to_user(ip, &ghd, sizeof(ghd))) +			return -EFAULT; + +		return 0; +	} +	return -EINVAL; +} + +#ifdef CONFIG_COMPAT +static long lineevent_ioctl_compat(struct file *filep, unsigned int cmd, +				   unsigned long arg) +{ +	return lineevent_ioctl(filep, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static const struct file_operations lineevent_fileops = { +	.release = lineevent_release, +	.read = lineevent_read, +	.poll = lineevent_poll, +	.owner = THIS_MODULE, +	.llseek = noop_llseek, +	.unlocked_ioctl = lineevent_ioctl, +#ifdef CONFIG_COMPAT +	.compat_ioctl = lineevent_ioctl_compat, +#endif +}; + +static irqreturn_t lineevent_irq_thread(int irq, void *p) +{ +	struct lineevent_state *le = p; +	struct gpioevent_data ge; +	int ret; + +	ge.timestamp = ktime_get_real_ns(); + +	if (le->eflags & GPIOEVENT_REQUEST_BOTH_EDGES) { +		int level = gpiod_get_value_cansleep(le->desc); + +		if (level) +			/* Emit low-to-high event */ +			ge.id = GPIOEVENT_EVENT_RISING_EDGE; +		else +			/* Emit high-to-low event */ +			ge.id = GPIOEVENT_EVENT_FALLING_EDGE; +	} else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) { +		/* Emit low-to-high event */ +		ge.id = GPIOEVENT_EVENT_RISING_EDGE; +	} else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) { +		/* Emit high-to-low event */ +		ge.id = GPIOEVENT_EVENT_FALLING_EDGE; +	} else { +		return IRQ_NONE; +	} + +	ret = kfifo_put(&le->events, ge); +	if (ret != 0) +		wake_up_poll(&le->wait, POLLIN); + +	return IRQ_HANDLED; +} + +static int lineevent_create(struct gpio_device *gdev, void __user *ip) +{ +	struct gpioevent_request eventreq; +	struct lineevent_state *le; +	struct gpio_desc *desc; +	u32 offset; +	u32 lflags; +	u32 eflags; +	int fd; +	int ret; +	int irqflags = 0; + +	if (copy_from_user(&eventreq, ip, sizeof(eventreq))) +		return -EFAULT; + +	le = kzalloc(sizeof(*le), GFP_KERNEL); +	if (!le) +		return -ENOMEM; +	le->gdev = gdev; +	get_device(&gdev->dev); + +	/* Make sure this is terminated */ +	eventreq.consumer_label[sizeof(eventreq.consumer_label)-1] = '\0'; +	if (strlen(eventreq.consumer_label)) { +		le->label = kstrdup(eventreq.consumer_label, +				    GFP_KERNEL); +		if (!le->label) { +			ret = -ENOMEM; +			goto out_free_le; +		} +	} + +	offset = eventreq.lineoffset; +	lflags = eventreq.handleflags; +	eflags = eventreq.eventflags; + +	/* This is just wrong: we don't look for events on output lines */ +	if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { +		ret = -EINVAL; +		goto out_free_label; +	} + +	desc = &gdev->descs[offset]; +	ret = gpiod_request(desc, le->label); +	if (ret) +		goto out_free_desc; +	le->desc = desc; +	le->eflags = eflags; + +	if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW) +		set_bit(FLAG_ACTIVE_LOW, &desc->flags); +	if (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) +		set_bit(FLAG_OPEN_DRAIN, &desc->flags); +	if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) +		set_bit(FLAG_OPEN_SOURCE, &desc->flags); + +	ret = gpiod_direction_input(desc); +	if (ret) +		goto out_free_desc; + +	le->irq = gpiod_to_irq(desc); +	if (le->irq <= 0) { +		ret = -ENODEV; +		goto out_free_desc; +	} + +	if (eflags & GPIOEVENT_REQUEST_RISING_EDGE) +		irqflags |= IRQF_TRIGGER_RISING; +	if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE) +		irqflags |= IRQF_TRIGGER_FALLING; +	irqflags |= IRQF_ONESHOT; +	irqflags |= IRQF_SHARED; + +	INIT_KFIFO(le->events); +	init_waitqueue_head(&le->wait); +	mutex_init(&le->read_lock); + +	/* Request a thread to read the events */ +	ret = request_threaded_irq(le->irq, +			NULL, +			lineevent_irq_thread, +			irqflags, +			le->label, +			le); +	if (ret) +		goto out_free_desc; + +	fd = anon_inode_getfd("gpio-event", +			      &lineevent_fileops, +			      le, +			      O_RDONLY | O_CLOEXEC); +	if (fd < 0) { +		ret = fd; +		goto out_free_irq; +	} + +	eventreq.fd = fd; +	if (copy_to_user(ip, &eventreq, sizeof(eventreq))) { +		ret = -EFAULT; +		goto out_free_irq; +	} + +	return 0; + +out_free_irq: +	free_irq(le->irq, le); +out_free_desc: +	gpiod_free(le->desc); +out_free_label: +	kfree(le->label); +out_free_le: +	kfree(le); +	put_device(&gdev->dev); +	return ret; +} +  /**   * gpio_ioctl() - ioctl handler for the GPIO chardev   */ @@ -385,6 +879,10 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  		if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))  			return -EFAULT;  		return 0; +	} else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { +		return linehandle_create(gdev, ip); +	} else if (cmd == GPIO_GET_LINEEVENT_IOCTL) { +		return lineevent_create(gdev, ip);  	}  	return -EINVAL;  } @@ -548,13 +1046,14 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)  	if (chip->parent) {  		gdev->dev.parent = chip->parent;  		gdev->dev.of_node = chip->parent->of_node; -	} else { +	} +  #ifdef CONFIG_OF_GPIO  	/* If the gpiochip has an assigned OF node this takes precedence */ -		if (chip->of_node) -			gdev->dev.of_node = chip->of_node; +	if (chip->of_node) +		gdev->dev.of_node = chip->of_node;  #endif -	} +  	gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL);  	if (gdev->id < 0) {  		status = gdev->id; @@ -1352,14 +1851,6 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label)  		spin_lock_irqsave(&gpio_lock, flags);  	}  done: -	if (status < 0) { -		/* Clear flags that might have been set by the caller before -		 * requesting the GPIO. -		 */ -		clear_bit(FLAG_ACTIVE_LOW, &desc->flags); -		clear_bit(FLAG_OPEN_DRAIN, &desc->flags); -		clear_bit(FLAG_OPEN_SOURCE, &desc->flags); -	}  	spin_unlock_irqrestore(&gpio_lock, flags);  	return status;  } @@ -1373,8 +1864,12 @@ done:  #define VALIDATE_DESC(desc) do { \  	if (!desc) \  		return 0; \ +	if (IS_ERR(desc)) {						\ +		pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \ +		return PTR_ERR(desc); \ +	} \  	if (!desc->gdev) { \ -		pr_warn("%s: invalid GPIO\n", __func__); \ +		pr_warn("%s: invalid GPIO (no device)\n", __func__); \  		return -EINVAL; \  	} \  	if ( !desc->gdev->chip ) { \ @@ -1386,8 +1881,12 @@ done:  #define VALIDATE_DESC_VOID(desc) do { \  	if (!desc) \  		return; \ +	if (IS_ERR(desc)) {						\ +		pr_warn("%s: invalid GPIO (errorpointer)\n", __func__); \ +		return; \ +	} \  	if (!desc->gdev) { \ -		pr_warn("%s: invalid GPIO\n", __func__); \ +		pr_warn("%s: invalid GPIO (no device)\n", __func__); \  		return; \  	} \  	if (!desc->gdev->chip) { \ @@ -2056,7 +2555,14 @@ int gpiod_to_irq(const struct gpio_desc *desc)  	struct gpio_chip *chip;  	int offset; -	VALIDATE_DESC(desc); +	/* +	 * Cannot VALIDATE_DESC() here as gpiod_to_irq() consumer semantics +	 * requires this function to not return zero on an invalid descriptor +	 * but rather a negative error number. +	 */ +	if (!desc || IS_ERR(desc) || !desc->gdev || !desc->gdev->chip) +		return -EINVAL; +  	chip = desc->gdev->chip;  	offset = gpio_chip_hwgpio(desc);  	if (chip->to_irq) { @@ -2326,7 +2832,7 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,  		desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,  						&of_flags); -		if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) +		if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))  			break;  	} @@ -2572,28 +3078,13 @@ struct gpio_desc *__must_check gpiod_get_optional(struct device *dev,  }  EXPORT_SYMBOL_GPL(gpiod_get_optional); -/** - * gpiod_parse_flags - helper function to parse GPIO lookup flags - * @desc:	gpio to be setup - * @lflags:	gpio_lookup_flags - returned from of_find_gpio() or - *		of_get_gpio_hog() - * - * Set the GPIO descriptor flags based on the given GPIO lookup flags. - */ -static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags) -{ -	if (lflags & GPIO_ACTIVE_LOW) -		set_bit(FLAG_ACTIVE_LOW, &desc->flags); -	if (lflags & GPIO_OPEN_DRAIN) -		set_bit(FLAG_OPEN_DRAIN, &desc->flags); -	if (lflags & GPIO_OPEN_SOURCE) -		set_bit(FLAG_OPEN_SOURCE, &desc->flags); -}  /**   * gpiod_configure_flags - helper function to configure a given GPIO   * @desc:	gpio whose value will be assigned   * @con_id:	function within the GPIO consumer + * @lflags:	gpio_lookup_flags - returned from of_find_gpio() or + *		of_get_gpio_hog()   * @dflags:	gpiod_flags - optional GPIO initialization flags   *   * Return 0 on success, -ENOENT if no GPIO has been assigned to the @@ -2601,10 +3092,17 @@ static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags)   * occurred while trying to acquire the GPIO.   */  static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, -				 enum gpiod_flags dflags) +		unsigned long lflags, enum gpiod_flags dflags)  {  	int status; +	if (lflags & GPIO_ACTIVE_LOW) +		set_bit(FLAG_ACTIVE_LOW, &desc->flags); +	if (lflags & GPIO_OPEN_DRAIN) +		set_bit(FLAG_OPEN_DRAIN, &desc->flags); +	if (lflags & GPIO_OPEN_SOURCE) +		set_bit(FLAG_OPEN_SOURCE, &desc->flags); +  	/* No particular flag request, return here... */  	if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {  		pr_debug("no flags found for %s\n", con_id); @@ -2671,13 +3169,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,  		return desc;  	} -	gpiod_parse_flags(desc, lookupflags); -  	status = gpiod_request(desc, con_id);  	if (status < 0)  		return ERR_PTR(status); -	status = gpiod_configure_flags(desc, con_id, flags); +	status = gpiod_configure_flags(desc, con_id, lookupflags, flags);  	if (status < 0) {  		dev_dbg(dev, "setup of GPIO %s failed\n", con_id);  		gpiod_put(desc); @@ -2733,6 +3229,10 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,  	if (IS_ERR(desc))  		return desc; +	ret = gpiod_request(desc, NULL); +	if (ret) +		return ERR_PTR(ret); +  	if (active_low)  		set_bit(FLAG_ACTIVE_LOW, &desc->flags); @@ -2743,10 +3243,6 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,  			set_bit(FLAG_OPEN_SOURCE, &desc->flags);  	} -	ret = gpiod_request(desc, NULL); -	if (ret) -		return ERR_PTR(ret); -  	return desc;  }  EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); @@ -2799,8 +3295,6 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,  	chip = gpiod_to_chip(desc);  	hwnum = gpio_chip_hwgpio(desc); -	gpiod_parse_flags(desc, lflags); -  	local_desc = gpiochip_request_own_desc(chip, hwnum, name);  	if (IS_ERR(local_desc)) {  		status = PTR_ERR(local_desc); @@ -2809,7 +3303,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,  		return status;  	} -	status = gpiod_configure_flags(desc, name, dflags); +	status = gpiod_configure_flags(desc, name, lflags, dflags);  	if (status < 0) {  		pr_err("setup of hog GPIO %s (chip %s, offset %d) failed, %d\n",  		       name, chip->label, hwnum, status);  |