diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-09 14:58:15 -0400 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-09 14:58:15 -0400 | 
| commit | ea584595fc85e65796335033dfca25ed655cd0ed (patch) | |
| tree | 79d444c507472f6c66d887ad332e7c1784eeb4de /drivers/gpio/gpio-stmpe.c | |
| parent | 782d59c5dfc5ac39ac8cfb4c6dd40597938dde9c (diff) | |
| parent | a092e19b688be88f7329bd05f90cb92ebe1a4f5b (diff) | |
Merge tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO changes from Linus Walleij:
 "This is the bulk of GPIO changes for the v3.18 development cycle:
   - Increase the default ARCH_NR_GPIO from 256 to 512.  This was done
     to avoid having a custom <asm/gpio.h> header for the x86
     architecture - GPIO is custom and complicated enough as it is
     already! We want to move to a radix to store the descriptors going
     forward, and finally get rid of this fixed array size altogether.
   - Endgame patching of the gpio_remove() semantics initiated by
     Abdoulaye Berthe.  It is not accepted by the system that the
     removal of a GPIO chip fails during eg reboot or shutdown, and
     therefore the return value has now painfully been refactored away.
     For special cases like GPIO expanders on a hot-pluggable bus like
     USB, we may later add some gpiochip_try_remove() call, but for the
     cases we have now, return values are moot.
   - Some incremental refactoring of the gpiolib core and ACPI GPIO
     library for more descriptor usage.
   - Refactor the chained IRQ handler set-up method to handle also
     threaded, nested interrupts and set up the parent IRQ correctly.
     Switch STMPE and TC3589x drivers to use this registration method.
   - Add a .irq_not_threaded flag to the struct gpio_chip, so that also
     GPIO expanders that block but are still not using threaded IRQ
     handlers.
   - New drivers for the ARM64 X-Gene SoC GPIO controller.
   - The syscon GPIO driver has been improved to handle the "DSP GPIO"
     found on the TI Keystone 2 SoC:s.
   - ADNP driver switched to use gpiolib irqchip helpers.
   - Refactor the DWAPB driver to support being instantiated from and
     MFD cell (platform device).
   - Incremental feature improvement in the Zynq, MCP23S08, DWAPB, OMAP,
     Xilinx and Crystalcove drivers.
   - Various minor fixes"
* tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (52 commits)
  gpio: pch: Build context save/restore only for PM
  pinctrl: abx500: get rid of unused variable
  gpio: ks8695: fix 'else should follow close brace '}''
  gpio: stmpe: add verbose debug code
  gpio: stmpe: fix up interrupt enable logic
  gpio: staticize xway_stp_init()
  gpio: handle also nested irqchips in the chained handler set-up
  gpio: set parent irq on chained handlers
  gpiolib: irqchip: use irq_find_mapping while removing irqchip
  gpio: crystalcove: support virtual GPIO
  pinctrl: bcm281xx: make Kconfig dependency more strict
  gpio: kona: enable only on BCM_MOBILE or for compile testing
  gpio, bcm-kona, LLVMLinux: Remove use of __initconst
  gpio: Fix ngpio in gpio-xilinx driver
  gpio: dwapb: fix pointer to integer cast
  gpio: xgene: Remove unneeded #ifdef CONFIG_OF guard
  gpio: xgene: Remove unneeded forward declation for struct xgene_gpio
  gpio: xgene: Fix missing spin_lock_init()
  gpio: ks8695: fix switch case indentation
  gpiolib: add irq_not_threaded flag to gpio_chip
  ...
