Merge commit 'gpio-lw/devel' into spear-for-3.8

This merges dependency branch gpio-lw/devel for SPEAr DT updates.
This commit is contained in:
Viresh Kumar 2012-11-26 15:48:53 +05:30
commit 53d74fd79d
21 changed files with 931 additions and 181 deletions

View File

@ -0,0 +1,50 @@
=== ST Microelectronics SPEAr SPI CS Driver ===
SPEAr platform provides a provision to control chipselects of ARM PL022 Prime
Cell spi controller through its system registers, which otherwise remains under
PL022 control. If chipselect remain under PL022 control then they would be
released as soon as transfer is over and TxFIFO becomes empty. This is not
desired by some of the device protocols above spi which expect (multiple)
transfers without releasing their chipselects.
Chipselects can be controlled by software by turning them as GPIOs. SPEAr
provides another interface through system registers through which software can
directly control each PL022 chipselect. Hence, it is natural for SPEAr to export
the control of this interface as gpio.
Required properties:
* compatible: should be defined as "st,spear-spics-gpio"
* reg: mentioning address range of spics controller
* st-spics,peripcfg-reg: peripheral configuration register offset
* st-spics,sw-enable-bit: bit offset to enable sw control
* st-spics,cs-value-bit: bit offset to drive chipselect low or high
* st-spics,cs-enable-mask: chip select number bit mask
* st-spics,cs-enable-shift: chip select number program offset
* gpio-controller: Marks the device node as gpio controller
* #gpio-cells: should be 1 and will mention chip select number
All the above bit offsets are within peripcfg register.
Example:
-------
spics: spics@e0700000{
compatible = "st,spear-spics-gpio";
reg = <0xe0700000 0x1000>;
st-spics,peripcfg-reg = <0x3b0>;
st-spics,sw-enable-bit = <12>;
st-spics,cs-value-bit = <11>;
st-spics,cs-enable-mask = <3>;
st-spics,cs-enable-shift = <8>;
gpio-controller;
#gpio-cells = <2>;
};
spi0: spi@e0100000 {
status = "okay";
num-cs = <3>;
cs-gpios = <&gpio1 7 0>, <&spics 0>,
<&spics 1>;
...
}

View File

@ -364,6 +364,7 @@ config ARCH_CNS3XXX
config ARCH_CLPS711X
bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
select ARCH_REQUIRE_GPIOLIB
select ARCH_USES_GETTIMEOFFSET
select CLKDEV_LOOKUP
select COMMON_CLK

View File

@ -12,6 +12,7 @@ config ARCH_SPEAR13XX
bool "ST SPEAr13xx with Device Tree"
select ARM_GIC
select CPU_V7
select GPIO_SPEAR_SPICS
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
select PINCTRL

View File

@ -86,11 +86,26 @@ config GPIO_DA9052
help
Say yes here to enable the GPIO driver for the DA9052 chip.
config GPIO_DA9055
tristate "Dialog Semiconductor DA9055 GPIO"
depends on MFD_DA9055
help
Say yes here to enable the GPIO driver for the DA9055 chip.
The Dialog DA9055 PMIC chip has 3 GPIO pins that can be
be controller by this driver.
If driver is built as a module it will be called gpio-da9055.
config GPIO_MAX730X
tristate
comment "Memory mapped GPIO drivers:"
config GPIO_CLPS711X
def_bool y
depends on ARCH_CLPS711X
config GPIO_GENERIC_PLATFORM
tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
select GPIO_GENERIC
@ -181,6 +196,13 @@ config GPIO_PXA
help
Say yes here to support the PXA GPIO device
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
depends on PLAT_SPEAR
select GENERIC_IRQ_CHIP
help
Say yes here to support ST SPEAr SPI Chip Select as GPIO device
config GPIO_STA2X11
bool "STA2x11/ConneXt GPIO support"
depends on MFD_STA2X11

View File

@ -16,8 +16,10 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
@ -57,6 +59,7 @@ obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o

View File

