mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 13:41:55 +00:00
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:
commit
53d74fd79d
50
Documentation/devicetree/bindings/gpio/spear_spics.txt
Normal file
50
Documentation/devicetree/bindings/gpio/spear_spics.txt
Normal 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>;
|
||||
...
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
199
drivers/gpio/gpio-clps711x.c
Normal file
199
drivers/gpio/gpio-clps711x.c
Normal 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
204
drivers/gpio/gpio-da9055.c
Normal 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");
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
217
drivers/gpio/gpio-spear-spics.c
Normal file
217
drivers/gpio/gpio-spear-spics.c
Normal 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");
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user