Diffstat (limited to 'drivers/gpio/gpio-stmpe.c')
| -rw-r--r-- | drivers/gpio/gpio-stmpe.c | 99 | 
1 files changed, 90 insertions, 9 deletions
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 845025a57240..85c5b1974294 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -13,6 +13,7 @@  #include <linux/interrupt.h>  #include <linux/of.h>  #include <linux/mfd/stmpe.h> +#include <linux/seq_file.h>  /*   * These registers are modified under the irq bus lock and cached to avoid @@ -127,19 +128,19 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)  	int regoffset = offset / 8;  	int mask = 1 << (offset % 8); -	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) +	if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH)  		return -EINVAL;  	/* STMPE801 doesn't have RE and FE registers */  	if (stmpe_gpio->stmpe->partnum == STMPE801)  		return 0; -	if (type == IRQ_TYPE_EDGE_RISING) +	if (type & IRQ_TYPE_EDGE_RISING)  		stmpe_gpio->regs[REG_RE][regoffset] |= mask;  	else  		stmpe_gpio->regs[REG_RE][regoffset] &= ~mask; -	if (type == IRQ_TYPE_EDGE_FALLING) +	if (type & IRQ_TYPE_EDGE_FALLING)  		stmpe_gpio->regs[REG_FE][regoffset] |= mask;  	else  		stmpe_gpio->regs[REG_FE][regoffset] &= ~mask; @@ -211,6 +212,77 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d)  	stmpe_gpio->regs[REG_IE][regoffset] |= mask;  } +static void stmpe_dbg_show_one(struct seq_file *s, +			       struct gpio_chip *gc, +			       unsigned offset, unsigned gpio) +{ +	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); +	struct stmpe *stmpe = stmpe_gpio->stmpe; +	const char *label = gpiochip_is_requested(gc, offset); +	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); +	bool val = !!stmpe_gpio_get(gc, offset); +	u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8); +	u8 mask = 1 << (offset % 8); +	int ret; +	u8 dir; + +	ret = stmpe_reg_read(stmpe, dir_reg); +	if (ret < 0) +		return; +	dir = !!(ret & mask); + +	if (dir) { +		seq_printf(s, " gpio-%-3d (%-20.20s) out %s", +			   gpio, label ?: "(none)", +			   val ? "hi" : "lo"); +	} else { +		u8 edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_MSB] + num_banks - 1 - (offset / 8); +		u8 rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB] - (offset / 8); +		u8 fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB] - (offset / 8); +		u8 irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB] - (offset / 8); +		bool edge_det; +		bool rise; +		bool fall; +		bool irqen; + +		ret = stmpe_reg_read(stmpe, edge_det_reg); +		if (ret < 0) +			return; +		edge_det = !!(ret & mask); +		ret = stmpe_reg_read(stmpe, rise_reg); +		if (ret < 0) +			return; +		rise = !!(ret & mask); +		ret = stmpe_reg_read(stmpe, fall_reg); +		if (ret < 0) +			return; +		fall = !!(ret & mask); +		ret = stmpe_reg_read(stmpe, irqen_reg); +		if (ret < 0) +			return; +		irqen = !!(ret & mask); + +		seq_printf(s, " gpio-%-3d (%-20.20s) in  %s %s %s%s%s", +			   gpio, label ?: "(none)", +			   val ? "hi" : "lo", +			   edge_det ? "edge-asserted" : "edge-inactive", +			   irqen ? "IRQ-enabled" : "", +			   rise ? " rising-edge-detection" : "", +			   fall ? " falling-edge-detection" : ""); +	} +} + +static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc) +{ +	unsigned i; +	unsigned gpio = gc->base; + +	for (i = 0; i < gc->ngpio; i++, gpio++) { +		stmpe_dbg_show_one(s, gc, i, gpio); +		seq_printf(s, "\n"); +	} +} +  static struct irq_chip stmpe_gpio_irq_chip = {  	.name			= "stmpe-gpio",  	.irq_bus_lock		= stmpe_gpio_irq_lock, @@ -293,6 +365,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)  #endif  	stmpe_gpio->chip.base = -1; +	if (IS_ENABLED(CONFIG_DEBUG_FS)) +                stmpe_gpio->chip.dbg_show = stmpe_dbg_show; +  	if (pdata)  		stmpe_gpio->norequest_mask = pdata->norequest_mask;  	else if (np) @@ -308,6 +383,12 @@ static int stmpe_gpio_probe(struct platform_device *pdev)  	if (ret)  		goto out_free; +	ret = gpiochip_add(&stmpe_gpio->chip); +	if (ret) { +		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); +		goto out_disable; +	} +  	if (irq > 0) {  		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,  				stmpe_gpio_irq, IRQF_ONESHOT, @@ -324,14 +405,13 @@ static int stmpe_gpio_probe(struct platform_device *pdev)  		if (ret) {  			dev_err(&pdev->dev,  				"could not connect irqchip to gpiochip\n"); -			return ret; +			goto out_disable;  		} -	} -	ret = gpiochip_add(&stmpe_gpio->chip); -	if (ret) { -		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); -		goto out_disable; +		gpiochip_set_chained_irqchip(&stmpe_gpio->chip, +					     &stmpe_gpio_irq_chip, +					     irq, +					     NULL);  	}  	if (pdata && pdata->setup) @@ -343,6 +423,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)  out_disable:  	stmpe_disable(stmpe, STMPE_BLOCK_GPIO); +	gpiochip_remove(&stmpe_gpio->chip);  out_free:  	kfree(stmpe_gpio);  	return ret;  | 