@ -0,0 +1,199 @@
/*
* CLPS711X GPIO driver
*
* Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
*
* 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/io.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <mach/hardware.h>
#define CLPS711X_GPIO_PORTS 5
#define CLPS711X_GPIO_NAME "gpio-clps711x"
struct clps711x_gpio {
struct gpio_chip chip[CLPS711X_GPIO_PORTS];
spinlock_t lock;
};
static void __iomem *clps711x_ports[] = {
CLPS711X_VIRT_BASE + PADR,
CLPS711X_VIRT_BASE + PBDR,
CLPS711X_VIRT_BASE + PCDR,
CLPS711X_VIRT_BASE + PDDR,
CLPS711X_VIRT_BASE + PEDR,
};
static void __iomem *clps711x_pdirs[] = {
CLPS711X_VIRT_BASE + PADDR,
CLPS711X_VIRT_BASE + PBDDR,
CLPS711X_VIRT_BASE + PCDDR,
CLPS711X_VIRT_BASE + PDDDR,
CLPS711X_VIRT_BASE + PEDDR,
};
#define clps711x_port(x) clps711x_ports[x->base / 8]
#define clps711x_pdir(x) clps711x_pdirs[x->base / 8]
static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset)
{
return !!(readb(clps711x_port(chip)) & (1 << offset));
}
static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset,
int value)
{
int tmp;
unsigned long flags;
struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
spin_lock_irqsave(&gpio->lock, flags);
tmp = readb(clps711x_port(chip)) & ~(1 << offset);
if (value)
tmp |= 1 << offset;
writeb(tmp, clps711x_port(chip));
spin_unlock_irqrestore(&gpio->lock, flags);
}
static int gpio_clps711x_dir_in(struct gpio_chip *chip, unsigned offset)
{
int tmp;
unsigned long flags;
struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
spin_lock_irqsave(&gpio->lock, flags);
tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
writeb(tmp, clps711x_pdir(chip));
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
}
static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset,
int value)
{
int tmp;
unsigned long flags;
struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
spin_lock_irqsave(&gpio->lock, flags);
tmp = readb(clps711x_pdir(chip)) | (1 << offset);
writeb(tmp, clps711x_pdir(chip));
tmp = readb(clps711x_port(chip)) & ~(1 << offset);
if (value)
tmp |= 1 << offset;
writeb(tmp, clps711x_port(chip));
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
}
static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset)
{
int tmp;
unsigned long flags;
struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
spin_lock_irqsave(&gpio->lock, flags);
tmp = readb(clps711x_pdir(chip)) | (1 << offset);
writeb(tmp, clps711x_pdir(chip));
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
}
static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset,
int value)
{
int tmp;
unsigned long flags;
struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
spin_lock_irqsave(&gpio->lock, flags);
tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
writeb(tmp, clps711x_pdir(chip));
tmp = readb(clps711x_port(chip)) & ~(1 << offset);
if (value)
tmp |= 1 << offset;
writeb(tmp, clps711x_port(chip));
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
}
static struct {
char *name;
int nr;
int inv_dir;
} clps711x_gpio_ports[] __initconst = {
{ "PORTA", 8, 0, },
{ "PORTB", 8, 0, },
{ "PORTC", 8, 0, },
{ "PORTD", 8, 1, },
{ "PORTE", 3, 0, },
};
static int __init gpio_clps711x_init(void)
{
int i;
struct platform_device *pdev;
struct clps711x_gpio *gpio;
pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0);
if (!pdev) {
pr_err("Cannot create platform device: %s\n",
CLPS711X_GPIO_NAME);
return -ENOMEM;
}
platform_device_add(pdev);
gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio),
GFP_KERNEL);
if (!gpio) {
dev_err(&pdev->dev, "GPIO allocating memory error\n");
platform_device_unregister(pdev);
return -ENOMEM;
}
platform_set_drvdata(pdev, gpio);
spin_lock_init(&gpio->lock);
for (i = 0; i < CLPS711X_GPIO_PORTS; i++) {
gpio->chip[i].owner = THIS_MODULE;
gpio->chip[i].dev = &pdev->dev;
gpio->chip[i].label = clps711x_gpio_ports[i].name;
gpio->chip[i].base = i * 8;
gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr;
gpio->chip[i].get = gpio_clps711x_get;
gpio->chip[i].set = gpio_clps711x_set;
if (!clps711x_gpio_ports[i].inv_dir) {
gpio->chip[i].direction_input = gpio_clps711x_dir_in;
gpio->chip[i].direction_output = gpio_clps711x_dir_out;
} else {
gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv;
gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv;
}
WARN_ON(gpiochip_add(&gpio->chip[i]));
}
dev_info(&pdev->dev, "GPIO driver initialized\n");
return 0;
}
arch_initcall(gpio_clps711x_init);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
MODULE_DESCRIPTION("CLPS711X GPIO driver");

204
drivers/gpio/gpio-da9055.c Normal file
View File

@ -0,0 +1,204 @@
/*
* GPIO Driver for Dialog DA9055 PMICs.
*
* Copyright(c) 2012 Dialog Semiconductor Ltd.
*
* Author: David Dajun Chen <dchen@diasemi.com>
*
* 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/platform_device.h>
#include <linux/gpio.h>
#include <linux/mfd/da9055/core.h>
#include <linux/mfd/da9055/reg.h>
#include <linux/mfd/da9055/pdata.h>
#define DA9055_VDD_IO 0x0
#define DA9055_PUSH_PULL 0x3
#define DA9055_ACT_LOW 0x0
#define DA9055_GPI 0x1
#define DA9055_PORT_MASK 0x3
#define DA9055_PORT_SHIFT(offset) (4 * (offset % 2))
#define DA9055_INPUT DA9055_GPI
#define DA9055_OUTPUT DA9055_PUSH_PULL
#define DA9055_IRQ_GPI0 3
struct da9055_gpio {
struct da9055 *da9055;
struct gpio_chip gp;
};
static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct da9055_gpio, gp);
}
static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
int gpio_direction = 0;
int ret;
/* Get GPIO direction */
ret = da9055_reg_read(gpio->da9055, (offset >> 1) + DA9055_REG_GPIO0_1);
if (ret < 0)
return ret;
gpio_direction = ret & (DA9055_PORT_MASK) << DA9055_PORT_SHIFT(offset);
gpio_direction >>= DA9055_PORT_SHIFT(offset);
switch (gpio_direction) {
case DA9055_INPUT:
ret = da9055_reg_read(gpio->da9055, DA9055_REG_STATUS_B);
if (ret < 0)
return ret;
break;
case DA9055_OUTPUT:
ret = da9055_reg_read(gpio->da9055, DA9055_REG_GPIO_MODE0_2);
if (ret < 0)
return ret;
}
return ret & (1 << offset);
}
static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
da9055_reg_update(gpio->da9055,
DA9055_REG_GPIO_MODE0_2,
1 << offset,
value << offset);
}
static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
unsigned char reg_byte;
reg_byte = (DA9055_ACT_LOW | DA9055_GPI)
<< DA9055_PORT_SHIFT(offset);
return da9055_reg_update(gpio->da9055, (offset >> 1) +
DA9055_REG_GPIO0_1,
DA9055_PORT_MASK <<
DA9055_PORT_SHIFT(offset),
reg_byte);
}
static int da9055_gpio_direction_output(struct gpio_chip *gc,
unsigned offset, int value)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
unsigned char reg_byte;
int ret;
reg_byte = (DA9055_VDD_IO | DA9055_PUSH_PULL)
<< DA9055_PORT_SHIFT(offset);
ret = da9055_reg_update(gpio->da9055, (offset >> 1) +
DA9055_REG_GPIO0_1,
DA9055_PORT_MASK <<
DA9055_PORT_SHIFT(offset),
reg_byte);
if (ret < 0)
return ret;
da9055_gpio_set(gc, offset, value);
return 0;
}
static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset)
{
struct da9055_gpio *gpio = to_da9055_gpio(gc);
struct da9055 *da9055 = gpio->da9055;
return regmap_irq_get_virq(da9055->irq_data,
DA9055_IRQ_GPI0 + offset);
}
static struct gpio_chip reference_gp __devinitdata = {
.label = "da9055-gpio",
.owner = THIS_MODULE,
.get = da9055_gpio_get,
.set = da9055_gpio_set,
.direction_input = da9055_gpio_direction_input,
.direction_output = da9055_gpio_direction_output,
.to_irq = da9055_gpio_to_irq,
.can_sleep = 1,
.ngpio = 3,
.base = -1,
};
static int __devinit da9055_gpio_probe(struct platform_device *pdev)
{
struct da9055_gpio *gpio;
struct da9055_pdata *pdata;
int ret;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (gpio == NULL)
return -ENOMEM;
gpio->da9055 = dev_get_drvdata(pdev->dev.parent);
pdata = gpio->da9055->dev->platform_data;
gpio->gp = reference_gp;
if (pdata && pdata->gpio_base)
gpio->gp.base = pdata->gpio_base;
ret = gpiochip_add(&gpio->gp);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
goto err_mem;
}
platform_set_drvdata(pdev, gpio);
return 0;
err_mem:
return ret;
}
static int __devexit da9055_gpio_remove(struct platform_device *pdev)
{
struct da9055_gpio *gpio = platform_get_drvdata(pdev);
return gpiochip_remove(&gpio->gp);
}
static struct platform_driver da9055_gpio_driver = {
.probe = da9055_gpio_probe,
.remove = __devexit_p(da9055_gpio_remove),
.driver = {
.name = "da9055-gpio",
.owner = THIS_MODULE,
},
};
static int __init da9055_gpio_init(void)
{
return platform_driver_register(&da9055_gpio_driver);
}
subsys_initcall(da9055_gpio_init);
static void __exit da9055_gpio_exit(void)
{
platform_driver_unregister(&da9055_gpio_driver);
}
module_exit(da9055_gpio_exit);
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
MODULE_DESCRIPTION("DA9055 GPIO Device Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9055-gpio");

View File

@ -35,7 +35,6 @@
struct em_gio_priv {
void __iomem *base0;
void __iomem *base1;
unsigned int irq_base;
spinlock_t sense_lock;
struct platform_device *pdev;
struct gpio_chip gpio_chip;
@ -214,7 +213,7 @@ static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
{
return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
}
static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
@ -234,40 +233,6 @@ static struct irq_domain_ops em_gio_irq_domain_ops = {
.map = em_gio_irq_domain_map,
};
static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
{
struct platform_device *pdev = p->pdev;
struct gpio_em_config *pdata = pdev->dev.platform_data;
p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
pdata->number_of_pins, numa_node_id());
if (p->irq_base < 0) {
dev_err(&pdev->dev, "cannot get irq_desc\n");
return p->irq_base;
}
pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
pdata->gpio_base, pdata->number_of_pins, p->irq_base);
p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
pdata->number_of_pins,
p->irq_base, 0,
&em_gio_irq_domain_ops, p);
if (!p->irq_domain) {
irq_free_descs(p->irq_base, pdata->number_of_pins);
return -ENXIO;
}
return 0;
}
static void em_gio_irq_domain_cleanup(struct em_gio_priv *p)
{
struct gpio_em_config *pdata = p->pdev->dev.platform_data;
irq_free_descs(p->irq_base, pdata->number_of_pins);
/* FIXME: irq domain wants to be freed! */
}
static int __devinit em_gio_probe(struct platform_device *pdev)
{
struct gpio_em_config *pdata = pdev->dev.platform_data;
@ -334,8 +299,11 @@ static int __devinit em_gio_probe(struct platform_device *pdev)
irq_chip->irq_set_type = em_gio_irq_set_type;
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
ret = em_gio_irq_domain_init(p);
if (ret) {
p->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
pdata->number_of_pins,
&em_gio_irq_domain_ops, p);
if (!p->irq_domain) {
ret = -ENXIO;
dev_err(&pdev->dev, "cannot initialize irq domain\n");
goto err3;
}
@ -364,7 +332,7 @@ err6:
err5:
free_irq(irq[0]->start, pdev);
err4:
em_gio_irq_domain_cleanup(p);
irq_domain_remove(p->irq_domain);
err3:
iounmap(p->base1);
err2:
@ -390,7 +358,7 @@ static int __devexit em_gio_remove(struct platform_device *pdev)
free_irq(irq[1]->start, pdev);
free_irq(irq[0]->start, pdev);
em_gio_irq_domain_cleanup(p);
irq_domain_remove(p->irq_domain);
iounmap(p->base1);
iounmap(p->base0);
kfree(p);

View File

@ -167,10 +167,6 @@ int __devinit __max730x_probe(struct max7301 *ts)
int i, ret;
pdata = dev->platform_data;
if (!pdata || !pdata->base) {
dev_err(dev, "incorrect or missing platform data\n");
return -EINVAL;
}
mutex_init(&ts->lock);
dev_set_drvdata(dev, ts);
@ -178,7 +174,12 @@ int __devinit __max730x_probe(struct max7301 *ts)
/* Power up the chip and disable IRQ output */
ts->write(dev, 0x04, 0x01);
ts->input_pullup_active = pdata->input_pullup_active;
if (pdata) {
ts->input_pullup_active = pdata->input_pullup_active;
ts->chip.base = pdata->base;
} else {
ts->chip.base = -1;
}
ts->chip.label = dev->driver->name;
ts->chip.direction_input = max7301_direction_input;
@ -186,7 +187,6 @@ int __devinit __max730x_probe(struct max7301 *ts)
ts->chip.direction_output = max7301_direction_output;
ts->chip.set = max7301_set;
ts->chip.base = pdata->base;
ts->chip.ngpio = PIN_NUMBER;
ts->chip.can_sleep = 1;
ts->chip.dev = dev;

View File

@ -168,12 +168,12 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
* Functions implementing the gpio_chip methods
*/
int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin)
static int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin)
{
return pinctrl_request_gpio(chip->base + pin);
}
void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin)
static void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin)
{
pinctrl_free_gpio(chip->base + pin);
}
@ -546,6 +546,7 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
mvchip->chip.label = dev_name(&pdev->dev);
mvchip->chip.dev = &pdev->dev;
mvchip->chip.request = mvebu_gpio_request;
mvchip->chip.free = mvebu_gpio_free;
mvchip->chip.direction_input = mvebu_gpio_direction_input;
mvchip->chip.get = mvebu_gpio_get;
mvchip->chip.direction_output = mvebu_gpio_direction_output;
@ -673,8 +674,8 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
/* Setup irq domain on top of the generic chip. */
mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio,
mvchip->irqbase, 0,
mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio,
mvchip->irqbase,
&irq_domain_simple_ops,
mvchip);
if (!mvchip->domain) {

View File

@ -1105,7 +1105,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
if (!pdata)
return -EINVAL;
bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL);
bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL);
if (!bank) {
dev_err(dev, "Memory alloc failed\n");
return -ENOMEM;

View File

@ -16,6 +16,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/i2c.h>
#include <linux/i2c/pca953x.h>
#include <linux/slab.h>
@ -83,6 +84,7 @@ struct pca953x_chip {
u32 irq_trig_raise;
u32 irq_trig_fall;
int irq_base;
struct irq_domain *domain;
#endif
struct i2c_client *client;
@ -333,14 +335,14 @@ static void pca953x_irq_mask(struct irq_data *d)
{
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
chip->irq_mask &= ~(1 << (d->irq - chip->irq_base));
chip->irq_mask &= ~(1 << d->hwirq);
}
static void pca953x_irq_unmask(struct irq_data *d)
{
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
chip->irq_mask |= 1 << (d->irq - chip->irq_base);
chip->irq_mask |= 1 << d->hwirq;
}
static void pca953x_irq_bus_lock(struct irq_data *d)
@ -372,8 +374,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
{
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
u32 level = d->irq - chip->irq_base;
u32 mask = 1 << level;
u32 mask = 1 << d->hwirq;
if (!(type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
@ -454,7 +455,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
do {
level = __ffs(pending);
handle_nested_irq(level + chip->irq_base);
handle_nested_irq(irq_find_mapping(chip->domain, level));
pending &= ~(1 << level);
} while (pending);
@ -499,6 +500,17 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
if (chip->irq_base < 0)
goto out_failed;
chip->domain = irq_domain_add_legacy(client->dev.of_node,
chip->gpio_chip.ngpio,
chip->irq_base,
0,
&irq_domain_simple_ops,
NULL);
if (!chip->domain) {
ret = -ENODEV;
goto out_irqdesc_free;
}
for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) {
int irq = lvl + chip->irq_base;
@ -521,7 +533,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
client->irq);
goto out_failed;
goto out_irqdesc_free;
}
chip->gpio_chip.to_irq = pca953x_gpio_to_irq;
@ -529,6 +541,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return 0;
out_irqdesc_free:
irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio);
out_failed:
chip->irq_base = -1;
return ret;
@ -751,9 +765,38 @@ static int pca953x_remove(struct i2c_client *client)
return 0;
}
static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "nxp,pca9534", },
{ .compatible = "nxp,pca9535", },
{ .compatible = "nxp,pca9536", },
{ .compatible = "nxp,pca9537", },
{ .compatible = "nxp,pca9538", },
{ .compatible = "nxp,pca9539", },
{ .compatible = "nxp,pca9554", },
{ .compatible = "nxp,pca9555", },
{ .compatible = "nxp,pca9556", },
{ .compatible = "nxp,pca9557", },
{ .compatible = "nxp,pca9574", },
{ .compatible = "nxp,pca9575", },
{ .compatible = "maxim,max7310", },
{ .compatible = "maxim,max7312", },
{ .compatible = "maxim,max7313", },
{ .compatible = "maxim,max7315", },
{ .compatible = "ti,pca6107", },
{ .compatible = "ti,tca6408", },
{ .compatible = "ti,tca6416", },
{ .compatible = "ti,tca6424", },
{ }
};
MODULE_DEVICE_TABLE(of, pca953x_dt_ids);
static struct i2c_driver pca953x_driver = {
.driver = {
.name = "pca953x",
.of_match_table = pca953x_dt_ids,
},
.probe = pca953x_probe,
.remove = pca953x_remove,

View File

@ -215,6 +215,7 @@ static void pch_gpio_setup(struct pch_gpio *chip)
struct gpio_chip *gpio = &chip->gpio;
gpio->label = dev_name(chip->dev);
gpio->dev = chip->dev;
gpio->owner = THIS_MODULE;
gpio->direction_input = pch_gpio_direction_input;
gpio->get = pch_gpio_get;

View File

@ -216,39 +216,34 @@ static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
}
static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct pl061_platform_data *pdata;
struct device *dev = &adev->dev;
struct pl061_platform_data *pdata = dev->platform_data;
struct pl061_gpio *chip;
int ret, irq, i;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
pdata = dev->dev.platform_data;
if (pdata) {
chip->gc.base = pdata->gpio_base;
chip->irq_base = pdata->irq_base;
} else if (dev->dev.of_node) {
} else if (adev->dev.of_node) {
chip->gc.base = -1;
chip->irq_base = 0;
} else {
ret = -ENODEV;
goto free_mem;
}
} else
return -ENODEV;
if (!request_mem_region(dev->res.start,
resource_size(&dev->res), "pl061")) {
ret = -EBUSY;
goto free_mem;
}
if (!devm_request_mem_region(dev, adev->res.start,
resource_size(&adev->res), "pl061"))
return -EBUSY;
chip->base = ioremap(dev->res.start, resource_size(&dev->res));
if (chip->base == NULL) {
ret = -ENOMEM;
goto release_region;
}
chip->base = devm_ioremap(dev, adev->res.start,
resource_size(&adev->res));
if (chip->base == NULL)
return -ENOMEM;
spin_lock_init(&chip->lock);
@ -258,13 +253,13 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
chip->gc.set = pl061_set_value;
chip->gc.to_irq = pl061_to_irq;
chip->gc.ngpio = PL061_GPIO_NR;
chip->gc.label = dev_name(&dev->dev);
chip->gc.dev = &dev->dev;
chip->gc.label = dev_name(dev);
chip->gc.dev = dev;
chip->gc.owner = THIS_MODULE;
ret = gpiochip_add(&chip->gc);
if (ret)
goto iounmap;
return ret;
/*
* irq_chip support
@ -276,11 +271,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
pl061_init_gc(chip, chip->irq_base);
writeb(0, chip->base + GPIOIE); /* disable irqs */
irq = dev->irq[0];
if (irq < 0) {
ret = -ENODEV;
goto iounmap;
}
irq = adev->irq[0];
if (irq < 0)
return -ENODEV;
irq_set_chained_handler(irq, pl061_irq_handler);
irq_set_handler_data(irq, chip);
@ -294,18 +288,9 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
}
}
amba_set_drvdata(dev, chip);
amba_set_drvdata(adev, chip);
return 0;
iounmap:
iounmap(chip->base);
release_region:
release_mem_region(dev->res.start, resource_size(&dev->res));
free_mem:
kfree(chip);
return ret;
}
#ifdef CONFIG_PM

View File

@ -0,0 +1,217 @@
/*
* SPEAr platform SPI chipselect abstraction over gpiolib
*
* Copyright (C) 2012 ST Microelectronics
* Shiraz Hashim <shiraz.hashim@st.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/gpio.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/types.h>
/* maximum chipselects */
#define NUM_OF_GPIO 4
/*
* Provision is available on some SPEAr SoCs to control ARM PL022 spi cs
* through system registers. This register lies outside spi (pl022)
* address space into system registers.
*
* It provides control for spi chip select lines so that any chipselect
* (out of 4 possible chipselects in pl022) can be made low to select
* the particular slave.
*/
/**
* struct spear_spics - represents spi chip select control
* @base: base address
* @perip_cfg: configuration register
* @sw_enable_bit: bit to enable s/w control over chipselects
* @cs_value_bit: bit to program high or low chipselect
* @cs_enable_mask: mask to select bits required to select chipselect
* @cs_enable_shift: bit pos of cs_enable_mask
* @use_count: use count of a spi controller cs lines
* @last_off: stores last offset caller of set_value()
* @chip: gpio_chip abstraction
*/
struct spear_spics {
void __iomem *base;
u32 perip_cfg;
u32 sw_enable_bit;
u32 cs_value_bit;
u32 cs_enable_mask;
u32 cs_enable_shift;
unsigned long use_count;
int last_off;
struct gpio_chip chip;
};
/* gpio framework specific routines */
static int spics_get_value(struct gpio_chip *chip, unsigned offset)
{
return -ENXIO;
}
static void spics_set_value(struct gpio_chip *chip, unsigned offset, int value)
{
struct spear_spics *spics = container_of(chip, struct spear_spics,
chip);
u32 tmp;
/* select chip select from register */
tmp = readl_relaxed(spics->base + spics->perip_cfg);
if (spics->last_off != offset) {
spics->last_off = offset;
tmp &= ~(spics->cs_enable_mask << spics->cs_enable_shift);
tmp |= offset << spics->cs_enable_shift;
}
/* toggle chip select line */
tmp &= ~(0x1 << spics->cs_value_bit);
tmp |= value << spics->cs_value_bit;
writel_relaxed(tmp, spics->base + spics->perip_cfg);
}
static int spics_direction_input(struct gpio_chip *chip, unsigned offset)
{
return -ENXIO;
}
static int spics_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
spics_set_value(chip, offset, value);
return 0;
}
static int spics_request(struct gpio_chip *chip, unsigned offset)
{
struct spear_spics *spics = container_of(chip, struct spear_spics,
chip);
u32 tmp;
if (!spics->use_count++) {
tmp = readl_relaxed(spics->base + spics->perip_cfg);
tmp |= 0x1 << spics->sw_enable_bit;
tmp |= 0x1 << spics->cs_value_bit;
writel_relaxed(tmp, spics->base + spics->perip_cfg);
}
return 0;
}
static void spics_free(struct gpio_chip *chip, unsigned offset)
{
struct spear_spics *spics = container_of(chip, struct spear_spics,
chip);
u32 tmp;
if (!--spics->use_count) {
tmp = readl_relaxed(spics->base + spics->perip_cfg);
tmp &= ~(0x1 << spics->sw_enable_bit);
writel_relaxed(tmp, spics->base + spics->perip_cfg);
}
}
static int spics_gpio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct spear_spics *spics;
struct resource *res;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n");
return -EBUSY;
}
spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL);
if (!spics) {
dev_err(&pdev->dev, "memory allocation fail\n");
return -ENOMEM;
}
spics->base = devm_request_and_ioremap(&pdev->dev, res);
if (!spics->base) {
dev_err(&pdev->dev, "request and ioremap fail\n");
return -ENOMEM;
}
if (of_property_read_u32(np, "st-spics,peripcfg-reg",
&spics->perip_cfg))
goto err_dt_data;
if (of_property_read_u32(np, "st-spics,sw-enable-bit",
&spics->sw_enable_bit))
goto err_dt_data;
if (of_property_read_u32(np, "st-spics,cs-value-bit",
&spics->cs_value_bit))
goto err_dt_data;
if (of_property_read_u32(np, "st-spics,cs-enable-mask",
&spics->cs_enable_mask))
goto err_dt_data;
if (of_property_read_u32(np, "st-spics,cs-enable-shift",
&spics->cs_enable_shift))
goto err_dt_data;
platform_set_drvdata(pdev, spics);
spics->chip.ngpio = NUM_OF_GPIO;
spics->chip.base = -1;
spics->chip.request = spics_request;
spics->chip.free = spics_free;
spics->chip.direction_input = spics_direction_input;
spics->chip.direction_output = spics_direction_output;
spics->chip.get = spics_get_value;
spics->chip.set = spics_set_value;
spics->chip.label = dev_name(&pdev->dev);
spics->chip.dev = &pdev->dev;
spics->chip.owner = THIS_MODULE;
spics->last_off = -1;
ret = gpiochip_add(&spics->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpio chip\n");
return ret;
}
dev_info(&pdev->dev, "spear spics registered\n");
return 0;
err_dt_data:
dev_err(&pdev->dev, "DT probe failed\n");
return -EINVAL;
}
static const struct of_device_id spics_gpio_of_match[] = {
{ .compatible = "st,spear-spics-gpio" },
{}
};
MODULE_DEVICE_TABLE(of, spics_gpio_of_match);
static struct platform_driver spics_gpio_driver = {
.probe = spics_gpio_probe,
.driver = {
.owner = THIS_MODULE,
.name = "spear-spics-gpio",
.of_match_table = spics_gpio_of_match,
},
};
static int __init spics_gpio_init(void)
{
return platform_driver_register(&spics_gpio_driver);
}
subsys_initcall(spics_gpio_init);
MODULE_AUTHOR("Shiraz Hashim <shiraz.hashim@st.com>");
MODULE_DESCRIPTION("ST Microlectronics SPEAr SPI Chip Select Abstraction");
MODULE_LICENSE("GPL");

View File

@ -292,17 +292,15 @@ static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio,
{
int base = tc3589x_gpio->irq_base;
if (base) {
tc3589x_gpio->domain = irq_domain_add_legacy(
NULL, tc3589x_gpio->chip.ngpio, base,
0, &tc3589x_irq_ops, tc3589x_gpio);
}
else {
tc3589x_gpio->domain = irq_domain_add_linear(
np, tc3589x_gpio->chip.ngpio,
&tc3589x_irq_ops, tc3589x_gpio);
}
/*
* If this results in a linear domain, irq_create_mapping() will
* take care of allocating IRQ descriptors at runtime. When a base
* is provided, the IRQ descriptors will be allocated when the
* domain is instantiated.
*/
tc3589x_gpio->domain = irq_domain_add_simple(np,
tc3589x_gpio->chip.ngpio, base, &tc3589x_irq_ops,
tc3589x_gpio);
if (!tc3589x_gpio->domain) {
dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n");
return -ENOSYS;

View File

@ -27,6 +27,7 @@
#include <linux/module.h>
#include <linux/irqdomain.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm.h>
#include <asm/mach/irq.h>
@ -64,7 +65,7 @@ struct tegra_gpio_bank {
int bank;
int irq;
spinlock_t lvl_lock[4];
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
u32 cnf[4];
u32 out[4];
u32 oe[4];
@ -109,20 +110,18 @@ static void tegra_gpio_enable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
}
EXPORT_SYMBOL_GPL(tegra_gpio_enable);
static void tegra_gpio_disable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
}
EXPORT_SYMBOL_GPL(tegra_gpio_disable);
int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
{
return pinctrl_request_gpio(offset);
}
void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
{
pinctrl_free_gpio(offset);
tegra_gpio_disable(offset);
@ -135,6 +134,11 @@ static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
{
/* If gpio is in output mode then read from the out value */
if ((tegra_gpio_readl(GPIO_OE(offset)) >> GPIO_BIT(offset)) & 1)
return (tegra_gpio_readl(GPIO_OUT(offset)) >>
GPIO_BIT(offset)) & 0x1;
return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1;
}
@ -285,8 +289,8 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
#ifdef CONFIG_PM
void tegra_gpio_resume(void)
#ifdef CONFIG_PM_SLEEP
static int tegra_gpio_resume(struct device *dev)
{
unsigned long flags;
int b;
@ -308,9 +312,10 @@ void tegra_gpio_resume(void)
}
local_irq_restore(flags);
return 0;
}
void tegra_gpio_suspend(void)
static int tegra_gpio_suspend(struct device *dev)
{
unsigned long flags;
int b;
@ -330,6 +335,7 @@ void tegra_gpio_suspend(void)
}
}
local_irq_restore(flags);
return 0;
}
static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable)
@ -345,11 +351,15 @@ static struct irq_chip tegra_gpio_irq_chip = {
.irq_mask = tegra_gpio_irq_mask,
.irq_unmask = tegra_gpio_irq_unmask,
.irq_set_type = tegra_gpio_irq_set_type,
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
.irq_set_wake = tegra_gpio_wake_enable,
#endif
};
static const struct dev_pm_ops tegra_gpio_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
};
struct tegra_gpio_soc_config {
u32 bank_stride;
u32 upper_offset;
@ -380,7 +390,6 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct tegra_gpio_soc_config *config;
int irq_base;
struct resource *res;
struct tegra_gpio_bank *bank;
int gpio;
@ -417,14 +426,11 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0);
if (irq_base < 0) {
dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n");
return -ENODEV;
}
irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
tegra_gpio_chip.ngpio, irq_base, 0,
irq_domain = irq_domain_add_linear(pdev->dev.of_node,
tegra_gpio_chip.ngpio,
&irq_domain_simple_ops, NULL);
if (!irq_domain)
return -ENODEV;
for (i = 0; i < tegra_gpio_bank_count; i++) {
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
@ -464,7 +470,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
gpiochip_add(&tegra_gpio_chip);
for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) {
int irq = irq_find_mapping(irq_domain, gpio);
int irq = irq_create_mapping(irq_domain, gpio);
/* No validity check; all Tegra GPIOs are valid IRQs */
bank = &tegra_gpio_banks[GPIO_BANK(gpio)];
@ -493,6 +499,7 @@ static struct platform_driver tegra_gpio_driver = {
.driver = {
.name = "tegra-gpio",
.owner = THIS_MODULE,
.pm = &tegra_gpio_pm_ops,
.of_match_table = tegra_gpio_of_match,
},
.probe = tegra_gpio_probe,

View File

@ -88,11 +88,15 @@ static inline int gpio_twl4030_write(u8 address, u8 data)
/*----------------------------------------------------------------------*/
/*
* LED register offsets (use TWL4030_MODULE_{LED,PWMA,PWMB}))
* LED register offsets from TWL_MODULE_LED base
* PWMs A and B are dedicated to LEDs A and B, respectively.
*/
#define TWL4030_LED_LEDEN 0x0
#define TWL4030_LED_LEDEN_REG 0x00
#define TWL4030_PWMAON_REG 0x01
#define TWL4030_PWMAOFF_REG 0x02
#define TWL4030_PWMBON_REG 0x03
#define TWL4030_PWMBOFF_REG 0x04
/* LEDEN bits */
#define LEDEN_LEDAON BIT(0)
@ -104,9 +108,6 @@ static inline int gpio_twl4030_write(u8 address, u8 data)
#define LEDEN_PWM_LENGTHA BIT(6)
#define LEDEN_PWM_LENGTHB BIT(7)
#define TWL4030_PWMx_PWMxON 0x0
#define TWL4030_PWMx_PWMxOFF 0x1
#define PWMxON_LENGTH BIT(7)
/*----------------------------------------------------------------------*/
@ -145,7 +146,7 @@ static void twl4030_led_set_value(int led, int value)
else
cached_leden |= mask;
status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
TWL4030_LED_LEDEN);
TWL4030_LED_LEDEN_REG);
mutex_unlock(&gpio_lock);
}
@ -216,33 +217,33 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
if (offset >= TWL4030_GPIO_MAX) {
u8 ledclr_mask = LEDEN_LEDAON | LEDEN_LEDAEXT
| LEDEN_LEDAPWM | LEDEN_PWM_LENGTHA;
u8 module = TWL4030_MODULE_PWMA;
u8 reg = TWL4030_PWMAON_REG;
offset -= TWL4030_GPIO_MAX;
if (offset) {
ledclr_mask <<= 1;
module = TWL4030_MODULE_PWMB;
reg = TWL4030_PWMBON_REG;
}
/* initialize PWM to always-drive */
status = twl_i2c_write_u8(module, 0x7f,
TWL4030_PWMx_PWMxOFF);
/* Configure PWM OFF register first */
status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg + 1);
if (status < 0)
goto done;
status = twl_i2c_write_u8(module, 0x7f,
TWL4030_PWMx_PWMxON);
/* Followed by PWM ON register */
status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg);
if (status < 0)
goto done;
/* init LED to not-driven (high) */
module = TWL4030_MODULE_LED;
status = twl_i2c_read_u8(module, &cached_leden,
TWL4030_LED_LEDEN);
status = twl_i2c_read_u8(TWL4030_MODULE_LED, &cached_leden,
TWL4030_LED_LEDEN_REG);
if (status < 0)
goto done;
cached_leden &= ~ledclr_mask;
status = twl_i2c_write_u8(module, cached_leden,
TWL4030_LED_LEDEN);
status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
TWL4030_LED_LEDEN_REG);
if (status < 0)
goto done;

View File

@ -96,6 +96,7 @@ static struct vt8500_gpio_data wm8505_data = {
VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
},
};
@ -115,6 +116,7 @@ static struct vt8500_gpio_data wm8650_data = {
VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
},
};

View File

@ -191,6 +191,32 @@ err:
return ret;
}
/* caller ensures gpio is valid and requested, chip->get_direction may sleep */
static int gpio_get_direction(unsigned gpio)
{
struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
chip = gpio_to_chip(gpio);
gpio -= chip->base;
if (!chip->get_direction)
return status;
status = chip->get_direction(chip, gpio);
if (status > 0) {
/* GPIOF_DIR_IN, or other positive */
status = 1;
clear_bit(FLAG_IS_OUT, &desc->flags);
}
if (status == 0) {
/* GPIOF_DIR_OUT */
set_bit(FLAG_IS_OUT, &desc->flags);
}
return status;
}
#ifdef CONFIG_GPIO_SYSFS
/* lock protects against unexport_gpio() being called while
@ -223,6 +249,7 @@ static ssize_t gpio_direction_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status;
mutex_lock(&sysfs_lock);
@ -230,6 +257,7 @@ static ssize_t gpio_direction_show(struct device *dev,
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else
gpio_get_direction(gpio);
status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in");
@ -704,8 +732,9 @@ int gpio_export(unsigned gpio, bool direction_may_change)
{
unsigned long flags;
struct gpio_desc *desc;
int status = -EINVAL;
int status;
const char *ioname = NULL;
struct device *dev;
/* can't export until sysfs is available ... */
if (!gpio_class.p) {
@ -713,59 +742,66 @@ int gpio_export(unsigned gpio, bool direction_may_change)
return -ENOENT;
}
if (!gpio_is_valid(gpio))
goto done;
if (!gpio_is_valid(gpio)) {
pr_debug("%s: gpio %d is not valid\n", __func__, gpio);
return -EINVAL;
}
mutex_lock(&sysfs_lock);
spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio];
if (test_bit(FLAG_REQUESTED, &desc->flags)
&& !test_bit(FLAG_EXPORT, &desc->flags)) {
status = 0;
if (!desc->chip->direction_input
|| !desc->chip->direction_output)
direction_may_change = false;
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__, gpio,
test_bit(FLAG_REQUESTED, &desc->flags),
test_bit(FLAG_EXPORT, &desc->flags));
status = -EPERM;
goto fail_unlock;
}
if (!desc->chip->direction_input || !desc->chip->direction_output)
direction_may_change = false;
spin_unlock_irqrestore(&gpio_lock, flags);
if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
ioname = desc->chip->names[gpio - desc->chip->base];
if (status == 0) {
struct device *dev;
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
desc, ioname ? ioname : "gpio%u", gpio);
if (!IS_ERR(dev)) {
status = sysfs_create_group(&dev->kobj,
&gpio_attr_group);
if (!status && direction_may_change)
status = device_create_file(dev,
&dev_attr_direction);
if (!status && gpio_to_irq(gpio) >= 0
&& (direction_may_change
|| !test_bit(FLAG_IS_OUT,
&desc->flags)))
status = device_create_file(dev,
&dev_attr_edge);
if (status != 0)
device_unregister(dev);
} else
status = PTR_ERR(dev);
if (status == 0)
set_bit(FLAG_EXPORT, &desc->flags);
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
desc, ioname ? ioname : "gpio%u", gpio);
if (IS_ERR(dev)) {
status = PTR_ERR(dev);
goto fail_unlock;
}
mutex_unlock(&sysfs_lock);
done:
status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
if (status)
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
goto fail_unregister_device;
if (direction_may_change) {
status = device_create_file(dev, &dev_attr_direction);
if (status)
goto fail_unregister_device;
}
if (gpio_to_irq(gpio) >= 0 && (direction_may_change ||
!test_bit(FLAG_IS_OUT, &desc->flags))) {
status = device_create_file(dev, &dev_attr_edge);
if (status)
goto fail_unregister_device;
}
set_bit(FLAG_EXPORT, &desc->flags);
mutex_unlock(&sysfs_lock);
return 0;
fail_unregister_device:
device_unregister(dev);
fail_unlock:
mutex_unlock(&sysfs_lock);
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
return status;
}
EXPORT_SYMBOL_GPL(gpio_export);
@ -1075,6 +1111,7 @@ int gpiochip_add(struct gpio_chip *chip)
* inputs (often with pullups enabled) so power
* usage is minimized. Linux code should set the
* gpio direction first thing; but until it does,
* and in case chip->get_direction is not set,
* we may expose the wrong direction in sysfs.
*/
gpio_desc[id].flags = !chip->direction_input
@ -1274,9 +1311,15 @@ int gpio_request(unsigned gpio, const char *label)
desc_set_label(desc, NULL);
module_put(chip->owner);
clear_bit(FLAG_REQUESTED, &desc->flags);
goto done;
}
}
if (chip->get_direction) {
/* chip->get_direction may sleep */
spin_unlock_irqrestore(&gpio_lock, flags);
gpio_get_direction(gpio);
spin_lock_irqsave(&gpio_lock, flags);
}
done:
if (status)
pr_debug("gpio_request: gpio-%d (%s) status %d\n",
@ -1812,6 +1855,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
continue;
gpio_get_direction(gpio);
is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
gpio, gdesc->label,

View File

@ -57,6 +57,8 @@ struct device_node;
* enabling module power and clock; may sleep
* @free: optional hook for chip-specific deactivation, such as
* disabling module power and clock; may sleep
* @get_direction: returns direction for signal "offset", 0=out, 1=in,
* (same as GPIOF_DIR_XXX), or negative error
* @direction_input: configures signal "offset" as input, or returns error
* @get: returns value for signal "offset"; for output signals this
* returns either the value actually sensed, or zero
@ -101,7 +103,8 @@ struct gpio_chip {
unsigned offset);
void (*free)(struct gpio_chip *chip,
unsigned offset);
int (*get_direction)(struct gpio_chip *chip,
unsigned offset);
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*get)(struct gpio_chip *chip,