This is the bulk of GPIO changes for the v3.17 development
cycle, and this time we got a lot of action going on and it will continue: - The core GPIO library implementation has been split up in three different files: - gpiolib.c for the latest and greatest and shiny GPIO library code using GPIO descriptors only - gpiolib-legacy.c for the old integer number space API that we are phasing out gradually - gpiolib-sysfs.c for the sysfs interface that we are not entirely happy with, but has to live on for ABI compatibility - Add a flags argument to *gpiod_get* functions, with some backward-compatibility macros to ease transitions. We should have had the flags there from the beginning it seems, now we need to clean up the mess. There is a plan on how to move forward here devised by Alexandre Courbot and Mark Brown. - Split off a special <linux/gpio/machine.h> header for the board gpio table registration, as per example from the regulator subsystem. - Start to kill off the return value from gpiochip_remove() by removing the __must_check attribute and removing all checks inside the drivers/gpio directory. The rationale is: well what were we supposed to do if there is an error code? Not much: print an error message. And gpiolib already does that. So make this function return void eventually. - Some cleanups of hairy gpiolib code, make some functions not to be used outside the library private and make sure they are not exported, remove gpiod_lock/unlock_as_irq() as the existing function is for driver-internal use and fine as it is, delete gpio_ensure_requested() as it is not meaningful anymore. - Support the GPIOF_ACTIVE_LOW flag from gpio_request_one() function calls, which is logical since this is already supported when referencing GPIOs from e.g. device trees. - Switch STMPE, intel-mid, lynxpoint and ACPI (!) to use the gpiolib irqchip helpers cutting down on GPIO irqchip boilerplate a bit more. - New driver for the Zynq GPIO block. - The usual incremental improvements around a bunch of drivers. - Janitorial syntactic and semantic cleanups by Jingoo Han, and Rickard Strandqvist especially. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJT5Ji9AAoJEEEQszewGV1zch8QAKp67+8ScxRBf/7RCSV6U/dy i7kt+nP4au/TScwtjbX264DM8hroW7BzN+GqF10NEFeGkYDR+42lMav9PrNjtKtk ojQPWdoGWzwwL0wa4j9rsuG/pRnbAEgDWPb+EkFdHQsLl6h71fyVoLOK+gKwJFyn aPYGXyNbT1FN38oj1rarENiOUxM7VMXvcJFfvDYFdDDhCS4PLYPOMw0lrsGtsHMZ epDa4z3yt4zHgYiUIT578nQ7EkIbGN3goywk3NQ+9WDQG+sLFHh4BdqcRKg6b9VM I64+47uNQxkyvWCvcLma5ziqvtNQk113986g+cv5YeTh18Ajyio1kxEIZM181eBk ITUPGrAorWHPLGNbe3psLmtK3+/BwmWIurPmHpckuW8d2JWWSVe0oepkUuqDwu/w lUB5KtM0joFOr5k61fj5tCKxH344jc1zvHJ/N+bVYilbOMvunWzuMJlc4hADIGC2 1uxUAcPbYUAphGaxhdMBca9ellm0lWG19Gj5TtdGbRtNgp6R2qrwI66DDzk+1kLR 8Szx6KHQdEHFTlCLKSIAMv33p1ClfmNikhdicT3urwR8PeXmmTR1pD7kGmVTDDZa gXSU5EilgGpak+77j/GZ2Ivp0Qt5M97UwWlZ7zTp++T1ZY+wwTHJI/09qcoWYjdz IpZRIqrQchalbscpn3LY =e+d6 -----END PGP SIGNATURE----- Merge tag 'gpio-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO update from Linus Walleij: "This is the bulk of GPIO changes for the v3.17 development cycle, and this time we got a lot of action going on and it will continue: - The core GPIO library implementation has been split up in three different files: - gpiolib.c for the latest and greatest and shiny GPIO library code using GPIO descriptors only - gpiolib-legacy.c for the old integer number space API that we are phasing out gradually - gpiolib-sysfs.c for the sysfs interface that we are not entirely happy with, but has to live on for ABI compatibility - Add a flags argument to *gpiod_get* functions, with some backward-compatibility macros to ease transitions. We should have had the flags there from the beginning it seems, now we need to clean up the mess. There is a plan on how to move forward here devised by Alexandre Courbot and Mark Brown - Split off a special <linux/gpio/machine.h> header for the board gpio table registration, as per example from the regulator subsystem - Start to kill off the return value from gpiochip_remove() by removing the __must_check attribute and removing all checks inside the drivers/gpio directory. The rationale is: well what were we supposed to do if there is an error code? Not much: print an error message. And gpiolib already does that. So make this function return void eventually - Some cleanups of hairy gpiolib code, make some functions not to be used outside the library private and make sure they are not exported, remove gpiod_lock/unlock_as_irq() as the existing function is for driver-internal use and fine as it is, delete gpio_ensure_requested() as it is not meaningful anymore - Support the GPIOF_ACTIVE_LOW flag from gpio_request_one() function calls, which is logical since this is already supported when referencing GPIOs from e.g. device trees - Switch STMPE, intel-mid, lynxpoint and ACPI (!) to use the gpiolib irqchip helpers cutting down on GPIO irqchip boilerplate a bit more - New driver for the Zynq GPIO block - The usual incremental improvements around a bunch of drivers - Janitorial syntactic and semantic cleanups by Jingoo Han, and Rickard Strandqvist especially" * tag 'gpio-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (37 commits) MAINTAINERS: update GPIO include files gpio: add missing includes in machine.h gpio: add flags argument to gpiod_get*() functions MAINTAINERS: Update Samsung pin control entry gpio / ACPI: Move event handling registration to gpiolib irqchip helpers gpio: lynxpoint: Convert to use gpiolib irqchip gpio: split gpiod board registration into machine header gpio: remove gpio_ensure_requested() gpio: remove useless check in gpiolib_sysfs_init() gpiolib: Export gpiochip_request_own_desc and gpiochip_free_own_desc gpio: move gpio_ensure_requested() into legacy C file gpio: remove gpiod_lock/unlock_as_irq() gpio: make gpiochip_get_desc() gpiolib-private gpio: simplify gpiochip_export() gpio: remove export of private of_get_named_gpio_flags() gpio: Add support for GPIOF_ACTIVE_LOW to gpio_request_one functions gpio: zynq: Clear pending interrupt when enabling a IRQ gpio: drop retval check enforcing from gpiochip_remove() gpio: remove all usage of gpio_remove retval in driver/gpio devicetree: Add Zynq GPIO devicetree bindings documentation ...
This commit is contained in:
commit
06b49ea43c
84 changed files with 2413 additions and 1931 deletions
26
Documentation/devicetree/bindings/gpio/gpio-zynq.txt
Normal file
26
Documentation/devicetree/bindings/gpio/gpio-zynq.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
Xilinx Zynq GPIO controller Device Tree Bindings
|
||||
-------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- #gpio-cells : Should be two
|
||||
- First cell is the GPIO line number
|
||||
- Second cell is used to specify optional
|
||||
parameters (unused)
|
||||
- compatible : Should be "xlnx,zynq-gpio-1.0"
|
||||
- clocks : Clock specifier (see clock bindings for details)
|
||||
- gpio-controller : Marks the device node as a GPIO controller.
|
||||
- interrupts : Interrupt specifier (see interrupt bindings for
|
||||
details)
|
||||
- interrupt-parent : Must be core interrupt controller
|
||||
- reg : Address and length of the register set for the device
|
||||
|
||||
Example:
|
||||
gpio@e000a000 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "xlnx,zynq-gpio-1.0";
|
||||
clocks = <&clkc 42>;
|
||||
gpio-controller;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 20 4>;
|
||||
reg = <0xe000a000 0x1000>;
|
||||
};
|
|
@ -60,7 +60,7 @@ Platform Data
|
|||
Finally, GPIOs can be bound to devices and functions using platform data. Board
|
||||
files that desire to do so need to include the following header:
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
GPIOs are mapped by the means of tables of lookups, containing instances of the
|
||||
gpiod_lookup structure. Two macros are defined to help declaring such mappings:
|
||||
|
|
|
@ -29,13 +29,24 @@ gpiod_get() functions. Like many other kernel subsystems, gpiod_get() takes the
|
|||
device that will use the GPIO and the function the requested GPIO is supposed to
|
||||
fulfill:
|
||||
|
||||
struct gpio_desc *gpiod_get(struct device *dev, const char *con_id)
|
||||
struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
|
||||
If a function is implemented by using several GPIOs together (e.g. a simple LED
|
||||
device that displays digits), an additional index argument can be specified:
|
||||
|
||||
struct gpio_desc *gpiod_get_index(struct device *dev,
|
||||
const char *con_id, unsigned int idx)
|
||||
const char *con_id, unsigned int idx,
|
||||
enum gpiod_flags flags)
|
||||
|
||||
The flags parameter is used to optionally specify a direction and initial value
|
||||
for the GPIO. Values can be:
|
||||
|
||||
* GPIOD_ASIS or 0 to not initialize the GPIO at all. The direction must be set
|
||||
later with one of the dedicated functions.
|
||||
* GPIOD_IN to initialize the GPIO as input.
|
||||
* GPIOD_OUT_LOW to initialize the GPIO as output with a value of 0.
|
||||
* GPIOD_OUT_HIGH to initialize the GPIO as output with a value of 1.
|
||||
|
||||
Both functions return either a valid GPIO descriptor, or an error code checkable
|
||||
with IS_ERR() (they will never return a NULL pointer). -ENOENT will be returned
|
||||
|
@ -46,11 +57,13 @@ errors and an absence of GPIO for optional GPIO parameters.
|
|||
|
||||
Device-managed variants of these functions are also defined:
|
||||
|
||||
struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id)
|
||||
struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
|
||||
struct gpio_desc *devm_gpiod_get_index(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx)
|
||||
unsigned int idx,
|
||||
enum gpiod_flags flags)
|
||||
|
||||
A GPIO descriptor can be disposed of using the gpiod_put() function:
|
||||
|
||||
|
@ -67,8 +80,9 @@ Using GPIOs
|
|||
|
||||
Setting Direction
|
||||
-----------------
|
||||
The first thing a driver must do with a GPIO is setting its direction. This is
|
||||
done by invoking one of the gpiod_direction_*() functions:
|
||||
The first thing a driver must do with a GPIO is setting its direction. If no
|
||||
direction-setting flags have been given to gpiod_get*(), this is done by
|
||||
invoking one of the gpiod_direction_*() functions:
|
||||
|
||||
int gpiod_direction_input(struct gpio_desc *desc)
|
||||
int gpiod_direction_output(struct gpio_desc *desc, int value)
|
||||
|
|
|
@ -157,13 +157,34 @@ Locking IRQ usage
|
|||
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
|
||||
to mark the GPIO as being used as an IRQ:
|
||||
|
||||
int gpiod_lock_as_irq(struct gpio_desc *desc)
|
||||
int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
|
||||
This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock
|
||||
is released:
|
||||
|
||||
void gpiod_unlock_as_irq(struct gpio_desc *desc)
|
||||
void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
|
||||
When implementing an irqchip inside a GPIO driver, these two functions should
|
||||
typically be called in the .startup() and .shutdown() callbacks from the
|
||||
irqchip.
|
||||
|
||||
|
||||
Requesting self-owned GPIO pins
|
||||
-------------------------------
|
||||
|
||||
Sometimes it is useful to allow a GPIO chip driver to request its own GPIO
|
||||
descriptors through the gpiolib API. Using gpio_request() for this purpose
|
||||
does not help since it pins the module to the kernel forever (it calls
|
||||
try_module_get()). A GPIO driver can use the following functions instead
|
||||
to request and free descriptors without being pinned to the kernel forever.
|
||||
|
||||
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
|
||||
|
||||
void gpiochip_free_own_desc(struct gpio_desc *desc)
|
||||
|
||||
Descriptors requested with gpiochip_request_own_desc() must be released with
|
||||
gpiochip_free_own_desc().
|
||||
|
||||
These functions must be used with care since they do not affect module use
|
||||
count. Do not use the functions to request gpio descriptors not owned by the
|
||||
calling driver.
|
||||
|
|
|
@ -4031,7 +4031,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
|
|||
S: Maintained
|
||||
F: Documentation/gpio/
|
||||
F: drivers/gpio/
|
||||
F: include/linux/gpio*
|
||||
F: include/linux/gpio/
|
||||
F: include/linux/gpio.h
|
||||
F: include/asm-generic/gpio.h
|
||||
|
||||
GRE DEMULTIPLEXER DRIVER
|
||||
|
@ -7002,9 +7003,7 @@ M: Thomas Abraham <thomas.abraham@linaro.org>
|
|||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: drivers/pinctrl/pinctrl-exynos.*
|
||||
F: drivers/pinctrl/pinctrl-s3c*
|
||||
F: drivers/pinctrl/pinctrl-samsung.*
|
||||
F: drivers/pinctrl/samsung/
|
||||
|
||||
PIN CONTROLLER - ST SPEAR
|
||||
M: Viresh Kumar <viresh.linux@gmail.com>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rfkill-gpio.h>
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
|
|
|
@ -340,6 +340,13 @@ config GPIO_XILINX
|
|||
help
|
||||
Say yes here to support the Xilinx FPGA GPIO device
|
||||
|
||||
config GPIO_ZYNQ
|
||||
tristate "Xilinx Zynq GPIO support"
|
||||
depends on ARCH_ZYNQ
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support Xilinx Zynq GPIO controller.
|
||||
|
||||
config GPIO_XTENSA
|
||||
bool "Xtensa GPIO32 support"
|
||||
depends on XTENSA
|
||||
|
@ -423,7 +430,7 @@ config GPIO_GE_FPGA
|
|||
config GPIO_LYNXPOINT
|
||||
tristate "Intel Lynxpoint GPIO support"
|
||||
depends on ACPI && X86
|
||||
select IRQ_DOMAIN
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
driver for GPIO functionality on Intel Lynxpoint PCH chipset
|
||||
Requires ACPI device enumeration code to set up a platform device.
|
||||
|
@ -586,6 +593,7 @@ config GPIO_SX150X
|
|||
config GPIO_STMPE
|
||||
bool "STMPE GPIOs"
|
||||
depends on MFD_STMPE
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
This enables support for the GPIOs found on the STMPE I/O
|
||||
Expanders.
|
||||
|
|
|
@ -4,7 +4,9 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
|
|||
|
||||
obj-$(CONFIG_GPIO_DEVRES) += devres.o
|
||||
obj-$(CONFIG_GPIOLIB) += gpiolib.o
|
||||
obj-$(CONFIG_GPIOLIB) += gpiolib-legacy.o
|
||||
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
|
||||
obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
|
||||
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
||||
|
||||
# Device drivers. Generally keep list sorted alphabetically
|
||||
|
@ -102,3 +104,4 @@ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
|
|||
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
|
||||
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
|
||||
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
|
||||
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
|
||||
|
|
|
@ -39,47 +39,53 @@ static int devm_gpiod_match(struct device *dev, void *res, void *data)
|
|||
* devm_gpiod_get - Resource-managed gpiod_get()
|
||||
* @dev: GPIO consumer
|
||||
* @con_id: function within the GPIO consumer
|
||||
* @flags: optional GPIO initialization flags
|
||||
*
|
||||
* Managed gpiod_get(). GPIO descriptors returned from this function are
|
||||
* automatically disposed on driver detach. See gpiod_get() for detailed
|
||||
* information about behavior and return values.
|
||||
*/
|
||||
struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
|
||||
const char *con_id)
|
||||
struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
{
|
||||
return devm_gpiod_get_index(dev, con_id, 0);
|
||||
return devm_gpiod_get_index(dev, con_id, 0, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get);
|
||||
EXPORT_SYMBOL(__devm_gpiod_get);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
|
||||
* @dev: GPIO consumer
|
||||
* @con_id: function within the GPIO consumer
|
||||
* @flags: optional GPIO initialization flags
|
||||
*
|
||||
* Managed gpiod_get_optional(). GPIO descriptors returned from this function
|
||||
* are automatically disposed on driver detach. See gpiod_get_optional() for
|
||||
* detailed information about behavior and return values.
|
||||
*/
|
||||
struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
|
||||
const char *con_id)
|
||||
struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
{
|
||||
return devm_gpiod_get_index_optional(dev, con_id, 0);
|
||||
return devm_gpiod_get_index_optional(dev, con_id, 0, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get_optional);
|
||||
EXPORT_SYMBOL(__devm_gpiod_get_optional);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_index - Resource-managed gpiod_get_index()
|
||||
* @dev: GPIO consumer
|
||||
* @con_id: function within the GPIO consumer
|
||||
* @idx: index of the GPIO to obtain in the consumer
|
||||
* @flags: optional GPIO initialization flags
|
||||
*
|
||||
* Managed gpiod_get_index(). GPIO descriptors returned from this function are
|
||||
* automatically disposed on driver detach. See gpiod_get_index() for detailed
|
||||
* information about behavior and return values.
|
||||
*/
|
||||
struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
|
||||
struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx)
|
||||
unsigned int idx,
|
||||
enum gpiod_flags flags)
|
||||
{
|
||||
struct gpio_desc **dr;
|
||||
struct gpio_desc *desc;
|
||||
|
@ -89,7 +95,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
|
|||
if (!dr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
desc = gpiod_get_index(dev, con_id, idx);
|
||||
desc = gpiod_get_index(dev, con_id, idx, flags);
|
||||
if (IS_ERR(desc)) {
|
||||
devres_free(dr);
|
||||
return desc;
|
||||
|
@ -100,26 +106,28 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
|
|||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get_index);
|
||||
EXPORT_SYMBOL(__devm_gpiod_get_index);
|
||||
|
||||
/**
|
||||
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
|
||||
* @dev: GPIO consumer
|
||||
* @con_id: function within the GPIO consumer
|
||||
* @index: index of the GPIO to obtain in the consumer
|
||||
* @flags: optional GPIO initialization flags
|
||||
*
|
||||
* Managed gpiod_get_index_optional(). GPIO descriptors returned from this
|
||||
* function are automatically disposed on driver detach. See
|
||||
* gpiod_get_index_optional() for detailed information about behavior and
|
||||
* return values.
|
||||
*/
|
||||
struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
|
||||
struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int index)
|
||||
unsigned int index,
|
||||
enum gpiod_flags flags)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = devm_gpiod_get_index(dev, con_id, index);
|
||||
desc = devm_gpiod_get_index(dev, con_id, index, flags);
|
||||
if (IS_ERR(desc)) {
|
||||
if (PTR_ERR(desc) == -ENOENT)
|
||||
return NULL;
|
||||
|
@ -127,7 +135,7 @@ struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
|
|||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_gpiod_get_index_optional);
|
||||
EXPORT_SYMBOL(__devm_gpiod_get_index_optional);
|
||||
|
||||
/**
|
||||
* devm_gpiod_put - Resource-managed gpiod_put()
|
||||
|
|
|
@ -167,13 +167,11 @@ static int gen_74x164_probe(struct spi_device *spi)
|
|||
static int gen_74x164_remove(struct spi_device *spi)
|
||||
{
|
||||
struct gen_74x164_chip *chip = spi_get_drvdata(spi);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&chip->gpio_chip);
|
||||
if (!ret)
|
||||
mutex_destroy(&chip->lock);
|
||||
gpiochip_remove(&chip->gpio_chip);
|
||||
mutex_destroy(&chip->lock);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id gen_74x164_dt_ids[] = {
|
||||
|
|
|
@ -585,15 +585,8 @@ static int adnp_i2c_remove(struct i2c_client *client)
|
|||
{
|
||||
struct adnp *adnp = i2c_get_clientdata(client);
|
||||
struct device_node *np = client->dev.of_node;
|
||||
int err;
|
||||
|
||||
err = gpiochip_remove(&adnp->gpio);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "%s failed: %d\n", "gpiochip_remove()",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
gpiochip_remove(&adnp->gpio);
|
||||
if (of_find_property(np, "interrupt-controller", NULL))
|
||||
adnp_irq_teardown(adnp);
|
||||
|
||||
|
|
|
@ -167,15 +167,9 @@ static int adp5520_gpio_probe(struct platform_device *pdev)
|
|||
static int adp5520_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct adp5520_gpio *dev;
|
||||
int ret;
|
||||
|
||||
dev = platform_get_drvdata(pdev);
|
||||
ret = gpiochip_remove(&dev->gpio_chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s failed, %d\n",
|
||||
"gpiochip_remove()", ret);
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&dev->gpio_chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -470,11 +470,7 @@ static int adp5588_gpio_remove(struct i2c_client *client)
|
|||
if (dev->irq_base)
|
||||
free_irq(dev->client->irq, dev);
|
||||
|
||||
ret = gpiochip_remove(&dev->gpio_chip);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "gpiochip_remove failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&dev->gpio_chip);
|
||||
|
||||
kfree(dev);
|
||||
return 0;
|
||||
|
|
|
@ -232,8 +232,7 @@ static int __init amd_gpio_init(void)
|
|||
|
||||
static void __exit amd_gpio_exit(void)
|
||||
{
|
||||
int err = gpiochip_remove(&gp.chip);
|
||||
WARN_ON(err);
|
||||
gpiochip_remove(&gp.chip);
|
||||
ioport_unmap(gp.pm);
|
||||
release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
|
||||
}
|
||||
|
|
|
@ -149,7 +149,8 @@ static int arizona_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct arizona_gpio *arizona_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&arizona_gpio->gpio_chip);
|
||||
gpiochip_remove(&arizona_gpio->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver arizona_gpio_driver = {
|
||||
|
|
|
@ -358,14 +358,8 @@ static int cs5535_gpio_probe(struct platform_device *pdev)
|
|||
static int cs5535_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r;
|
||||
int err;
|
||||
|
||||
err = gpiochip_remove(&cs5535_gpio_chip.chip);
|
||||
if (err) {
|
||||
/* uhh? */
|
||||
dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
|
||||
return err;
|
||||
}
|
||||
gpiochip_remove(&cs5535_gpio_chip.chip);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
release_region(r->start, resource_size(r));
|
||||
|
|
|
@ -237,7 +237,8 @@ static int da9052_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct da9052_gpio *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&gpio->gp);
|
||||
gpiochip_remove(&gpio->gp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver da9052_gpio_driver = {
|
||||
|
|
|
@ -174,7 +174,8 @@ static int da9055_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct da9055_gpio *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&gpio->gp);
|
||||
gpiochip_remove(&gpio->gp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver da9055_gpio_driver = {
|
||||
|
|
|
@ -359,7 +359,7 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
|
|||
|
||||
for (m = 0; m < gpio->nr_ports; ++m)
|
||||
if (gpio->ports[m].is_registered)
|
||||
WARN_ON(gpiochip_remove(&gpio->ports[m].bgc.gc));
|
||||
gpiochip_remove(&gpio->ports[m].bgc.gc);
|
||||
}
|
||||
|
||||
static int dwapb_gpio_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -409,11 +409,8 @@ static int em_gio_probe(struct platform_device *pdev)
|
|||
static int em_gio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct em_gio_priv *p = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&p->gpio_chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
gpiochip_remove(&p->gpio_chip);
|
||||
|
||||
irq_domain_remove(p->irq_domain);
|
||||
return 0;
|
||||
|
|
|
@ -317,13 +317,7 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
|
|||
err_gpiochip:
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
struct f7188x_gpio_bank *bank = &data->bank[i];
|
||||
int tmp;
|
||||
|
||||
tmp = gpiochip_remove(&bank->chip);
|
||||
if (tmp < 0)
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to remove gpiochip %d: %d\n",
|
||||
i, tmp);
|
||||
gpiochip_remove(&bank->chip);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -331,20 +325,12 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
static int f7188x_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
struct f7188x_gpio_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < data->nr_bank; i++) {
|
||||
struct f7188x_gpio_bank *bank = &data->bank[i];
|
||||
|
||||
err = gpiochip_remove(&bank->chip);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to remove GPIO gpiochip %d: %d\n",
|
||||
i, err);
|
||||
return err;
|
||||
}
|
||||
gpiochip_remove(&bank->chip);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -398,7 +398,8 @@ static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
|
|||
|
||||
int bgpio_remove(struct bgpio_chip *bgc)
|
||||
{
|
||||
return gpiochip_remove(&bgc->gc);
|
||||
gpiochip_remove(&bgc->gc);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bgpio_remove);
|
||||
|
||||
|
|
|
@ -468,9 +468,7 @@ static int grgpio_remove(struct platform_device *ofdev)
|
|||
}
|
||||
}
|
||||
|
||||
ret = gpiochip_remove(&priv->bgc.gc);
|
||||
if (ret)
|
||||
goto out;
|
||||
gpiochip_remove(&priv->bgc.gc);
|
||||
|
||||
if (priv->domain)
|
||||
irq_domain_remove(priv->domain);
|
||||
|
|
|
@ -514,14 +514,7 @@ static int ichx_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
static int ichx_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = gpiochip_remove(&ichx_priv.chip);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "%s failed, %d\n",
|
||||
"gpiochip_remove()", err);
|
||||
return err;
|
||||
}
|
||||
gpiochip_remove(&ichx_priv.chip);
|
||||
|
||||
ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio);
|
||||
if (ichx_priv.pm_base)
|
||||
|
|
|
@ -28,12 +28,10 @@
|
|||
#include <linux/stddef.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/irqdomain.h>
|
||||
|
||||
#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0)
|
||||
#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1)
|
||||
|
@ -78,10 +76,12 @@ struct intel_mid_gpio {
|
|||
void __iomem *reg_base;
|
||||
spinlock_t lock;
|
||||
struct pci_dev *pdev;
|
||||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
#define to_intel_gpio_priv(chip) container_of(chip, struct intel_mid_gpio, chip)
|
||||
static inline struct intel_mid_gpio *to_intel_gpio_priv(struct gpio_chip *gc)
|
||||
{
|
||||
return container_of(gc, struct intel_mid_gpio, chip);
|
||||
}
|
||||
|
||||
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
|
||||
enum GPIO_REG reg_type)
|
||||
|
@ -182,15 +182,10 @@ static int intel_gpio_direction_output(struct gpio_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int intel_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
|
||||
return irq_create_mapping(priv->domain, offset);
|
||||
}
|
||||
|
||||
static int intel_mid_irq_type(struct irq_data *d, unsigned type)
|
||||
{
|
||||
struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct intel_mid_gpio *priv = to_intel_gpio_priv(gc);
|
||||
u32 gpio = irqd_to_hwirq(d);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
@ -231,33 +226,11 @@ static void intel_mid_irq_mask(struct irq_data *d)
|
|||
{
|
||||
}
|
||||
|
||||
static int intel_mid_irq_reqres(struct irq_data *d)
|
||||
{
|
||||
struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||
|
||||
if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) {
|
||||
dev_err(priv->chip.dev,
|
||||
"unable to lock HW IRQ %lu for IRQ\n",
|
||||
irqd_to_hwirq(d));
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_mid_irq_relres(struct irq_data *d)
|
||||
{
|
||||
struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||
|
||||
gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static struct irq_chip intel_mid_irqchip = {
|
||||
.name = "INTEL_MID-GPIO",
|
||||
.irq_mask = intel_mid_irq_mask,
|
||||
.irq_unmask = intel_mid_irq_unmask,
|
||||
.irq_set_type = intel_mid_irq_type,
|
||||
.irq_request_resources = intel_mid_irq_reqres,
|
||||
.irq_release_resources = intel_mid_irq_relres,
|
||||
};
|
||||
|
||||
static const struct intel_mid_gpio_ddata gpio_lincroft = {
|
||||
|
@ -330,8 +303,9 @@ MODULE_DEVICE_TABLE(pci, intel_gpio_ids);
|
|||
|
||||
static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct intel_mid_gpio *priv = to_intel_gpio_priv(gc);
|
||||
struct irq_data *data = irq_desc_get_irq_data(desc);
|
||||
struct intel_mid_gpio *priv = irq_data_get_irq_handler_data(data);
|
||||
struct irq_chip *chip = irq_data_get_irq_chip(data);
|
||||
u32 base, gpio, mask;
|
||||
unsigned long pending;
|
||||
|
@ -345,7 +319,7 @@ static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc)
|
|||
mask = BIT(gpio);
|
||||
/* Clear before handling so we can't lose an edge */
|
||||
writel(mask, gedr);
|
||||
generic_handle_irq(irq_find_mapping(priv->domain,
|
||||
generic_handle_irq(irq_find_mapping(gc->irqdomain,
|
||||
base + gpio));
|
||||
}
|
||||
}
|
||||
|
@ -371,23 +345,6 @@ static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv)
|
|||
}
|
||||
}
|
||||
|
||||
static int intel_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct intel_mid_gpio *priv = d->host_data;
|
||||
|
||||
irq_set_chip_and_handler(irq, &intel_mid_irqchip, handle_simple_irq);
|
||||
irq_set_chip_data(irq, priv);
|
||||
irq_set_irq_type(irq, IRQ_TYPE_NONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops intel_gpio_irq_ops = {
|
||||
.map = intel_gpio_irq_map,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int intel_gpio_runtime_idle(struct device *dev)
|
||||
{
|
||||
int err = pm_schedule_suspend(dev, 500);
|
||||
|
@ -441,7 +398,6 @@ static int intel_gpio_probe(struct pci_dev *pdev,
|
|||
priv->chip.direction_output = intel_gpio_direction_output;
|
||||
priv->chip.get = intel_gpio_get;
|
||||
priv->chip.set = intel_gpio_set;
|
||||
priv->chip.to_irq = intel_gpio_to_irq;
|
||||
priv->chip.base = gpio_base;
|
||||
priv->chip.ngpio = ddata->ngpio;
|
||||
priv->chip.can_sleep = false;
|
||||
|
@ -449,11 +405,6 @@ static int intel_gpio_probe(struct pci_dev *pdev,
|
|||
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
priv->domain = irq_domain_add_simple(pdev->dev.of_node, ddata->ngpio,
|
||||
irq_base, &intel_gpio_irq_ops, priv);
|
||||
if (!priv->domain)
|
||||
return -ENOMEM;
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
retval = gpiochip_add(&priv->chip);
|
||||
if (retval) {
|
||||
|
@ -461,10 +412,23 @@ static int intel_gpio_probe(struct pci_dev *pdev,
|
|||
return retval;
|
||||
}
|
||||
|
||||
retval = gpiochip_irqchip_add(&priv->chip,
|
||||
&intel_mid_irqchip,
|
||||
irq_base,
|
||||
handle_simple_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev,
|
||||
"could not connect irqchip to gpiochip\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
intel_mid_irq_init_hw(priv);
|
||||
|
||||
irq_set_handler_data(pdev->irq, priv);
|
||||
irq_set_chained_handler(pdev->irq, intel_mid_irq_handler);
|
||||
gpiochip_set_chained_irqchip(&priv->chip,
|
||||
&intel_mid_irqchip,
|
||||
pdev->irq,
|
||||
intel_mid_irq_handler);
|
||||
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
|
|
|
@ -217,11 +217,7 @@ static int __init it8761e_gpio_init(void)
|
|||
static void __exit it8761e_gpio_exit(void)
|
||||
{
|
||||
if (gpio_ba) {
|
||||
int ret = gpiochip_remove(&it8761e_gpio_chip);
|
||||
|
||||
WARN(ret, "%s(): gpiochip_remove() failed, ret=%d\n",
|
||||
__func__, ret);
|
||||
|
||||
gpiochip_remove(&it8761e_gpio_chip);
|
||||
release_region(gpio_ba, GPIO_IOSIZE);
|
||||
gpio_ba = 0;
|
||||
}
|
||||
|
|
|
@ -194,14 +194,8 @@ static int ttl_probe(struct platform_device *pdev)
|
|||
static int ttl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ttl_module *mod = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&mod->gpio);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to remove GPIO chip\n");
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&mod->gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -199,7 +199,8 @@ static int kempld_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct kempld_gpio_data *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&gpio->chip);
|
||||
gpiochip_remove(&gpio->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver kempld_gpio_driver = {
|
||||
|
|
|
@ -216,7 +216,8 @@ static int lp3943_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct lp3943_gpio *lp3943_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&lp3943_gpio->chip);
|
||||
gpiochip_remove(&lp3943_gpio->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id lp3943_gpio_of_match[] = {
|
||||
|
|
|
@ -560,7 +560,7 @@ static int lpc32xx_gpio_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id lpc32xx_gpio_of_match[] = {
|
||||
static const struct of_device_id lpc32xx_gpio_of_match[] = {
|
||||
{ .compatible = "nxp,lpc3220-gpio", },
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -25,9 +25,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -62,7 +60,6 @@
|
|||
|
||||
struct lp_gpio {
|
||||
struct gpio_chip chip;
|
||||
struct irq_domain *domain;
|
||||
struct platform_device *pdev;
|
||||
spinlock_t lock;
|
||||
unsigned long reg_base;
|
||||
|
@ -151,7 +148,8 @@ static void lp_gpio_free(struct gpio_chip *chip, unsigned offset)
|
|||
|
||||
static int lp_irq_type(struct irq_data *d, unsigned type)
|
||||
{
|
||||
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
|
||||
u32 hwirq = irqd_to_hwirq(d);
|
||||
unsigned long flags;
|
||||
u32 value;
|
||||
|
@ -236,16 +234,11 @@ static int lp_gpio_direction_output(struct gpio_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
|
||||
return irq_create_mapping(lg->domain, offset);
|
||||
}
|
||||
|
||||
static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc)
|
||||
{
|
||||
struct irq_data *data = irq_desc_get_irq_data(desc);
|
||||
struct lp_gpio *lg = irq_data_get_irq_handler_data(data);
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
|
||||
struct irq_chip *chip = irq_data_get_irq_chip(data);
|
||||
u32 base, pin, mask;
|
||||
unsigned long reg, ena, pending;
|
||||
|
@ -262,7 +255,7 @@ static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc)
|
|||
mask = BIT(pin);
|
||||
/* Clear before handling so we don't lose an edge */
|
||||
outl(mask, reg);
|
||||
irq = irq_find_mapping(lg->domain, base + pin);
|
||||
irq = irq_find_mapping(lg->chip.irqdomain, base + pin);
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +272,8 @@ static void lp_irq_mask(struct irq_data *d)
|
|||
|
||||
static void lp_irq_enable(struct irq_data *d)
|
||||
{
|
||||
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
|
||||
u32 hwirq = irqd_to_hwirq(d);
|
||||
unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
|
||||
unsigned long flags;
|
||||
|
@ -291,7 +285,8 @@ static void lp_irq_enable(struct irq_data *d)
|
|||
|
||||
static void lp_irq_disable(struct irq_data *d)
|
||||
{
|
||||
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct lp_gpio *lg = container_of(gc, struct lp_gpio, chip);
|
||||
u32 hwirq = irqd_to_hwirq(d);
|
||||
unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
|
||||
unsigned long flags;
|
||||
|
@ -301,26 +296,6 @@ static void lp_irq_disable(struct irq_data *d)
|
|||
spin_unlock_irqrestore(&lg->lock, flags);
|
||||
}
|
||||
|
||||
static int lp_irq_reqres(struct irq_data *d)
|
||||
{
|
||||
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
|
||||
|
||||
if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) {
|
||||
dev_err(lg->chip.dev,
|
||||
"unable to lock HW IRQ %lu for IRQ\n",
|
||||
irqd_to_hwirq(d));
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lp_irq_relres(struct irq_data *d)
|
||||
{
|
||||
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
|
||||
|
||||
gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d));
|
||||
}
|
||||
|
||||
static struct irq_chip lp_irqchip = {
|
||||
.name = "LP-GPIO",
|
||||
.irq_mask = lp_irq_mask,
|
||||
|
@ -328,8 +303,6 @@ static struct irq_chip lp_irqchip = {
|
|||
.irq_enable = lp_irq_enable,
|
||||
.irq_disable = lp_irq_disable,
|
||||
.irq_set_type = lp_irq_type,
|
||||
.irq_request_resources = lp_irq_reqres,
|
||||
.irq_release_resources = lp_irq_relres,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
|
@ -348,22 +321,6 @@ static void lp_gpio_irq_init_hw(struct lp_gpio *lg)
|
|||
}
|
||||
}
|
||||
|
||||
static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct lp_gpio *lg = d->host_data;
|
||||
|
||||
irq_set_chip_and_handler(irq, &lp_irqchip, handle_simple_irq);
|
||||
irq_set_chip_data(irq, lg);
|
||||
irq_set_irq_type(irq, IRQ_TYPE_NONE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops lp_gpio_irq_ops = {
|
||||
.map = lp_gpio_irq_map,
|
||||
};
|
||||
|
||||
static int lp_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lp_gpio *lg;
|
||||
|
@ -371,7 +328,6 @@ static int lp_gpio_probe(struct platform_device *pdev)
|
|||
struct resource *io_rc, *irq_rc;
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned long reg_len;
|
||||
unsigned hwirq;
|
||||
int ret = -ENODEV;
|
||||
|
||||
lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL);
|
||||
|
@ -414,27 +370,28 @@ static int lp_gpio_probe(struct platform_device *pdev)
|
|||
gc->can_sleep = false;
|
||||
gc->dev = dev;
|
||||
|
||||
/* set up interrupts */
|
||||
if (irq_rc && irq_rc->start) {
|
||||
hwirq = irq_rc->start;
|
||||
gc->to_irq = lp_gpio_to_irq;
|
||||
|
||||
lg->domain = irq_domain_add_linear(NULL, LP_NUM_GPIO,
|
||||
&lp_gpio_irq_ops, lg);
|
||||
if (!lg->domain)
|
||||
return -ENXIO;
|
||||
|
||||
lp_gpio_irq_init_hw(lg);
|
||||
|
||||
irq_set_handler_data(hwirq, lg);
|
||||
irq_set_chained_handler(hwirq, lp_gpio_irq_handler);
|
||||
}
|
||||
|
||||
ret = gpiochip_add(gc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed adding lp-gpio chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set up interrupts */
|
||||
if (irq_rc && irq_rc->start) {
|
||||
lp_gpio_irq_init_hw(lg);
|
||||
ret = gpiochip_irqchip_add(gc, &lp_irqchip, 0,
|
||||
handle_simple_irq, IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to add irqchip\n");
|
||||
gpiochip_remove(gc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(gc, &lp_irqchip,
|
||||
(unsigned)irq_rc->start,
|
||||
lp_gpio_irq_handler);
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
|
@ -465,11 +422,8 @@ MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match);
|
|||
static int lp_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lp_gpio *lg = platform_get_drvdata(pdev);
|
||||
int err;
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
err = gpiochip_remove(&lg->chip);
|
||||
if (err)
|
||||
dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
|
||||
gpiochip_remove(&lg->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -228,21 +228,16 @@ EXPORT_SYMBOL_GPL(__max730x_probe);
|
|||
int __max730x_remove(struct device *dev)
|
||||
{
|
||||
struct max7301 *ts = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (ts == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
/* Power down the chip and disable IRQ output */
|
||||
ts->write(dev, 0x04, 0x00);
|
||||
|
||||
ret = gpiochip_remove(&ts->chip);
|
||||
if (!ret)
|
||||
mutex_destroy(&ts->lock);
|
||||
else
|
||||
dev_err(dev, "Failed to remove GPIO controller: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
gpiochip_remove(&ts->chip);
|
||||
mutex_destroy(&ts->lock);
|
||||
kfree(ts);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__max730x_remove);
|
||||
|
||||
|
|
|
@ -676,12 +676,7 @@ static int max732x_remove(struct i2c_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
ret = gpiochip_remove(&chip->gpio_chip);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s failed, %d\n",
|
||||
"gpiochip_remove()", ret);
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&chip->gpio_chip);
|
||||
|
||||
max732x_irq_teardown(chip);
|
||||
|
||||
|
|
|
@ -149,20 +149,15 @@ static int mc33880_probe(struct spi_device *spi)
|
|||
static int mc33880_remove(struct spi_device *spi)
|
||||
{
|
||||
struct mc33880 *mc;
|
||||
int ret;
|
||||
|
||||
mc = spi_get_drvdata(spi);
|
||||
if (mc == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
ret = gpiochip_remove(&mc->chip);
|
||||
if (!ret)
|
||||
mutex_destroy(&mc->lock);
|
||||
else
|
||||
dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
|
||||
ret);
|
||||
gpiochip_remove(&mc->chip);
|
||||
mutex_destroy(&mc->lock);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver mc33880_driver = {
|
||||
|
|
|
@ -118,7 +118,8 @@ static int mc9s08dz60_remove(struct i2c_client *client)
|
|||
|
||||
mc9s = i2c_get_clientdata(client);
|
||||
|
||||
return gpiochip_remove(&mc9s->chip);
|
||||
gpiochip_remove(&mc9s->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mc9s08dz60_id[] = {
|
||||
|
|
|
@ -812,16 +812,14 @@ static int mcp230xx_probe(struct i2c_client *client,
|
|||
static int mcp230xx_remove(struct i2c_client *client)
|
||||
{
|
||||
struct mcp23s08 *mcp = i2c_get_clientdata(client);
|
||||
int status;
|
||||
|
||||
if (client->irq && mcp->irq_controller)
|
||||
mcp23s08_irq_teardown(mcp);
|
||||
|
||||
status = gpiochip_remove(&mcp->chip);
|
||||
if (status == 0)
|
||||
kfree(mcp);
|
||||
gpiochip_remove(&mcp->chip);
|
||||
kfree(mcp);
|
||||
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mcp230xx_id[] = {
|
||||
|
@ -960,13 +958,10 @@ static int mcp23s08_probe(struct spi_device *spi)
|
|||
|
||||
fail:
|
||||
for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) {
|
||||
int tmp;
|
||||
|
||||
if (!data->mcp[addr])
|
||||
continue;
|
||||
tmp = gpiochip_remove(&data->mcp[addr]->chip);
|
||||
if (tmp < 0)
|
||||
dev_err(&spi->dev, "%s --> %d\n", "remove", tmp);
|
||||
gpiochip_remove(&data->mcp[addr]->chip);
|
||||
}
|
||||
kfree(data);
|
||||
return status;
|
||||
|
@ -976,23 +971,16 @@ static int mcp23s08_remove(struct spi_device *spi)
|
|||
{
|
||||
struct mcp23s08_driver_data *data = spi_get_drvdata(spi);
|
||||
unsigned addr;
|
||||
int status = 0;
|
||||
|
||||
for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) {
|
||||
int tmp;
|
||||
|
||||
if (!data->mcp[addr])
|
||||
continue;
|
||||
|
||||
tmp = gpiochip_remove(&data->mcp[addr]->chip);
|
||||
if (tmp < 0) {
|
||||
dev_err(&spi->dev, "%s --> %d\n", "remove", tmp);
|
||||
status = tmp;
|
||||
}
|
||||
gpiochip_remove(&data->mcp[addr]->chip);
|
||||
}
|
||||
if (status == 0)
|
||||
kfree(data);
|
||||
return status;
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id mcp23s08_ids[] = {
|
||||
|
|
|
@ -497,8 +497,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
|||
err_gpiochip_add:
|
||||
while (--i >= 0) {
|
||||
chip--;
|
||||
if (gpiochip_remove(&chip->gpio))
|
||||
dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i);
|
||||
gpiochip_remove(&chip->gpio);
|
||||
}
|
||||
kfree(chip_save);
|
||||
|
||||
|
@ -519,7 +518,6 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
|||
|
||||
static void ioh_gpio_remove(struct pci_dev *pdev)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
struct ioh_gpio *chip = pci_get_drvdata(pdev);
|
||||
void *chip_save;
|
||||
|
@ -530,9 +528,7 @@ static void ioh_gpio_remove(struct pci_dev *pdev)
|
|||
|
||||
for (i = 0; i < 8; i++, chip++) {
|
||||
irq_free_descs(chip->irq_base, num_ports[i]);
|
||||
err = gpiochip_remove(&chip->gpio);
|
||||
if (err)
|
||||
dev_err(&pdev->dev, "Failed gpiochip_remove\n");
|
||||
gpiochip_remove(&chip->gpio);
|
||||
}
|
||||
|
||||
chip = chip_save;
|
||||
|
|
|
@ -438,10 +438,7 @@ MODULE_DEVICE_TABLE(of, msm_gpio_of_match);
|
|||
|
||||
static int msm_gpio_remove(struct platform_device *dev)
|
||||
{
|
||||
int ret = gpiochip_remove(&msm_gpio.gpio_chip);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
gpiochip_remove(&msm_gpio.gpio_chip);
|
||||
|
||||
irq_set_handler(msm_gpio.summary_irq, NULL);
|
||||
|
||||
|
|
|
@ -485,7 +485,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
|||
out_irqdesc_free:
|
||||
irq_free_descs(irq_base, 32);
|
||||
out_gpiochip_remove:
|
||||
WARN_ON(gpiochip_remove(&port->bgc.gc) < 0);
|
||||
gpiochip_remove(&port->bgc.gc);
|
||||
out_bgpio_remove:
|
||||
bgpio_remove(&port->bgc);
|
||||
out_bgio:
|
||||
|
|
|
@ -129,7 +129,8 @@ static int octeon_gpio_probe(struct platform_device *pdev)
|
|||
static int octeon_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_chip *chip = pdev->dev.platform_data;
|
||||
return gpiochip_remove(chip);
|
||||
gpiochip_remove(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id octeon_gpio_match[] = {
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/pm.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/platform_data/gpio-omap.h>
|
||||
|
@ -89,18 +88,19 @@ struct gpio_bank {
|
|||
#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage)
|
||||
#define LINE_USED(line, offset) (line & (BIT(offset)))
|
||||
|
||||
static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
|
||||
static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
|
||||
{
|
||||
return bank->chip.base + gpio_irq;
|
||||
}
|
||||
|
||||
static inline struct gpio_bank *_irq_data_get_bank(struct irq_data *d)
|
||||
static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
return container_of(chip, struct gpio_bank, chip);
|
||||
}
|
||||
|
||||
static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
|
||||
static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
|
||||
int is_input)
|
||||
{
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l;
|
||||
|
@ -117,7 +117,8 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
|
|||
|
||||
|
||||
/* set data out value using dedicate set/clear register */
|
||||
static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable)
|
||||
static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, int gpio,
|
||||
int enable)
|
||||
{
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l = GPIO_BIT(bank, gpio);
|
||||
|
@ -134,7 +135,8 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable)
|
|||
}
|
||||
|
||||
/* set data out value using mask register */
|
||||
static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)
|
||||
static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, int gpio,
|
||||
int enable)
|
||||
{
|
||||
void __iomem *reg = bank->base + bank->regs->dataout;
|
||||
u32 gpio_bit = GPIO_BIT(bank, gpio);
|
||||
|
@ -149,21 +151,21 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)
|
|||
bank->context.dataout = l;
|
||||
}
|
||||
|
||||
static int _get_gpio_datain(struct gpio_bank *bank, int offset)
|
||||
static int omap_get_gpio_datain(struct gpio_bank *bank, int offset)
|
||||
{
|
||||
void __iomem *reg = bank->base + bank->regs->datain;
|
||||
|
||||
return (readl_relaxed(reg) & (BIT(offset))) != 0;
|
||||
}
|
||||
|
||||
static int _get_gpio_dataout(struct gpio_bank *bank, int offset)
|
||||
static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset)
|
||||
{
|
||||
void __iomem *reg = bank->base + bank->regs->dataout;
|
||||
|
||||
return (readl_relaxed(reg) & (BIT(offset))) != 0;
|
||||
}
|
||||
|
||||
static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
|
||||
static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
|
||||
{
|
||||
int l = readl_relaxed(base + reg);
|
||||
|
||||
|
@ -175,7 +177,7 @@ static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
|
|||
writel_relaxed(l, base + reg);
|
||||
}
|
||||
|
||||
static inline void _gpio_dbck_enable(struct gpio_bank *bank)
|
||||
static inline void omap_gpio_dbck_enable(struct gpio_bank *bank)
|
||||
{
|
||||
if (bank->dbck_enable_mask && !bank->dbck_enabled) {
|
||||
clk_prepare_enable(bank->dbck);
|
||||
|
@ -186,7 +188,7 @@ static inline void _gpio_dbck_enable(struct gpio_bank *bank)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void _gpio_dbck_disable(struct gpio_bank *bank)
|
||||
static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
|
||||
{
|
||||
if (bank->dbck_enable_mask && bank->dbck_enabled) {
|
||||
/*
|
||||
|
@ -202,7 +204,7 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank)
|
|||
}
|
||||
|
||||
/**
|
||||
* _set_gpio_debounce - low level gpio debounce time
|
||||
* omap2_set_gpio_debounce - low level gpio debounce time
|
||||
* @bank: the gpio bank we're acting upon
|
||||
* @gpio: the gpio number on this @gpio
|
||||
* @debounce: debounce time to use
|
||||
|
@ -210,8 +212,8 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank)
|
|||
* OMAP's debounce time is in 31us steps so we need
|
||||
* to convert and round up to the closest unit.
|
||||
*/
|
||||
static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
|
||||
unsigned debounce)
|
||||
static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
|
||||
unsigned debounce)
|
||||
{
|
||||
void __iomem *reg;
|
||||
u32 val;
|
||||
|
@ -252,7 +254,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
|
|||
* used within _gpio_dbck_enable() is still not initialized at
|
||||
* that point. Therefore we have to enable dbck here.
|
||||
*/
|
||||
_gpio_dbck_enable(bank);
|
||||
omap_gpio_dbck_enable(bank);
|
||||
if (bank->dbck_enable_mask) {
|
||||
bank->context.debounce = debounce;
|
||||
bank->context.debounce_en = val;
|
||||
|
@ -260,7 +262,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
|
|||
}
|
||||
|
||||
/**
|
||||
* _clear_gpio_debounce - clear debounce settings for a gpio
|
||||
* omap_clear_gpio_debounce - clear debounce settings for a gpio
|
||||
* @bank: the gpio bank we're acting upon
|
||||
* @gpio: the gpio number on this @gpio
|
||||
*
|
||||
|
@ -269,7 +271,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
|
|||
* time too. The debounce clock will also be disabled when calling this function
|
||||
* if this is the only gpio in the bank using debounce.
|
||||
*/
|
||||
static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
|
||||
static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
|
||||
{
|
||||
u32 gpio_bit = GPIO_BIT(bank, gpio);
|
||||
|
||||
|
@ -293,20 +295,20 @@ static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
|
||||
static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
|
||||
unsigned trigger)
|
||||
{
|
||||
void __iomem *base = bank->base;
|
||||
u32 gpio_bit = BIT(gpio);
|
||||
|
||||
_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
|
||||
trigger & IRQ_TYPE_LEVEL_LOW);
|
||||
_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
|
||||
trigger & IRQ_TYPE_LEVEL_HIGH);
|
||||
_gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
|
||||
trigger & IRQ_TYPE_EDGE_RISING);
|
||||
_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
|
||||
trigger & IRQ_TYPE_EDGE_FALLING);
|
||||
omap_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
|
||||
trigger & IRQ_TYPE_LEVEL_LOW);
|
||||
omap_gpio_rmw(base, bank->regs->leveldetect1, gpio_bit,
|
||||
trigger & IRQ_TYPE_LEVEL_HIGH);
|
||||
omap_gpio_rmw(base, bank->regs->risingdetect, gpio_bit,
|
||||
trigger & IRQ_TYPE_EDGE_RISING);
|
||||
omap_gpio_rmw(base, bank->regs->fallingdetect, gpio_bit,
|
||||
trigger & IRQ_TYPE_EDGE_FALLING);
|
||||
|
||||
bank->context.leveldetect0 =
|
||||
readl_relaxed(bank->base + bank->regs->leveldetect0);
|
||||
|
@ -318,7 +320,7 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
|
|||
readl_relaxed(bank->base + bank->regs->fallingdetect);
|
||||
|
||||
if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
|
||||
_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
|
||||
omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
|
||||
bank->context.wake_en =
|
||||
readl_relaxed(bank->base + bank->regs->wkup_en);
|
||||
}
|
||||
|
@ -354,7 +356,7 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
|
|||
* This only applies to chips that can't do both rising and falling edge
|
||||
* detection at once. For all other chips, this function is a noop.
|
||||
*/
|
||||
static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
|
||||
static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
|
||||
{
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l = 0;
|
||||
|
@ -373,18 +375,18 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
|
|||
writel_relaxed(l, reg);
|
||||
}
|
||||
#else
|
||||
static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
|
||||
static void omap_toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
|
||||
#endif
|
||||
|
||||
static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
|
||||
unsigned trigger)
|
||||
static int omap_set_gpio_triggering(struct gpio_bank *bank, int gpio,
|
||||
unsigned trigger)
|
||||
{
|
||||
void __iomem *reg = bank->base;
|
||||
void __iomem *base = bank->base;
|
||||
u32 l = 0;
|
||||
|
||||
if (bank->regs->leveldetect0 && bank->regs->wkup_en) {
|
||||
set_gpio_trigger(bank, gpio, trigger);
|
||||
omap_set_gpio_trigger(bank, gpio, trigger);
|
||||
} else if (bank->regs->irqctrl) {
|
||||
reg += bank->regs->irqctrl;
|
||||
|
||||
|
@ -414,7 +416,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
|
|||
l |= BIT(gpio << 1);
|
||||
|
||||
/* Enable wake-up during idle for dynamic tick */
|
||||
_gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger);
|
||||
omap_gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger);
|
||||
bank->context.wake_en =
|
||||
readl_relaxed(bank->base + bank->regs->wkup_en);
|
||||
writel_relaxed(l, reg);
|
||||
|
@ -422,7 +424,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset)
|
||||
static void omap_enable_gpio_module(struct gpio_bank *bank, unsigned offset)
|
||||
{
|
||||
if (bank->regs->pinctrl) {
|
||||
void __iomem *reg = bank->base + bank->regs->pinctrl;
|
||||
|
@ -443,7 +445,7 @@ static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset)
|
|||
}
|
||||
}
|
||||
|
||||
static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset)
|
||||
static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset)
|
||||
{
|
||||
void __iomem *base = bank->base;
|
||||
|
||||
|
@ -451,7 +453,7 @@ static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset)
|
|||
!LINE_USED(bank->mod_usage, offset) &&
|
||||
!LINE_USED(bank->irq_usage, offset)) {
|
||||
/* Disable wake-up during idle for dynamic tick */
|
||||
_gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0);
|
||||
omap_gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0);
|
||||
bank->context.wake_en =
|
||||
readl_relaxed(bank->base + bank->regs->wkup_en);
|
||||
}
|
||||
|
@ -468,16 +470,16 @@ static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset)
|
|||
}
|
||||
}
|
||||
|
||||
static int gpio_is_input(struct gpio_bank *bank, int mask)
|
||||
static int omap_gpio_is_input(struct gpio_bank *bank, int mask)
|
||||
{
|
||||
void __iomem *reg = bank->base + bank->regs->direction;
|
||||
|
||||
return readl_relaxed(reg) & mask;
|
||||
}
|
||||
|
||||
static int gpio_irq_type(struct irq_data *d, unsigned type)
|
||||
static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
||||
{
|
||||
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
||||
unsigned gpio = 0;
|
||||
int retval;
|
||||
unsigned long flags;
|
||||
|
@ -492,7 +494,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
|
|||
#endif
|
||||
|
||||
if (!gpio)
|
||||
gpio = irq_to_gpio(bank, d->hwirq);
|
||||
gpio = omap_irq_to_gpio(bank, d->hwirq);
|
||||
|
||||
if (type & ~IRQ_TYPE_SENSE_MASK)
|
||||
return -EINVAL;
|
||||
|
@ -503,11 +505,11 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
|
|||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
offset = GPIO_INDEX(bank, gpio);
|
||||
retval = _set_gpio_triggering(bank, offset, type);
|
||||
retval = omap_set_gpio_triggering(bank, offset, type);
|
||||
if (!LINE_USED(bank->mod_usage, offset)) {
|
||||
_enable_gpio_module(bank, offset);
|
||||
_set_gpio_direction(bank, offset, 1);
|
||||
} else if (!gpio_is_input(bank, BIT(offset))) {
|
||||
omap_enable_gpio_module(bank, offset);
|
||||
omap_set_gpio_direction(bank, offset, 1);
|
||||
} else if (!omap_gpio_is_input(bank, BIT(offset))) {
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -523,7 +525,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
||||
static void omap_clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
||||
{
|
||||
void __iomem *reg = bank->base;
|
||||
|
||||
|
@ -540,12 +542,12 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
|||
readl_relaxed(reg);
|
||||
}
|
||||
|
||||
static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
|
||||
static inline void omap_clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
|
||||
{
|
||||
_clear_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
|
||||
omap_clear_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
|
||||
}
|
||||
|
||||
static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
|
||||
static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank)
|
||||
{
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l;
|
||||
|
@ -559,7 +561,7 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
|
|||
return l;
|
||||
}
|
||||
|
||||
static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
||||
static void omap_enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
||||
{
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l;
|
||||
|
@ -581,7 +583,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
|||
writel_relaxed(l, reg);
|
||||
}
|
||||
|
||||
static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
||||
static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
||||
{
|
||||
void __iomem *reg = bank->base;
|
||||
u32 l;
|
||||
|
@ -603,12 +605,13 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
|
|||
writel_relaxed(l, reg);
|
||||
}
|
||||
|
||||
static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
|
||||
static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, int gpio,
|
||||
int enable)
|
||||
{
|
||||
if (enable)
|
||||
_enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
|
||||
omap_enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
|
||||
else
|
||||
_disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
|
||||
omap_disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -619,7 +622,7 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena
|
|||
* enabled. When system is suspended, only selected GPIO interrupts need
|
||||
* to have wake-up enabled.
|
||||
*/
|
||||
static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
|
||||
static int omap_set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
|
||||
{
|
||||
u32 gpio_bit = GPIO_BIT(bank, gpio);
|
||||
unsigned long flags;
|
||||
|
@ -642,22 +645,22 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void _reset_gpio(struct gpio_bank *bank, int gpio)
|
||||
static void omap_reset_gpio(struct gpio_bank *bank, int gpio)
|
||||
{
|
||||
_set_gpio_direction(bank, GPIO_INDEX(bank, gpio), 1);
|
||||
_set_gpio_irqenable(bank, gpio, 0);
|
||||
_clear_gpio_irqstatus(bank, gpio);
|
||||
_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
|
||||
_clear_gpio_debounce(bank, gpio);
|
||||
omap_set_gpio_direction(bank, GPIO_INDEX(bank, gpio), 1);
|
||||
omap_set_gpio_irqenable(bank, gpio, 0);
|
||||
omap_clear_gpio_irqstatus(bank, gpio);
|
||||
omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
|
||||
omap_clear_gpio_debounce(bank, gpio);
|
||||
}
|
||||
|
||||
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
|
||||
static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
|
||||
static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
|
||||
{
|
||||
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
||||
unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
|
||||
|
||||
return _set_gpio_wakeup(bank, gpio, enable);
|
||||
return omap_set_gpio_wakeup(bank, gpio, enable);
|
||||
}
|
||||
|
||||
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
|
@ -678,8 +681,8 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
|
|||
* not already been requested.
|
||||
*/
|
||||
if (!LINE_USED(bank->irq_usage, offset)) {
|
||||
_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
|
||||
_enable_gpio_module(bank, offset);
|
||||
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
|
||||
omap_enable_gpio_module(bank, offset);
|
||||
}
|
||||
bank->mod_usage |= BIT(offset);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
@ -694,8 +697,8 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
|
|||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
bank->mod_usage &= ~(BIT(offset));
|
||||
_disable_gpio_module(bank, offset);
|
||||
_reset_gpio(bank, bank->chip.base + offset);
|
||||
omap_disable_gpio_module(bank, offset);
|
||||
omap_reset_gpio(bank, bank->chip.base + offset);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
/*
|
||||
|
@ -715,7 +718,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
|
|||
* line's interrupt handler has been run, we may miss some nested
|
||||
* interrupts.
|
||||
*/
|
||||
static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||
static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
void __iomem *isr_reg = NULL;
|
||||
u32 isr;
|
||||
|
@ -738,7 +741,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|||
u32 isr_saved, level_mask = 0;
|
||||
u32 enabled;
|
||||
|
||||
enabled = _get_gpio_irqbank_mask(bank);
|
||||
enabled = omap_get_gpio_irqbank_mask(bank);
|
||||
isr_saved = isr = readl_relaxed(isr_reg) & enabled;
|
||||
|
||||
if (bank->level_mask)
|
||||
|
@ -747,9 +750,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|||
/* clear edge sensitive interrupts before handler(s) are
|
||||
called so that we don't miss any interrupt occurred while
|
||||
executing them */
|
||||
_disable_gpio_irqbank(bank, isr_saved & ~level_mask);
|
||||
_clear_gpio_irqbank(bank, isr_saved & ~level_mask);
|
||||
_enable_gpio_irqbank(bank, isr_saved & ~level_mask);
|
||||
omap_disable_gpio_irqbank(bank, isr_saved & ~level_mask);
|
||||
omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask);
|
||||
omap_enable_gpio_irqbank(bank, isr_saved & ~level_mask);
|
||||
|
||||
/* if there is only edge sensitive GPIO pin interrupts
|
||||
configured, we could unmask GPIO bank interrupt immediately */
|
||||
|
@ -773,7 +776,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|||
* This will be indicated in the bank toggle_mask.
|
||||
*/
|
||||
if (bank->toggle_mask & (BIT(bit)))
|
||||
_toggle_gpio_edge_triggering(bank, bit);
|
||||
omap_toggle_gpio_edge_triggering(bank, bit);
|
||||
|
||||
generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
|
||||
bit));
|
||||
|
@ -789,18 +792,18 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|||
pm_runtime_put(bank->dev);
|
||||
}
|
||||
|
||||
static void gpio_irq_shutdown(struct irq_data *d)
|
||||
static void omap_gpio_irq_shutdown(struct irq_data *d)
|
||||
{
|
||||
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
||||
unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
|
||||
unsigned long flags;
|
||||
unsigned offset = GPIO_INDEX(bank, gpio);
|
||||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
gpio_unlock_as_irq(&bank->chip, offset);
|
||||
bank->irq_usage &= ~(BIT(offset));
|
||||
_disable_gpio_module(bank, offset);
|
||||
_reset_gpio(bank, gpio);
|
||||
omap_disable_gpio_module(bank, offset);
|
||||
omap_reset_gpio(bank, gpio);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
/*
|
||||
|
@ -811,57 +814,57 @@ static void gpio_irq_shutdown(struct irq_data *d)
|
|||
pm_runtime_put(bank->dev);
|
||||
}
|
||||
|
||||
static void gpio_ack_irq(struct irq_data *d)
|
||||
static void omap_gpio_ack_irq(struct irq_data *d)
|
||||
{
|
||||
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
||||
unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
|
||||
|
||||
_clear_gpio_irqstatus(bank, gpio);
|
||||
omap_clear_gpio_irqstatus(bank, gpio);
|
||||
}
|
||||
|
||||
static void gpio_mask_irq(struct irq_data *d)
|
||||
static void omap_gpio_mask_irq(struct irq_data *d)
|
||||
{
|
||||
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
||||
unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
_set_gpio_irqenable(bank, gpio, 0);
|
||||
_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
|
||||
omap_set_gpio_irqenable(bank, gpio, 0);
|
||||
omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
}
|
||||
|
||||
static void gpio_unmask_irq(struct irq_data *d)
|
||||
static void omap_gpio_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
||||
unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
|
||||
unsigned int irq_mask = GPIO_BIT(bank, gpio);
|
||||
u32 trigger = irqd_get_trigger_type(d);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
if (trigger)
|
||||
_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), trigger);
|
||||
omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), trigger);
|
||||
|
||||
/* For level-triggered GPIOs, the clearing must be done after
|
||||
* the HW source is cleared, thus after the handler has run */
|
||||
if (bank->level_mask & irq_mask) {
|
||||
_set_gpio_irqenable(bank, gpio, 0);
|
||||
_clear_gpio_irqstatus(bank, gpio);
|
||||
omap_set_gpio_irqenable(bank, gpio, 0);
|
||||
omap_clear_gpio_irqstatus(bank, gpio);
|
||||
}
|
||||
|
||||
_set_gpio_irqenable(bank, gpio, 1);
|
||||
omap_set_gpio_irqenable(bank, gpio, 1);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
}
|
||||
|
||||
static struct irq_chip gpio_irq_chip = {
|
||||
.name = "GPIO",
|
||||
.irq_shutdown = gpio_irq_shutdown,
|
||||
.irq_ack = gpio_ack_irq,
|
||||
.irq_mask = gpio_mask_irq,
|
||||
.irq_unmask = gpio_unmask_irq,
|
||||
.irq_set_type = gpio_irq_type,
|
||||
.irq_set_wake = gpio_wake_enable,
|
||||
.irq_shutdown = omap_gpio_irq_shutdown,
|
||||
.irq_ack = omap_gpio_ack_irq,
|
||||
.irq_mask = omap_gpio_mask_irq,
|
||||
.irq_unmask = omap_gpio_unmask_irq,
|
||||
.irq_set_type = omap_gpio_irq_type,
|
||||
.irq_set_wake = omap_gpio_wake_enable,
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
@ -918,7 +921,7 @@ static struct platform_device omap_mpuio_device = {
|
|||
/* could list the /proc/iomem resources */
|
||||
};
|
||||
|
||||
static inline void mpuio_init(struct gpio_bank *bank)
|
||||
static inline void omap_mpuio_init(struct gpio_bank *bank)
|
||||
{
|
||||
platform_set_drvdata(&omap_mpuio_device, bank);
|
||||
|
||||
|
@ -928,7 +931,7 @@ static inline void mpuio_init(struct gpio_bank *bank)
|
|||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
static int gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
unsigned long flags;
|
||||
|
@ -943,19 +946,19 @@ static int gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
|||
return dir;
|
||||
}
|
||||
|
||||
static int gpio_input(struct gpio_chip *chip, unsigned offset)
|
||||
static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
unsigned long flags;
|
||||
|
||||
bank = container_of(chip, struct gpio_bank, chip);
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
_set_gpio_direction(bank, offset, 1);
|
||||
omap_set_gpio_direction(bank, offset, 1);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
static int omap_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
u32 mask;
|
||||
|
@ -963,13 +966,13 @@ static int gpio_get(struct gpio_chip *chip, unsigned offset)
|
|||
bank = container_of(chip, struct gpio_bank, chip);
|
||||
mask = (BIT(offset));
|
||||
|
||||
if (gpio_is_input(bank, mask))
|
||||
return _get_gpio_datain(bank, offset);
|
||||
if (omap_gpio_is_input(bank, mask))
|
||||
return omap_get_gpio_datain(bank, offset);
|
||||
else
|
||||
return _get_gpio_dataout(bank, offset);
|
||||
return omap_get_gpio_dataout(bank, offset);
|
||||
}
|
||||
|
||||
static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
|
||||
static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
unsigned long flags;
|
||||
|
@ -977,13 +980,13 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
|
|||
bank = container_of(chip, struct gpio_bank, chip);
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
bank->set_dataout(bank, offset, value);
|
||||
_set_gpio_direction(bank, offset, 0);
|
||||
omap_set_gpio_direction(bank, offset, 0);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
|
||||
unsigned debounce)
|
||||
static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
|
||||
unsigned debounce)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
unsigned long flags;
|
||||
|
@ -991,13 +994,13 @@ static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
|
|||
bank = container_of(chip, struct gpio_bank, chip);
|
||||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
_set_gpio_debounce(bank, offset, debounce);
|
||||
omap2_set_gpio_debounce(bank, offset, debounce);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
unsigned long flags;
|
||||
|
@ -1025,11 +1028,6 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank)
|
|||
called = true;
|
||||
}
|
||||
|
||||
/* This lock class tells lockdep that GPIO irqs are in a different
|
||||
* category than their parents, so it won't report false recursion.
|
||||
*/
|
||||
static struct lock_class_key gpio_lock_class;
|
||||
|
||||
static void omap_gpio_mod_init(struct gpio_bank *bank)
|
||||
{
|
||||
void __iomem *base = bank->base;
|
||||
|
@ -1043,8 +1041,10 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
|
|||
return;
|
||||
}
|
||||
|
||||
_gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv);
|
||||
_gpio_rmw(base, bank->regs->irqstatus, l, !bank->regs->irqenable_inv);
|
||||
omap_gpio_rmw(base, bank->regs->irqenable, l,
|
||||
bank->regs->irqenable_inv);
|
||||
omap_gpio_rmw(base, bank->regs->irqstatus, l,
|
||||
!bank->regs->irqenable_inv);
|
||||
if (bank->regs->debounce_en)
|
||||
writel_relaxed(0, base + bank->regs->debounce_en);
|
||||
|
||||
|
@ -1078,10 +1078,10 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
|
|||
/* NOTE: No ack required, reading IRQ status clears it. */
|
||||
ct->chip.irq_mask = irq_gc_mask_set_bit;
|
||||
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
|
||||
ct->chip.irq_set_type = gpio_irq_type;
|
||||
ct->chip.irq_set_type = omap_gpio_irq_type;
|
||||
|
||||
if (bank->regs->wkup_en)
|
||||
ct->chip.irq_set_wake = gpio_wake_enable;
|
||||
ct->chip.irq_set_wake = omap_gpio_wake_enable;
|
||||
|
||||
ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride;
|
||||
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
|
||||
|
@ -1101,12 +1101,12 @@ static int omap_gpio_chip_init(struct gpio_bank *bank)
|
|||
*/
|
||||
bank->chip.request = omap_gpio_request;
|
||||
bank->chip.free = omap_gpio_free;
|
||||
bank->chip.get_direction = gpio_get_direction;
|
||||
bank->chip.direction_input = gpio_input;
|
||||
bank->chip.get = gpio_get;
|
||||
bank->chip.direction_output = gpio_output;
|
||||
bank->chip.set_debounce = gpio_debounce;
|
||||
bank->chip.set = gpio_set;
|
||||
bank->chip.get_direction = omap_gpio_get_direction;
|
||||
bank->chip.direction_input = omap_gpio_input;
|
||||
bank->chip.get = omap_gpio_get;
|
||||
bank->chip.direction_output = omap_gpio_output;
|
||||
bank->chip.set_debounce = omap_gpio_debounce;
|
||||
bank->chip.set = omap_gpio_set;
|
||||
if (bank->is_mpuio) {
|
||||
bank->chip.label = "mpuio";
|
||||
if (bank->regs->wkup_en)
|
||||
|
@ -1138,7 +1138,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank)
|
|||
#endif
|
||||
|
||||
ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip,
|
||||
irq_base, gpio_irq_handler,
|
||||
irq_base, omap_gpio_irq_handler,
|
||||
IRQ_TYPE_NONE);
|
||||
|
||||
if (ret) {
|
||||
|
@ -1148,11 +1148,10 @@ static int omap_gpio_chip_init(struct gpio_bank *bank)
|
|||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip,
|
||||
bank->irq, gpio_irq_handler);
|
||||
bank->irq, omap_gpio_irq_handler);
|
||||
|
||||
for (j = 0; j < bank->width; j++) {
|
||||
int irq = irq_find_mapping(bank->chip.irqdomain, j);
|
||||
irq_set_lockdep_class(irq, &gpio_lock_class);
|
||||
if (bank->is_mpuio) {
|
||||
omap_mpuio_alloc_gc(bank, irq, bank->width);
|
||||
irq_set_chip_and_handler(irq, NULL, NULL);
|
||||
|
@ -1217,9 +1216,9 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (bank->regs->set_dataout && bank->regs->clr_dataout)
|
||||
bank->set_dataout = _set_gpio_dataout_reg;
|
||||
bank->set_dataout = omap_set_gpio_dataout_reg;
|
||||
else
|
||||
bank->set_dataout = _set_gpio_dataout_mask;
|
||||
bank->set_dataout = omap_set_gpio_dataout_mask;
|
||||
|
||||
spin_lock_init(&bank->lock);
|
||||
|
||||
|
@ -1238,7 +1237,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
|||
pm_runtime_get_sync(bank->dev);
|
||||
|
||||
if (bank->is_mpuio)
|
||||
mpuio_init(bank);
|
||||
omap_mpuio_init(bank);
|
||||
|
||||
omap_gpio_mod_init(bank);
|
||||
|
||||
|
@ -1320,7 +1319,7 @@ static int omap_gpio_runtime_suspend(struct device *dev)
|
|||
bank->context_loss_count =
|
||||
bank->get_context_loss_count(bank->dev);
|
||||
|
||||
_gpio_dbck_disable(bank);
|
||||
omap_gpio_dbck_disable(bank);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
return 0;
|
||||
|
@ -1351,7 +1350,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
|
|||
bank->get_context_loss_count(bank->dev);
|
||||
}
|
||||
|
||||
_gpio_dbck_enable(bank);
|
||||
omap_gpio_dbck_enable(bank);
|
||||
|
||||
/*
|
||||
* In ->runtime_suspend(), level-triggered, wakeup-enabled
|
||||
|
|
|
@ -210,7 +210,8 @@ static int palmas_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&palmas_gpio->gpio_chip);
|
||||
gpiochip_remove(&palmas_gpio->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver palmas_gpio_driver = {
|
||||
|
|
|
@ -765,12 +765,7 @@ static int pca953x_remove(struct i2c_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
ret = gpiochip_remove(&chip->gpio_chip);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s failed, %d\n",
|
||||
"gpiochip_remove()", ret);
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&chip->gpio_chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -444,9 +444,7 @@ static int pcf857x_remove(struct i2c_client *client)
|
|||
if (client->irq)
|
||||
pcf857x_irq_domain_cleanup(gpio);
|
||||
|
||||
status = gpiochip_remove(&gpio->chip);
|
||||
if (status)
|
||||
dev_err(&client->dev, "%s --> %d\n", "remove", status);
|
||||
gpiochip_remove(&gpio->chip);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -426,9 +426,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
|
|||
|
||||
err_request_irq:
|
||||
irq_free_descs(irq_base, gpio_pins[chip->ioh]);
|
||||
|
||||
if (gpiochip_remove(&chip->gpio))
|
||||
dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
|
||||
gpiochip_remove(&chip->gpio);
|
||||
|
||||
err_gpiochip_add:
|
||||
pci_iounmap(pdev, chip->base);
|
||||
|
@ -447,7 +445,6 @@ static int pch_gpio_probe(struct pci_dev *pdev,
|
|||
|
||||
static void pch_gpio_remove(struct pci_dev *pdev)
|
||||
{
|
||||
int err;
|
||||
struct pch_gpio *chip = pci_get_drvdata(pdev);
|
||||
|
||||
if (chip->irq_base != -1) {
|
||||
|
@ -456,10 +453,7 @@ static void pch_gpio_remove(struct pci_dev *pdev)
|
|||
irq_free_descs(chip->irq_base, gpio_pins[chip->ioh]);
|
||||
}
|
||||
|
||||
err = gpiochip_remove(&chip->gpio);
|
||||
if (err)
|
||||
dev_err(&pdev->dev, "Failed gpiochip_remove\n");
|
||||
|
||||
gpiochip_remove(&chip->gpio);
|
||||
pci_iounmap(pdev, chip->base);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
|
|
@ -498,7 +498,7 @@ static int pxa_gpio_nums(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id pxa_gpio_dt_ids[] = {
|
||||
static const struct of_device_id pxa_gpio_dt_ids[] = {
|
||||
{ .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, },
|
||||
{ .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, },
|
||||
{ .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, },
|
||||
|
@ -649,6 +649,11 @@ static int pxa_gpio_probe(struct platform_device *pdev)
|
|||
handle_edge_irq);
|
||||
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||
}
|
||||
} else {
|
||||
if (irq0 > 0)
|
||||
irq_set_chained_handler(irq0, pxa_gpio_demux_handler);
|
||||
if (irq1 > 0)
|
||||
irq_set_chained_handler(irq1, pxa_gpio_demux_handler);
|
||||
}
|
||||
|
||||
irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
|
||||
|
|
|
@ -148,7 +148,8 @@ static int rc5t583_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&rc5t583_gpio->gpio_chip);
|
||||
gpiochip_remove(&rc5t583_gpio->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rc5t583_gpio_driver = {
|
||||
|
|
|
@ -240,9 +240,9 @@ static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
|
|||
/* testing on r8a7790 shows that INDT does not show correct pin state
|
||||
* when configured as output, so use OUTDT in case of output pins */
|
||||
if (gpio_rcar_read(gpio_to_priv(chip), INOUTSEL) & bit)
|
||||
return (int)(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
|
||||
return !!(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
|
||||
else
|
||||
return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
|
||||
return !!(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
|
||||
}
|
||||
|
||||
static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
|
@ -472,11 +472,8 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
|||
static int gpio_rcar_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_rcar_priv *p = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&p->gpio_chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
gpiochip_remove(&p->gpio_chip);
|
||||
|
||||
irq_domain_remove(p->irq_domain);
|
||||
pm_runtime_put(&pdev->dev);
|
||||
|
|
|
@ -199,14 +199,11 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
static int rdc321x_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct rdc321x_gpio *rdc321x_gpio_dev = platform_get_drvdata(pdev);
|
||||
|
||||
ret = gpiochip_remove(&rdc321x_gpio_dev->chip);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to unregister chip\n");
|
||||
gpiochip_remove(&rdc321x_gpio_dev->chip);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rdc321x_gpio_driver = {
|
||||
|
|
|
@ -290,8 +290,7 @@ static int sch_gpio_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_sch_gpio_resume:
|
||||
if (gpiochip_remove(&sch_gpio_core))
|
||||
dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
|
||||
gpiochip_remove(&sch_gpio_core);
|
||||
|
||||
err_sch_gpio_core:
|
||||
release_region(res->start, resource_size(res));
|
||||
|
@ -304,23 +303,14 @@ static int sch_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct resource *res;
|
||||
if (gpio_ba) {
|
||||
int err;
|
||||
|
||||
err = gpiochip_remove(&sch_gpio_core);
|
||||
if (err)
|
||||
dev_err(&pdev->dev, "%s failed, %d\n",
|
||||
"gpiochip_remove()", err);
|
||||
err = gpiochip_remove(&sch_gpio_resume);
|
||||
if (err)
|
||||
dev_err(&pdev->dev, "%s failed, %d\n",
|
||||
"gpiochip_remove()", err);
|
||||
gpiochip_remove(&sch_gpio_core);
|
||||
gpiochip_remove(&sch_gpio_resume);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
|
||||
release_region(res->start, resource_size(res));
|
||||
gpio_ba = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -291,14 +291,12 @@ static int sch311x_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
|
||||
struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
|
||||
int err, i;
|
||||
int i;
|
||||
|
||||
release_region(pdata->runtime_reg + GP1, 6);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
|
||||
err = gpiochip_remove(&priv->blocks[i].chip);
|
||||
if (err)
|
||||
return err;
|
||||
gpiochip_remove(&priv->blocks[i].chip);
|
||||
dev_info(&pdev->dev,
|
||||
"SMSC SCH311x GPIO block %d unregistered.\n", i);
|
||||
}
|
||||
|
|
|
@ -265,9 +265,7 @@ static void sdv_gpio_remove(struct pci_dev *pdev)
|
|||
free_irq(pdev->irq, sd);
|
||||
irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
|
||||
|
||||
if (gpiochip_remove(&sd->bgpio.gc))
|
||||
dev_err(&pdev->dev, "gpiochip_remove() failed.\n");
|
||||
|
||||
gpiochip_remove(&sd->bgpio.gc);
|
||||
pci_release_region(pdev, GPIO_BAR);
|
||||
iounmap(sd->gpio_pub_base);
|
||||
pci_disable_device(pdev);
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/stmpe.h>
|
||||
|
@ -31,9 +29,7 @@ struct stmpe_gpio {
|
|||
struct stmpe *stmpe;
|
||||
struct device *dev;
|
||||
struct mutex irq_lock;
|
||||
struct irq_domain *domain;
|
||||
unsigned norequest_mask;
|
||||
|
||||
/* Caches of interrupt control registers for bus_lock */
|
||||
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
|
||||
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
|
||||
|
@ -101,13 +97,6 @@ static int stmpe_gpio_direction_input(struct gpio_chip *chip,
|
|||
return stmpe_set_bits(stmpe, reg, mask, 0);
|
||||
}
|
||||
|
||||
static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
|
||||
|
||||
return irq_create_mapping(stmpe_gpio->domain, offset);
|
||||
}
|
||||
|
||||
static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
|
||||
|
@ -126,14 +115,14 @@ static struct gpio_chip template_chip = {
|
|||
.get = stmpe_gpio_get,
|
||||
.direction_output = stmpe_gpio_direction_output,
|
||||
.set = stmpe_gpio_set,
|
||||
.to_irq = stmpe_gpio_to_irq,
|
||||
.request = stmpe_gpio_request,
|
||||
.can_sleep = true,
|
||||
};
|
||||
|
||||
static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
|
||||
int offset = d->hwirq;
|
||||
int regoffset = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
@ -160,14 +149,16 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
|
||||
static void stmpe_gpio_irq_lock(struct irq_data *d)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
|
||||
|
||||
mutex_lock(&stmpe_gpio->irq_lock);
|
||||
}
|
||||
|
||||
static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
|
||||
struct stmpe *stmpe = stmpe_gpio->stmpe;
|
||||
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
|
||||
static const u8 regmap[] = {
|
||||
|
@ -200,7 +191,8 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
|
|||
|
||||
static void stmpe_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
|
||||
int offset = d->hwirq;
|
||||
int regoffset = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
@ -210,7 +202,8 @@ static void stmpe_gpio_irq_mask(struct irq_data *d)
|
|||
|
||||
static void stmpe_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
|
||||
int offset = d->hwirq;
|
||||
int regoffset = offset / 8;
|
||||
int mask = 1 << (offset % 8);
|
||||
|
@ -253,7 +246,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
|
|||
while (stat) {
|
||||
int bit = __ffs(stat);
|
||||
int line = bank * 8 + bit;
|
||||
int child_irq = irq_find_mapping(stmpe_gpio->domain,
|
||||
int child_irq = irq_find_mapping(stmpe_gpio->chip.irqdomain,
|
||||
line);
|
||||
|
||||
handle_nested_irq(child_irq);
|
||||
|
@ -271,56 +264,6 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct stmpe_gpio *stmpe_gpio = d->host_data;
|
||||
|
||||
if (!stmpe_gpio)
|
||||
return -EINVAL;
|
||||
|
||||
irq_set_chip_data(irq, stmpe_gpio);
|
||||
irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip,
|
||||
handle_simple_irq);
|
||||
irq_set_nested_thread(irq, 1);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(irq);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
|
||||
{
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(irq, 0);
|
||||
#endif
|
||||
irq_set_chip_and_handler(irq, NULL, NULL);
|
||||
irq_set_chip_data(irq, NULL);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
|
||||
.unmap = stmpe_gpio_irq_unmap,
|
||||
.map = stmpe_gpio_irq_map,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
|
||||
struct device_node *np)
|
||||
{
|
||||
stmpe_gpio->domain = irq_domain_add_simple(np,
|
||||
stmpe_gpio->chip.ngpio, 0,
|
||||
&stmpe_gpio_irq_simple_ops, stmpe_gpio);
|
||||
if (!stmpe_gpio->domain) {
|
||||
dev_err(stmpe_gpio->dev, "failed to create irqdomain\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
|
||||
|
@ -358,30 +301,37 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
if (irq < 0)
|
||||
dev_info(&pdev->dev,
|
||||
"device configured in no-irq mode; "
|
||||
"device configured in no-irq mode: "
|
||||
"irqs are not available\n");
|
||||
|
||||
ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
if (irq >= 0) {
|
||||
ret = stmpe_gpio_irq_init(stmpe_gpio, np);
|
||||
if (ret)
|
||||
goto out_disable;
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq,
|
||||
IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
|
||||
if (irq > 0) {
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
stmpe_gpio_irq, IRQF_ONESHOT,
|
||||
"stmpe-gpio", stmpe_gpio);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
|
||||
goto out_disable;
|
||||
}
|
||||
ret = gpiochip_irqchip_add(&stmpe_gpio->chip,
|
||||
&stmpe_gpio_irq_chip,
|
||||
0,
|
||||
handle_simple_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"could not connect irqchip to gpiochip\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpiochip_add(&stmpe_gpio->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
|
||||
goto out_freeirq;
|
||||
goto out_disable;
|
||||
}
|
||||
|
||||
if (pdata && pdata->setup)
|
||||
|
@ -391,9 +341,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
out_freeirq:
|
||||
if (irq >= 0)
|
||||
free_irq(irq, stmpe_gpio);
|
||||
out_disable:
|
||||
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
|
||||
out_free:
|
||||
|
@ -406,24 +353,14 @@ static int stmpe_gpio_remove(struct platform_device *pdev)
|
|||
struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
|
||||
struct stmpe *stmpe = stmpe_gpio->stmpe;
|
||||
struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio;
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
int ret;
|
||||
|
||||
if (pdata && pdata->remove)
|
||||
pdata->remove(stmpe, stmpe_gpio->chip.base);
|
||||
|
||||
ret = gpiochip_remove(&stmpe_gpio->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(stmpe_gpio->dev,
|
||||
"unable to remove gpiochip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&stmpe_gpio->chip);
|
||||
|
||||
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
|
||||
|
||||
if (irq >= 0)
|
||||
free_irq(irq, stmpe_gpio);
|
||||
|
||||
kfree(stmpe_gpio);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -615,19 +615,16 @@ static int sx150x_probe(struct i2c_client *client,
|
|||
|
||||
return 0;
|
||||
probe_fail_post_gpiochip_add:
|
||||
WARN_ON(gpiochip_remove(&chip->gpio_chip) < 0);
|
||||
gpiochip_remove(&chip->gpio_chip);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sx150x_remove(struct i2c_client *client)
|
||||
{
|
||||
struct sx150x_chip *chip;
|
||||
int rc;
|
||||
|
||||
chip = i2c_get_clientdata(client);
|
||||
rc = gpiochip_remove(&chip->gpio_chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
gpiochip_remove(&chip->gpio_chip);
|
||||
|
||||
if (chip->irq_summary >= 0)
|
||||
sx150x_remove_irq_chip(chip);
|
||||
|
|
|
@ -172,7 +172,8 @@ static int syscon_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct syscon_gpio_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&priv->chip);
|
||||
gpiochip_remove(&priv->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver syscon_gpio_driver = {
|
||||
|
|
|
@ -291,7 +291,6 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
|
|||
static int __exit tb10x_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tb10x_gpio *tb10x_gpio = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
if (tb10x_gpio->gc.to_irq) {
|
||||
irq_remove_generic_chip(tb10x_gpio->domain->gc->gc[0],
|
||||
|
@ -300,9 +299,7 @@ static int __exit tb10x_gpio_remove(struct platform_device *pdev)
|
|||
irq_domain_remove(tb10x_gpio->domain);
|
||||
free_irq(tb10x_gpio->irq, tb10x_gpio);
|
||||
}
|
||||
ret = gpiochip_remove(&tb10x_gpio->gc);
|
||||
if (ret)
|
||||
return ret;
|
||||
gpiochip_remove(&tb10x_gpio->gc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -313,17 +313,11 @@ static int tc3589x_gpio_remove(struct platform_device *pdev)
|
|||
struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev);
|
||||
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
|
||||
struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio;
|
||||
int ret;
|
||||
|
||||
if (pdata && pdata->remove)
|
||||
pdata->remove(tc3589x, tc3589x_gpio->chip.base);
|
||||
|
||||
ret = gpiochip_remove(&tc3589x_gpio->chip);
|
||||
if (ret < 0) {
|
||||
dev_err(tc3589x_gpio->dev,
|
||||
"unable to remove gpiochip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
gpiochip_remove(&tc3589x_gpio->chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -307,7 +307,6 @@ static int timbgpio_probe(struct platform_device *pdev)
|
|||
|
||||
static int timbgpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct timbgpio *tgpio = platform_get_drvdata(pdev);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
@ -323,9 +322,7 @@ static int timbgpio_remove(struct platform_device *pdev)
|
|||
irq_set_handler_data(irq, NULL);
|
||||
}
|
||||
|
||||
err = gpiochip_remove(&tgpio->gpio);
|
||||
if (err)
|
||||
printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n");
|
||||
gpiochip_remove(&tgpio->gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -137,7 +137,8 @@ static int tps6586x_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct tps6586x_gpio *tps6586x_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&tps6586x_gpio->gpio_chip);
|
||||
gpiochip_remove(&tps6586x_gpio->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tps6586x_gpio_driver = {
|
||||
|
|
|
@ -190,7 +190,8 @@ static int tps65910_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&tps65910_gpio->gpio_chip);
|
||||
gpiochip_remove(&tps65910_gpio->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tps65910_gpio_driver = {
|
||||
|
|
|
@ -117,7 +117,8 @@ static int tps65912_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct tps65912_gpio_data *tps65912_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&tps65912_gpio->gpio_chip);
|
||||
gpiochip_remove(&tps65912_gpio->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tps65912_gpio_driver = {
|
||||
|
|
|
@ -427,8 +427,7 @@ static int ts5500_dio_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
cleanup:
|
||||
if (gpiochip_remove(&priv->gpio_chip))
|
||||
dev_err(dev, "failed to remove gpio chip\n");
|
||||
gpiochip_remove(&priv->gpio_chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -437,7 +436,8 @@ static int ts5500_dio_remove(struct platform_device *pdev)
|
|||
struct ts5500_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
ts5500_disable_irq(priv);
|
||||
return gpiochip_remove(&priv->gpio_chip);
|
||||
gpiochip_remove(&priv->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id ts5500_dio_ids[] = {
|
||||
|
|
|
@ -554,7 +554,7 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
if (pdata && pdata->setup) {
|
||||
if (pdata->setup) {
|
||||
int status;
|
||||
|
||||
status = pdata->setup(&pdev->dev, priv->gpio_chip.base,
|
||||
|
@ -583,9 +583,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
status = gpiochip_remove(&priv->gpio_chip);
|
||||
if (status < 0)
|
||||
return status;
|
||||
gpiochip_remove(&priv->gpio_chip);
|
||||
|
||||
if (is_module())
|
||||
return 0;
|
||||
|
|
|
@ -111,7 +111,8 @@ static int gpo_twl6040_probe(struct platform_device *pdev)
|
|||
|
||||
static int gpo_twl6040_remove(struct platform_device *pdev)
|
||||
{
|
||||
return gpiochip_remove(&twl6040gpo_chip);
|
||||
gpiochip_remove(&twl6040gpo_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note: this hardware lives inside an I2C-based multi-function device. */
|
||||
|
|
|
@ -70,7 +70,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
|
|||
if (err)
|
||||
goto err;
|
||||
|
||||
if (ucb && ucb->gpio_setup)
|
||||
if (ucb->gpio_setup)
|
||||
err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio);
|
||||
|
||||
err:
|
||||
|
@ -89,7 +89,7 @@ static int ucb1400_gpio_remove(struct platform_device *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = gpiochip_remove(&ucb->gc);
|
||||
gpiochip_remove(&ucb->gc);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -446,8 +446,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
err_gpiob:
|
||||
if (gpiochip_remove(&vb_gpio->gpioa))
|
||||
dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
|
||||
gpiochip_remove(&vb_gpio->gpioa);
|
||||
|
||||
err_gpioa:
|
||||
return ret;
|
||||
|
@ -456,13 +455,10 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
|
|||
static int vprbrd_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vprbrd_gpio *vb_gpio = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_remove(&vb_gpio->gpiob);
|
||||
if (ret == 0)
|
||||
ret = gpiochip_remove(&vb_gpio->gpioa);
|
||||
gpiochip_remove(&vb_gpio->gpiob);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vprbrd_gpio_driver = {
|
||||
|
|
|
@ -515,7 +515,7 @@ static int giu_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
unsigned int trigger, i, pin;
|
||||
struct irq_chip *chip;
|
||||
int irq, retval;
|
||||
int irq, ret;
|
||||
|
||||
switch (pdev->id) {
|
||||
case GPIO_50PINS_PULLUPDOWN:
|
||||
|
@ -544,7 +544,11 @@ static int giu_probe(struct platform_device *pdev)
|
|||
|
||||
vr41xx_gpio_chip.dev = &pdev->dev;
|
||||
|
||||
retval = gpiochip_add(&vr41xx_gpio_chip);
|
||||
ret = gpiochip_add(&vr41xx_gpio_chip);
|
||||
if (!ret) {
|
||||
iounmap(giu_base);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
giu_write(GIUINTENL, 0);
|
||||
giu_write(GIUINTENH, 0);
|
||||
|
|
|
@ -288,8 +288,7 @@ static int vx855gpio_remove(struct platform_device *pdev)
|
|||
struct vx855_gpio *vg = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
if (gpiochip_remove(&vg->gpio))
|
||||
dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
|
||||
gpiochip_remove(&vg->gpio);
|
||||
|
||||
if (vg->gpi_reserved) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
|
|
|
@ -279,7 +279,8 @@ static int wm831x_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct wm831x_gpio *wm831x_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&wm831x_gpio->gpio_chip);
|
||||
gpiochip_remove(&wm831x_gpio->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver wm831x_gpio_driver = {
|
||||
|
|
|
@ -145,7 +145,8 @@ static int wm8350_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct wm8350_gpio_data *wm8350_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&wm8350_gpio->gpio_chip);
|
||||
gpiochip_remove(&wm8350_gpio->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver wm8350_gpio_driver = {
|
||||
|
|
|
@ -285,7 +285,8 @@ static int wm8994_gpio_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct wm8994_gpio *wm8994_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return gpiochip_remove(&wm8994_gpio->gpio_chip);
|
||||
gpiochip_remove(&wm8994_gpio->gpio_chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver wm8994_gpio_driver = {
|
||||
|
|
692
drivers/gpio/gpio-zynq.c
Normal file
692
drivers/gpio/gpio-zynq.c
Normal file
|
@ -0,0 +1,692 @@
|
|||
/*
|
||||
* Xilinx Zynq GPIO device driver
|
||||
*
|
||||
* Copyright (C) 2009 - 2014 Xilinx, Inc.
|
||||
*
|
||||
* 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/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define DRIVER_NAME "zynq-gpio"
|
||||
|
||||
/* Maximum banks */
|
||||
#define ZYNQ_GPIO_MAX_BANK 4
|
||||
|
||||
#define ZYNQ_GPIO_BANK0_NGPIO 32
|
||||
#define ZYNQ_GPIO_BANK1_NGPIO 22
|
||||
#define ZYNQ_GPIO_BANK2_NGPIO 32
|
||||
#define ZYNQ_GPIO_BANK3_NGPIO 32
|
||||
|
||||
#define ZYNQ_GPIO_NR_GPIOS (ZYNQ_GPIO_BANK0_NGPIO + \
|
||||
ZYNQ_GPIO_BANK1_NGPIO + \
|
||||
ZYNQ_GPIO_BANK2_NGPIO + \
|
||||
ZYNQ_GPIO_BANK3_NGPIO)
|
||||
|
||||
#define ZYNQ_GPIO_BANK0_PIN_MIN 0
|
||||
#define ZYNQ_GPIO_BANK0_PIN_MAX (ZYNQ_GPIO_BANK0_PIN_MIN + \
|
||||
ZYNQ_GPIO_BANK0_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK1_PIN_MIN (ZYNQ_GPIO_BANK0_PIN_MAX + 1)
|
||||
#define ZYNQ_GPIO_BANK1_PIN_MAX (ZYNQ_GPIO_BANK1_PIN_MIN + \
|
||||
ZYNQ_GPIO_BANK1_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK2_PIN_MIN (ZYNQ_GPIO_BANK1_PIN_MAX + 1)
|
||||
#define ZYNQ_GPIO_BANK2_PIN_MAX (ZYNQ_GPIO_BANK2_PIN_MIN + \
|
||||
ZYNQ_GPIO_BANK2_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK3_PIN_MIN (ZYNQ_GPIO_BANK2_PIN_MAX + 1)
|
||||
#define ZYNQ_GPIO_BANK3_PIN_MAX (ZYNQ_GPIO_BANK3_PIN_MIN + \
|
||||
ZYNQ_GPIO_BANK3_NGPIO - 1)
|
||||
|
||||
|
||||
/* Register offsets for the GPIO device */
|
||||
/* LSW Mask & Data -WO */
|
||||
#define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK))
|
||||
/* MSW Mask & Data -WO */
|
||||
#define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK))
|
||||
/* Data Register-RW */
|
||||
#define ZYNQ_GPIO_DATA_RO_OFFSET(BANK) (0x060 + (4 * BANK))
|
||||
/* Direction mode reg-RW */
|
||||
#define ZYNQ_GPIO_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK))
|
||||
/* Output enable reg-RW */
|
||||
#define ZYNQ_GPIO_OUTEN_OFFSET(BANK) (0x208 + (0x40 * BANK))
|
||||
/* Interrupt mask reg-RO */
|
||||
#define ZYNQ_GPIO_INTMASK_OFFSET(BANK) (0x20C + (0x40 * BANK))
|
||||
/* Interrupt enable reg-WO */
|
||||
#define ZYNQ_GPIO_INTEN_OFFSET(BANK) (0x210 + (0x40 * BANK))
|
||||
/* Interrupt disable reg-WO */
|
||||
#define ZYNQ_GPIO_INTDIS_OFFSET(BANK) (0x214 + (0x40 * BANK))
|
||||
/* Interrupt status reg-RO */
|
||||
#define ZYNQ_GPIO_INTSTS_OFFSET(BANK) (0x218 + (0x40 * BANK))
|
||||
/* Interrupt type reg-RW */
|
||||
#define ZYNQ_GPIO_INTTYPE_OFFSET(BANK) (0x21C + (0x40 * BANK))
|
||||
/* Interrupt polarity reg-RW */
|
||||
#define ZYNQ_GPIO_INTPOL_OFFSET(BANK) (0x220 + (0x40 * BANK))
|
||||
/* Interrupt on any, reg-RW */
|
||||
#define ZYNQ_GPIO_INTANY_OFFSET(BANK) (0x224 + (0x40 * BANK))
|
||||
|
||||
/* Disable all interrupts mask */
|
||||
#define ZYNQ_GPIO_IXR_DISABLE_ALL 0xFFFFFFFF
|
||||
|
||||
/* Mid pin number of a bank */
|
||||
#define ZYNQ_GPIO_MID_PIN_NUM 16
|
||||
|
||||
/* GPIO upper 16 bit mask */
|
||||
#define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000
|
||||
|
||||
/**
|
||||
* struct zynq_gpio - gpio device private data structure
|
||||
* @chip: instance of the gpio_chip
|
||||
* @base_addr: base address of the GPIO device
|
||||
* @clk: clock resource for this controller
|
||||
*/
|
||||
struct zynq_gpio {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *base_addr;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
/**
|
||||
* zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
|
||||
* for a given pin in the GPIO device
|
||||
* @pin_num: gpio pin number within the device
|
||||
* @bank_num: an output parameter used to return the bank number of the gpio
|
||||
* pin
|
||||
* @bank_pin_num: an output parameter used to return pin number within a bank
|
||||
* for the given gpio pin
|
||||
*
|
||||
* Returns the bank number and pin offset within the bank.
|
||||
*/
|
||||
static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
|
||||
unsigned int *bank_num,
|
||||
unsigned int *bank_pin_num)
|
||||
{
|
||||
switch (pin_num) {
|
||||
case ZYNQ_GPIO_BANK0_PIN_MIN ... ZYNQ_GPIO_BANK0_PIN_MAX:
|
||||
*bank_num = 0;
|
||||
*bank_pin_num = pin_num;
|
||||
break;
|
||||
case ZYNQ_GPIO_BANK1_PIN_MIN ... ZYNQ_GPIO_BANK1_PIN_MAX:
|
||||
*bank_num = 1;
|
||||
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK1_PIN_MIN;
|
||||
break;
|
||||
case ZYNQ_GPIO_BANK2_PIN_MIN ... ZYNQ_GPIO_BANK2_PIN_MAX:
|
||||
*bank_num = 2;
|
||||
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK2_PIN_MIN;
|
||||
break;
|
||||
case ZYNQ_GPIO_BANK3_PIN_MIN ... ZYNQ_GPIO_BANK3_PIN_MAX:
|
||||
*bank_num = 3;
|
||||
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK3_PIN_MIN;
|
||||
break;
|
||||
default:
|
||||
WARN(true, "invalid GPIO pin number: %u", pin_num);
|
||||
*bank_num = 0;
|
||||
*bank_pin_num = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_get_value - Get the state of the specified pin of GPIO device
|
||||
* @chip: gpio_chip instance to be worked on
|
||||
* @pin: gpio pin number within the device
|
||||
*
|
||||
* This function reads the state of the specified pin of the GPIO device.
|
||||
*
|
||||
* Return: 0 if the pin is low, 1 if pin is high.
|
||||
*/
|
||||
static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
u32 data;
|
||||
unsigned int bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
|
||||
|
||||
data = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
|
||||
|
||||
return (data >> bank_pin_num) & 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_set_value - Modify the state of the pin with specified value
|
||||
* @chip: gpio_chip instance to be worked on
|
||||
* @pin: gpio pin number within the device
|
||||
* @state: value used to modify the state of the specified pin
|
||||
*
|
||||
* This function calculates the register offset (i.e to lower 16 bits or
|
||||
* upper 16 bits) based on the given pin number and sets the state of a
|
||||
* gpio pin to the specified value. The state is either 0 or non-zero.
|
||||
*/
|
||||
static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
|
||||
int state)
|
||||
{
|
||||
unsigned int reg_offset, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
|
||||
|
||||
if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
|
||||
/* only 16 data bits in bit maskable reg */
|
||||
bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM;
|
||||
reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num);
|
||||
} else {
|
||||
reg_offset = ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num);
|
||||
}
|
||||
|
||||
/*
|
||||
* get the 32 bit value to be written to the mask/data register where
|
||||
* the upper 16 bits is the mask and lower 16 bits is the data
|
||||
*/
|
||||
state = !!state;
|
||||
state = ~(1 << (bank_pin_num + ZYNQ_GPIO_MID_PIN_NUM)) &
|
||||
((state << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK);
|
||||
|
||||
writel_relaxed(state, gpio->base_addr + reg_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_dir_in - Set the direction of the specified GPIO pin as input
|
||||
* @chip: gpio_chip instance to be worked on
|
||||
* @pin: gpio pin number within the device
|
||||
*
|
||||
* This function uses the read-modify-write sequence to set the direction of
|
||||
* the gpio pin as input.
|
||||
*
|
||||
* Return: 0 always
|
||||
*/
|
||||
static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned int bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
|
||||
|
||||
/* bank 0 pins 7 and 8 are special and cannot be used as inputs */
|
||||
if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8))
|
||||
return -EINVAL;
|
||||
|
||||
/* clear the bit in direction mode reg to set the pin as input */
|
||||
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||
reg &= ~BIT(bank_pin_num);
|
||||
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_dir_out - Set the direction of the specified GPIO pin as output
|
||||
* @chip: gpio_chip instance to be worked on
|
||||
* @pin: gpio pin number within the device
|
||||
* @state: value to be written to specified pin
|
||||
*
|
||||
* This function sets the direction of specified GPIO pin as output, configures
|
||||
* the Output Enable register for the pin and uses zynq_gpio_set to set
|
||||
* the state of the pin to the value specified.
|
||||
*
|
||||
* Return: 0 always
|
||||
*/
|
||||
static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
|
||||
int state)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned int bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
|
||||
|
||||
/* set the GPIO pin as output */
|
||||
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||
reg |= BIT(bank_pin_num);
|
||||
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||
|
||||
/* configure the output enable reg for the pin */
|
||||
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
|
||||
reg |= BIT(bank_pin_num);
|
||||
writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
|
||||
|
||||
/* set the state of the pin */
|
||||
zynq_gpio_set_value(chip, pin, state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_irq_mask - Disable the interrupts for a gpio pin
|
||||
* @irq_data: per irq and chip data passed down to chip functions
|
||||
*
|
||||
* This function calculates gpio pin number from irq number and sets the
|
||||
* bit in the Interrupt Disable register of the corresponding bank to disable
|
||||
* interrupts for that pin.
|
||||
*/
|
||||
static void zynq_gpio_irq_mask(struct irq_data *irq_data)
|
||||
{
|
||||
unsigned int device_pin_num, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
|
||||
writel_relaxed(BIT(bank_pin_num),
|
||||
gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_irq_unmask - Enable the interrupts for a gpio pin
|
||||
* @irq_data: irq data containing irq number of gpio pin for the interrupt
|
||||
* to enable
|
||||
*
|
||||
* This function calculates the gpio pin number from irq number and sets the
|
||||
* bit in the Interrupt Enable register of the corresponding bank to enable
|
||||
* interrupts for that pin.
|
||||
*/
|
||||
static void zynq_gpio_irq_unmask(struct irq_data *irq_data)
|
||||
{
|
||||
unsigned int device_pin_num, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
|
||||
writel_relaxed(BIT(bank_pin_num),
|
||||
gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num));
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_irq_ack - Acknowledge the interrupt of a gpio pin
|
||||
* @irq_data: irq data containing irq number of gpio pin for the interrupt
|
||||
* to ack
|
||||
*
|
||||
* This function calculates gpio pin number from irq number and sets the bit
|
||||
* in the Interrupt Status Register of the corresponding bank, to ACK the irq.
|
||||
*/
|
||||
static void zynq_gpio_irq_ack(struct irq_data *irq_data)
|
||||
{
|
||||
unsigned int device_pin_num, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
|
||||
writel_relaxed(BIT(bank_pin_num),
|
||||
gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_irq_enable - Enable the interrupts for a gpio pin
|
||||
* @irq_data: irq data containing irq number of gpio pin for the interrupt
|
||||
* to enable
|
||||
*
|
||||
* Clears the INTSTS bit and unmasks the given interrrupt.
|
||||
*/
|
||||
static void zynq_gpio_irq_enable(struct irq_data *irq_data)
|
||||
{
|
||||
/*
|
||||
* The Zynq GPIO controller does not disable interrupt detection when
|
||||
* the interrupt is masked and only disables the propagation of the
|
||||
* interrupt. This means when the controller detects an interrupt
|
||||
* condition while the interrupt is logically disabled it will propagate
|
||||
* that interrupt event once the interrupt is enabled. This will cause
|
||||
* the interrupt consumer to see spurious interrupts to prevent this
|
||||
* first make sure that the interrupt is not asserted and then enable
|
||||
* it.
|
||||
*/
|
||||
zynq_gpio_irq_ack(irq_data);
|
||||
zynq_gpio_irq_unmask(irq_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_set_irq_type - Set the irq type for a gpio pin
|
||||
* @irq_data: irq data containing irq number of gpio pin
|
||||
* @type: interrupt type that is to be set for the gpio pin
|
||||
*
|
||||
* This function gets the gpio pin number and its bank from the gpio pin number
|
||||
* and configures the INT_TYPE, INT_POLARITY and INT_ANY registers.
|
||||
*
|
||||
* Return: 0, negative error otherwise.
|
||||
* TYPE-EDGE_RISING, INT_TYPE - 1, INT_POLARITY - 1, INT_ANY - 0;
|
||||
* TYPE-EDGE_FALLING, INT_TYPE - 1, INT_POLARITY - 0, INT_ANY - 0;
|
||||
* TYPE-EDGE_BOTH, INT_TYPE - 1, INT_POLARITY - NA, INT_ANY - 1;
|
||||
* TYPE-LEVEL_HIGH, INT_TYPE - 0, INT_POLARITY - 1, INT_ANY - NA;
|
||||
* TYPE-LEVEL_LOW, INT_TYPE - 0, INT_POLARITY - 0, INT_ANY - NA
|
||||
*/
|
||||
static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
|
||||
{
|
||||
u32 int_type, int_pol, int_any;
|
||||
unsigned int device_pin_num, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
|
||||
|
||||
int_type = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
|
||||
int_pol = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTPOL_OFFSET(bank_num));
|
||||
int_any = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTANY_OFFSET(bank_num));
|
||||
|
||||
/*
|
||||
* based on the type requested, configure the INT_TYPE, INT_POLARITY
|
||||
* and INT_ANY registers
|
||||
*/
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
int_type |= BIT(bank_pin_num);
|
||||
int_pol |= BIT(bank_pin_num);
|
||||
int_any &= ~BIT(bank_pin_num);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
int_type |= BIT(bank_pin_num);
|
||||
int_pol &= ~BIT(bank_pin_num);
|
||||
int_any &= ~BIT(bank_pin_num);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
int_type |= BIT(bank_pin_num);
|
||||
int_any |= BIT(bank_pin_num);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
int_type &= ~BIT(bank_pin_num);
|
||||
int_pol |= BIT(bank_pin_num);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
int_type &= ~BIT(bank_pin_num);
|
||||
int_pol &= ~BIT(bank_pin_num);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
writel_relaxed(int_type,
|
||||
gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
|
||||
writel_relaxed(int_pol,
|
||||
gpio->base_addr + ZYNQ_GPIO_INTPOL_OFFSET(bank_num));
|
||||
writel_relaxed(int_any,
|
||||
gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
|
||||
{
|
||||
if (on)
|
||||
zynq_gpio_irq_unmask(data);
|
||||
else
|
||||
zynq_gpio_irq_mask(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* irq chip descriptor */
|
||||
static struct irq_chip zynq_gpio_irqchip = {
|
||||
.name = DRIVER_NAME,
|
||||
.irq_enable = zynq_gpio_irq_enable,
|
||||
.irq_mask = zynq_gpio_irq_mask,
|
||||
.irq_unmask = zynq_gpio_irq_unmask,
|
||||
.irq_set_type = zynq_gpio_set_irq_type,
|
||||
.irq_set_wake = zynq_gpio_set_wake,
|
||||
};
|
||||
|
||||
/**
|
||||
* zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device
|
||||
* @irq: irq number of the gpio bank where interrupt has occurred
|
||||
* @desc: irq descriptor instance of the 'irq'
|
||||
*
|
||||
* This function reads the Interrupt Status Register of each bank to get the
|
||||
* gpio pin number which has triggered an interrupt. It then acks the triggered
|
||||
* interrupt and calls the pin specific handler set by the higher layer
|
||||
* application for that pin.
|
||||
* Note: A bug is reported if no handler is set for the gpio pin.
|
||||
*/
|
||||
static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
u32 int_sts, int_enb;
|
||||
unsigned int bank_num;
|
||||
struct zynq_gpio *gpio = irq_get_handler_data(irq);
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++) {
|
||||
int_sts = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
|
||||
int_enb = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTMASK_OFFSET(bank_num));
|
||||
int_sts &= ~int_enb;
|
||||
if (int_sts) {
|
||||
int offset;
|
||||
unsigned long pending = int_sts;
|
||||
|
||||
for_each_set_bit(offset, &pending, 32) {
|
||||
unsigned int gpio_irq =
|
||||
irq_find_mapping(gpio->chip.irqdomain,
|
||||
offset);
|
||||
generic_handle_irq(gpio_irq);
|
||||
}
|
||||
|
||||
/* clear IRQ in HW */
|
||||
writel_relaxed(int_sts, gpio->base_addr +
|
||||
ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
|
||||
}
|
||||
}
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
||||
{
|
||||
if (!device_may_wakeup(dev))
|
||||
return pm_runtime_force_suspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused zynq_gpio_resume(struct device *dev)
|
||||
{
|
||||
if (!device_may_wakeup(dev))
|
||||
return pm_runtime_force_resume(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused zynq_gpio_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
return clk_prepare_enable(gpio->clk);
|
||||
}
|
||||
|
||||
static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(chip->dev);
|
||||
|
||||
/*
|
||||
* If the device is already active pm_runtime_get() will return 1 on
|
||||
* success, but gpio_request still needs to return 0.
|
||||
*/
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pm_runtime_put(chip->dev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume)
|
||||
SET_PM_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend,
|
||||
zynq_gpio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
/**
|
||||
* zynq_gpio_probe - Initialization method for a zynq_gpio device
|
||||
* @pdev: platform device instance
|
||||
*
|
||||
* This function allocates memory resources for the gpio device and registers
|
||||
* all the banks of the device. It will also set up interrupts for the gpio
|
||||
* pins.
|
||||
* Note: Interrupts are disabled for all the banks during initialization.
|
||||
*
|
||||
* Return: 0 on success, negative error otherwise.
|
||||
*/
|
||||
static int zynq_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret, bank_num, irq;
|
||||
struct zynq_gpio *gpio;
|
||||
struct gpio_chip *chip;
|
||||
struct resource *res;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
gpio->base_addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(gpio->base_addr))
|
||||
return PTR_ERR(gpio->base_addr);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "invalid IRQ\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
/* configure the gpio chip */
|
||||
chip = &gpio->chip;
|
||||
chip->label = "zynq_gpio";
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->get = zynq_gpio_get_value;
|
||||
chip->set = zynq_gpio_set_value;
|
||||
chip->request = zynq_gpio_request;
|
||||
chip->free = zynq_gpio_free;
|
||||
chip->direction_input = zynq_gpio_dir_in;
|
||||
chip->direction_output = zynq_gpio_dir_out;
|
||||
chip->base = -1;
|
||||
chip->ngpio = ZYNQ_GPIO_NR_GPIOS;
|
||||
|
||||
/* Enable GPIO clock */
|
||||
gpio->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(gpio->clk)) {
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
return PTR_ERR(gpio->clk);
|
||||
}
|
||||
ret = clk_prepare_enable(gpio->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* report a bug if gpio chip registration fails */
|
||||
ret = gpiochip_add(chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add gpio chip\n");
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
/* disable interrupts for all banks */
|
||||
for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++)
|
||||
writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
|
||||
ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
|
||||
|
||||
ret = gpiochip_irqchip_add(chip, &zynq_gpio_irqchip, 0,
|
||||
handle_simple_irq, IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add irq chip\n");
|
||||
goto err_rm_gpiochip;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(chip, &zynq_gpio_irqchip, irq,
|
||||
zynq_gpio_irqhandler);
|
||||
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
err_rm_gpiochip:
|
||||
if (gpiochip_remove(chip))
|
||||
dev_err(&pdev->dev, "Failed to remove gpio chip\n");
|
||||
err_disable_clk:
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_remove - Driver removal function
|
||||
* @pdev: platform device instance
|
||||
*
|
||||
* Return: 0 always
|
||||
*/
|
||||
static int zynq_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
ret = gpiochip_remove(&gpio->chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to remove gpio chip\n");
|
||||
return ret;
|
||||
}
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
device_set_wakeup_capable(&pdev->dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id zynq_gpio_of_match[] = {
|
||||
{ .compatible = "xlnx,zynq-gpio-1.0", },
|
||||
{ /* end of table */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
|
||||
|
||||
static struct platform_driver zynq_gpio_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &zynq_gpio_dev_pm_ops,
|
||||
.of_match_table = zynq_gpio_of_match,
|
||||
},
|
||||
.probe = zynq_gpio_probe,
|
||||
.remove = zynq_gpio_remove,
|
||||
};
|
||||
|
||||
/**
|
||||
* zynq_gpio_init - Initial driver registration call
|
||||
*
|
||||
* Return: value from platform_driver_register
|
||||
*/
|
||||
static int __init zynq_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&zynq_gpio_driver);
|
||||
}
|
||||
postcore_initcall(zynq_gpio_init);
|
||||
|
||||
MODULE_AUTHOR("Xilinx Inc.");
|
||||
MODULE_DESCRIPTION("Zynq GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -157,7 +157,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
|||
|
||||
gpiod_direction_input(desc);
|
||||
|
||||
ret = gpiod_lock_as_irq(desc);
|
||||
ret = gpio_lock_as_irq(chip, pin);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to lock GPIO as interrupt\n");
|
||||
goto fail_free_desc;
|
||||
|
@ -212,7 +212,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
|||
fail_free_event:
|
||||
kfree(event);
|
||||
fail_unlock_irq:
|
||||
gpiod_unlock_as_irq(desc);
|
||||
gpio_unlock_as_irq(chip, pin);
|
||||
fail_free_desc:
|
||||
gpiochip_free_own_desc(desc);
|
||||
|
||||
|
@ -221,7 +221,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
|||
|
||||
/**
|
||||
* acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
|
||||
* @acpi_gpio: ACPI GPIO chip
|
||||
* @chip: GPIO chip
|
||||
*
|
||||
* ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
|
||||
* handled by ACPI event methods which need to be called from the GPIO
|
||||
|
@ -229,11 +229,21 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
|||
* gpio pins have acpi event methods and assigns interrupt handlers that calls
|
||||
* the acpi event methods for those pins.
|
||||
*/
|
||||
static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
|
||||
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
|
||||
{
|
||||
struct gpio_chip *chip = acpi_gpio->chip;
|
||||
struct acpi_gpio_chip *acpi_gpio;
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
|
||||
if (!chip->to_irq)
|
||||
if (!chip->dev || !chip->to_irq)
|
||||
return;
|
||||
|
||||
handle = ACPI_HANDLE(chip->dev);
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&acpi_gpio->events);
|
||||
|
@ -243,17 +253,27 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
|
|||
|
||||
/**
|
||||
* acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
|
||||
* @acpi_gpio: ACPI GPIO chip
|
||||
* @chip: GPIO chip
|
||||
*
|
||||
* Free interrupts associated with GPIO ACPI event method for the given
|
||||
* GPIO chip.
|
||||
*/
|
||||
static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
|
||||
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
|
||||
{
|
||||
struct acpi_gpio_chip *acpi_gpio;
|
||||
struct acpi_gpio_event *event, *ep;
|
||||
struct gpio_chip *chip = acpi_gpio->chip;
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
|
||||
if (!chip->to_irq)
|
||||
if (!chip->dev || !chip->to_irq)
|
||||
return;
|
||||
|
||||
handle = ACPI_HANDLE(chip->dev);
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
|
||||
|
@ -263,7 +283,7 @@ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
|
|||
desc = gpiochip_get_desc(chip, event->pin);
|
||||
if (WARN_ON(IS_ERR(desc)))
|
||||
continue;
|
||||
gpiod_unlock_as_irq(desc);
|
||||
gpio_unlock_as_irq(chip, event->pin);
|
||||
gpiochip_free_own_desc(desc);
|
||||
list_del(&event->node);
|
||||
kfree(event);
|
||||
|
@ -525,7 +545,6 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
|
|||
return;
|
||||
}
|
||||
|
||||
acpi_gpiochip_request_interrupts(acpi_gpio);
|
||||
acpi_gpiochip_request_regions(acpi_gpio);
|
||||
}
|
||||
|
||||
|
@ -549,7 +568,6 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
|
|||
}
|
||||
|
||||
acpi_gpiochip_free_regions(acpi_gpio);
|
||||
acpi_gpiochip_free_interrupts(acpi_gpio);
|
||||
|
||||
acpi_detach_data(handle, acpi_gpio_chip_dh);
|
||||
kfree(acpi_gpio);
|
||||
|
|
102
drivers/gpio/gpiolib-legacy.c
Normal file
102
drivers/gpio/gpiolib-legacy.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
||||
void gpio_free(unsigned gpio)
|
||||
{
|
||||
gpiod_free(gpio_to_desc(gpio));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpio_free);
|
||||
|
||||
/**
|
||||
* gpio_request_one - request a single GPIO with initial configuration
|
||||
* @gpio: the GPIO number
|
||||
* @flags: GPIO configuration as specified by GPIOF_*
|
||||
* @label: a literal description string of this GPIO
|
||||
*/
|
||||
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
int err;
|
||||
|
||||
desc = gpio_to_desc(gpio);
|
||||
|
||||
err = gpiod_request(desc, label);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (flags & GPIOF_OPEN_DRAIN)
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
|
||||
if (flags & GPIOF_OPEN_SOURCE)
|
||||
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
|
||||
if (flags & GPIOF_ACTIVE_LOW)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
|
||||
if (flags & GPIOF_DIR_IN)
|
||||
err = gpiod_direction_input(desc);
|
||||
else
|
||||
err = gpiod_direction_output_raw(desc,
|
||||
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
|
||||
|
||||
if (err)
|
||||
goto free_gpio;
|
||||
|
||||
if (flags & GPIOF_EXPORT) {
|
||||
err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
|
||||
if (err)
|
||||
goto free_gpio;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_gpio:
|
||||
gpiod_free(desc);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpio_request_one);
|
||||
|
||||
int gpio_request(unsigned gpio, const char *label)
|
||||
{
|
||||
return gpiod_request(gpio_to_desc(gpio), label);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpio_request);
|
||||
|
||||
/**
|
||||
* gpio_request_array - request multiple GPIOs in a single call
|
||||
* @array: array of the 'struct gpio'
|
||||
* @num: how many GPIOs in the array
|
||||
*/
|
||||
int gpio_request_array(const struct gpio *array, size_t num)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < num; i++, array++) {
|
||||
err = gpio_request_one(array->gpio, array->flags, array->label);
|
||||
if (err)
|
||||
goto err_free;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
while (i--)
|
||||
gpio_free((--array)->gpio);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpio_request_array);
|
||||
|
||||
/**
|
||||
* gpio_free_array - release multiple GPIOs in a single call
|
||||
* @array: array of the 'struct gpio'
|
||||
* @num: how many GPIOs in the array
|
||||
*/
|
||||
void gpio_free_array(const struct gpio *array, size_t num)
|
||||
{
|
||||
while (num--)
|
||||
gpio_free((array++)->gpio);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpio_free_array);
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct gpio_desc;
|
||||
#include "gpiolib.h"
|
||||
|
||||
/* Private data structure for of_gpiochip_find_and_xlate */
|
||||
struct gg_data {
|
||||
|
@ -82,19 +82,19 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
|||
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
|
||||
&gg_data.gpiospec);
|
||||
if (ret) {
|
||||
pr_debug("%s: can't parse gpios property of node '%s[%d]'\n",
|
||||
__func__, np->full_name, index);
|
||||
pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n",
|
||||
__func__, propname, np->full_name, index);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
|
||||
|
||||
of_node_put(gg_data.gpiospec.np);
|
||||
pr_debug("%s exited with status %d\n", __func__,
|
||||
pr_debug("%s: parsed '%s' property of node '%s[%d]' - status (%d)\n",
|
||||
__func__, propname, np->full_name, index,
|
||||
PTR_ERR_OR_ZERO(gg_data.out_gpio));
|
||||
return gg_data.out_gpio;
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_named_gpiod_flags);
|
||||
|
||||
int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
|
||||
int index, enum of_gpio_flags *flags)
|
||||
|
|
827
drivers/gpio/gpiolib-sysfs.c
Normal file
827
drivers/gpio/gpiolib-sysfs.c
Normal file
|
@ -0,0 +1,827 @@
|
|||
#include <linux/idr.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
||||
static DEFINE_IDR(dirent_idr);
|
||||
|
||||
|
||||
/* lock protects against unexport_gpio() being called while
|
||||
* sysfs files are active.
|
||||
*/
|
||||
static DEFINE_MUTEX(sysfs_lock);
|
||||
|
||||
/*
|
||||
* /sys/class/gpio/gpioN... only for GPIOs that are exported
|
||||
* /direction
|
||||
* * MAY BE OMITTED if kernel won't allow direction changes
|
||||
* * is read/write as "in" or "out"
|
||||
* * may also be written as "high" or "low", initializing
|
||||
* output value as specified ("out" implies "low")
|
||||
* /value
|
||||
* * always readable, subject to hardware behavior
|
||||
* * may be writable, as zero/nonzero
|
||||
* /edge
|
||||
* * configures behavior of poll(2) on /value
|
||||
* * available only if pin can generate IRQs on input
|
||||
* * is read/write as "none", "falling", "rising", or "both"
|
||||
* /active_low
|
||||
* * configures polarity of /value
|
||||
* * is read/write as zero/nonzero
|
||||
* * also affects existing and subsequent "falling" and "rising"
|
||||
* /edge configuration
|
||||
*/
|
||||
|
||||
static ssize_t gpio_direction_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
status = -EIO;
|
||||
} else {
|
||||
gpiod_get_direction(desc);
|
||||
status = sprintf(buf, "%s\n",
|
||||
test_bit(FLAG_IS_OUT, &desc->flags)
|
||||
? "out" : "in");
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_direction_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else if (sysfs_streq(buf, "high"))
|
||||
status = gpiod_direction_output_raw(desc, 1);
|
||||
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
|
||||
status = gpiod_direction_output_raw(desc, 0);
|
||||
else if (sysfs_streq(buf, "in"))
|
||||
status = gpiod_direction_input(desc);
|
||||
else
|
||||
status = -EINVAL;
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
return status ? : size;
|
||||
}
|
||||
|
||||
static /* const */ DEVICE_ATTR(direction, 0644,
|
||||
gpio_direction_show, gpio_direction_store);
|
||||
|
||||
static ssize_t gpio_value_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else
|
||||
status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_value_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else if (!test_bit(FLAG_IS_OUT, &desc->flags))
|
||||
status = -EPERM;
|
||||
else {
|
||||
long value;
|
||||
|
||||
status = kstrtol(buf, 0, &value);
|
||||
if (status == 0) {
|
||||
gpiod_set_value_cansleep(desc, value);
|
||||
status = size;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static const DEVICE_ATTR(value, 0644,
|
||||
gpio_value_show, gpio_value_store);
|
||||
|
||||
static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
|
||||
{
|
||||
struct kernfs_node *value_sd = priv;
|
||||
|
||||
sysfs_notify_dirent(value_sd);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
|
||||
unsigned long gpio_flags)
|
||||
{
|
||||
struct kernfs_node *value_sd;
|
||||
unsigned long irq_flags;
|
||||
int ret, irq, id;
|
||||
|
||||
if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
|
||||
return 0;
|
||||
|
||||
irq = gpiod_to_irq(desc);
|
||||
if (irq < 0)
|
||||
return -EIO;
|
||||
|
||||
id = desc->flags >> ID_SHIFT;
|
||||
value_sd = idr_find(&dirent_idr, id);
|
||||
if (value_sd)
|
||||
free_irq(irq, value_sd);
|
||||
|
||||
desc->flags &= ~GPIO_TRIGGER_MASK;
|
||||
|
||||
if (!gpio_flags) {
|
||||
gpio_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
|
||||
ret = 0;
|
||||
goto free_id;
|
||||
}
|
||||
|
||||
irq_flags = IRQF_SHARED;
|
||||
if (test_bit(FLAG_TRIG_FALL, &gpio_flags))
|
||||
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
|
||||
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
|
||||
if (test_bit(FLAG_TRIG_RISE, &gpio_flags))
|
||||
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
|
||||
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
|
||||
|
||||
if (!value_sd) {
|
||||
value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
|
||||
if (!value_sd) {
|
||||
ret = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto free_sd;
|
||||
id = ret;
|
||||
|
||||
desc->flags &= GPIO_FLAGS_MASK;
|
||||
desc->flags |= (unsigned long)id << ID_SHIFT;
|
||||
|
||||
if (desc->flags >> ID_SHIFT != id) {
|
||||
ret = -ERANGE;
|
||||
goto free_id;
|
||||
}
|
||||
}
|
||||
|
||||
ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
|
||||
"gpiolib", value_sd);
|
||||
if (ret < 0)
|
||||
goto free_id;
|
||||
|
||||
ret = gpio_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
|
||||
if (ret < 0) {
|
||||
gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
|
||||
goto free_id;
|
||||
}
|
||||
|
||||
desc->flags |= gpio_flags;
|
||||
return 0;
|
||||
|
||||
free_id:
|
||||
idr_remove(&dirent_idr, id);
|
||||
desc->flags &= GPIO_FLAGS_MASK;
|
||||
free_sd:
|
||||
if (value_sd)
|
||||
sysfs_put(value_sd);
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
unsigned long flags;
|
||||
} trigger_types[] = {
|
||||
{ "none", 0 },
|
||||
{ "falling", BIT(FLAG_TRIG_FALL) },
|
||||
{ "rising", BIT(FLAG_TRIG_RISE) },
|
||||
{ "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) },
|
||||
};
|
||||
|
||||
static ssize_t gpio_edge_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else {
|
||||
int i;
|
||||
|
||||
status = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
|
||||
if ((desc->flags & GPIO_TRIGGER_MASK)
|
||||
== trigger_types[i].flags) {
|
||||
status = sprintf(buf, "%s\n",
|
||||
trigger_types[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_edge_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
|
||||
if (sysfs_streq(trigger_types[i].name, buf))
|
||||
goto found;
|
||||
return -EINVAL;
|
||||
|
||||
found:
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else {
|
||||
status = gpio_setup_irq(desc, dev, trigger_types[i].flags);
|
||||
if (!status)
|
||||
status = size;
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);
|
||||
|
||||
static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
|
||||
int value)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
|
||||
return 0;
|
||||
|
||||
if (value)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
else
|
||||
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
|
||||
/* reconfigure poll(2) support if enabled on one edge only */
|
||||
if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^
|
||||
!!test_bit(FLAG_TRIG_FALL, &desc->flags))) {
|
||||
unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK;
|
||||
|
||||
gpio_setup_irq(desc, dev, 0);
|
||||
status = gpio_setup_irq(desc, dev, trigger_flags);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_active_low_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else
|
||||
status = sprintf(buf, "%d\n",
|
||||
!!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_active_low_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
status = -EIO;
|
||||
} else {
|
||||
long value;
|
||||
|
||||
status = kstrtol(buf, 0, &value);
|
||||
if (status == 0)
|
||||
status = sysfs_set_active_low(desc, dev, value != 0);
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
return status ? : size;
|
||||
}
|
||||
|
||||
static const DEVICE_ATTR(active_low, 0644,
|
||||
gpio_active_low_show, gpio_active_low_store);
|
||||
|
||||
static const struct attribute *gpio_attrs[] = {
|
||||
&dev_attr_value.attr,
|
||||
&dev_attr_active_low.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group gpio_attr_group = {
|
||||
.attrs = (struct attribute **) gpio_attrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* /sys/class/gpio/gpiochipN/
|
||||
* /base ... matching gpio_chip.base (N)
|
||||
* /label ... matching gpio_chip.label
|
||||
* /ngpio ... matching gpio_chip.ngpio
|
||||
*/
|
||||
|
||||
static ssize_t chip_base_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", chip->base);
|
||||
}
|
||||
static DEVICE_ATTR(base, 0444, chip_base_show, NULL);
|
||||
|
||||
static ssize_t chip_label_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", chip->label ? : "");
|
||||
}
|
||||
static DEVICE_ATTR(label, 0444, chip_label_show, NULL);
|
||||
|
||||
static ssize_t chip_ngpio_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", chip->ngpio);
|
||||
}
|
||||
static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
|
||||
|
||||
static const struct attribute *gpiochip_attrs[] = {
|
||||
&dev_attr_base.attr,
|
||||
&dev_attr_label.attr,
|
||||
&dev_attr_ngpio.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group gpiochip_attr_group = {
|
||||
.attrs = (struct attribute **) gpiochip_attrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* /sys/class/gpio/export ... write-only
|
||||
* integer N ... number of GPIO to export (full access)
|
||||
* /sys/class/gpio/unexport ... write-only
|
||||
* integer N ... number of GPIO to unexport
|
||||
*/
|
||||
static ssize_t export_store(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
long gpio;
|
||||
struct gpio_desc *desc;
|
||||
int status;
|
||||
|
||||
status = kstrtol(buf, 0, &gpio);
|
||||
if (status < 0)
|
||||
goto done;
|
||||
|
||||
desc = gpio_to_desc(gpio);
|
||||
/* reject invalid GPIOs */
|
||||
if (!desc) {
|
||||
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* No extra locking here; FLAG_SYSFS just signifies that the
|
||||
* request and export were done by on behalf of userspace, so
|
||||
* they may be undone on its behalf too.
|
||||
*/
|
||||
|
||||
status = gpiod_request(desc, "sysfs");
|
||||
if (status < 0) {
|
||||
if (status == -EPROBE_DEFER)
|
||||
status = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
status = gpiod_export(desc, true);
|
||||
if (status < 0)
|
||||
gpiod_free(desc);
|
||||
else
|
||||
set_bit(FLAG_SYSFS, &desc->flags);
|
||||
|
||||
done:
|
||||
if (status)
|
||||
pr_debug("%s: status %d\n", __func__, status);
|
||||
return status ? : len;
|
||||
}
|
||||
|
||||
static ssize_t unexport_store(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
long gpio;
|
||||
struct gpio_desc *desc;
|
||||
int status;
|
||||
|
||||
status = kstrtol(buf, 0, &gpio);
|
||||
if (status < 0)
|
||||
goto done;
|
||||
|
||||
desc = gpio_to_desc(gpio);
|
||||
/* reject bogus commands (gpio_unexport ignores them) */
|
||||
if (!desc) {
|
||||
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = -EINVAL;
|
||||
|
||||
/* No extra locking here; FLAG_SYSFS just signifies that the
|
||||
* request and export were done by on behalf of userspace, so
|
||||
* they may be undone on its behalf too.
|
||||
*/
|
||||
if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
|
||||
status = 0;
|
||||
gpiod_free(desc);
|
||||
}
|
||||
done:
|
||||
if (status)
|
||||
pr_debug("%s: status %d\n", __func__, status);
|
||||
return status ? : len;
|
||||
}
|
||||
|
||||
static struct class_attribute gpio_class_attrs[] = {
|
||||
__ATTR(export, 0200, NULL, export_store),
|
||||
__ATTR(unexport, 0200, NULL, unexport_store),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static struct class gpio_class = {
|
||||
.name = "gpio",
|
||||
.owner = THIS_MODULE,
|
||||
|
||||
.class_attrs = gpio_class_attrs,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* gpiod_export - export a GPIO through sysfs
|
||||
* @gpio: gpio to make available, already requested
|
||||
* @direction_may_change: true if userspace may change gpio direction
|
||||
* Context: arch_initcall or later
|
||||
*
|
||||
* When drivers want to make a GPIO accessible to userspace after they
|
||||
* have requested it -- perhaps while debugging, or as part of their
|
||||
* public interface -- they may use this routine. If the GPIO can
|
||||
* change direction (some can't) and the caller allows it, userspace
|
||||
* will see "direction" sysfs attribute which may be used to change
|
||||
* the gpio's direction. A "value" attribute will always be provided.
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
{
|
||||
unsigned long flags;
|
||||
int status;
|
||||
const char *ioname = NULL;
|
||||
struct device *dev;
|
||||
int offset;
|
||||
|
||||
/* can't export until sysfs is available ... */
|
||||
if (!gpio_class.p) {
|
||||
pr_debug("%s: called too early!\n", __func__);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!desc) {
|
||||
pr_debug("%s: invalid gpio descriptor\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
|
||||
test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
|
||||
__func__,
|
||||
test_bit(FLAG_REQUESTED, &desc->flags),
|
||||
test_bit(FLAG_EXPORT, &desc->flags));
|
||||
status = -EPERM;
|
||||
goto fail_unlock;
|
||||
}
|
||||
|
||||
if (!desc->chip->direction_input || !desc->chip->direction_output)
|
||||
direction_may_change = false;
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
offset = gpio_chip_hwgpio(desc);
|
||||
if (desc->chip->names && desc->chip->names[offset])
|
||||
ioname = desc->chip->names[offset];
|
||||
|
||||
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
|
||||
desc, ioname ? ioname : "gpio%u",
|
||||
desc_to_gpio(desc));
|
||||
if (IS_ERR(dev)) {
|
||||
status = PTR_ERR(dev);
|
||||
goto fail_unlock;
|
||||
}
|
||||
|
||||
status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
|
||||
if (status)
|
||||
goto fail_unregister_device;
|
||||
|
||||
if (direction_may_change) {
|
||||
status = device_create_file(dev, &dev_attr_direction);
|
||||
if (status)
|
||||
goto fail_unregister_device;
|
||||
}
|
||||
|
||||
if (gpiod_to_irq(desc) >= 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);
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_export);
|
||||
|
||||
static int match_export(struct device *dev, const void *data)
|
||||
{
|
||||
return dev_get_drvdata(dev) == data;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiod_export_link - create a sysfs link to an exported GPIO node
|
||||
* @dev: device under which to create symlink
|
||||
* @name: name of the symlink
|
||||
* @gpio: gpio to create symlink to, already exported
|
||||
*
|
||||
* Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN
|
||||
* node. Caller is responsible for unlinking.
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
int gpiod_export_link(struct device *dev, const char *name,
|
||||
struct gpio_desc *desc)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
|
||||
if (!desc) {
|
||||
pr_warn("%s: invalid GPIO\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
struct device *tdev;
|
||||
|
||||
tdev = class_find_device(&gpio_class, NULL, desc, match_export);
|
||||
if (tdev != NULL) {
|
||||
status = sysfs_create_link(&dev->kobj, &tdev->kobj,
|
||||
name);
|
||||
} else {
|
||||
status = -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
if (status)
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_export_link);
|
||||
|
||||
/**
|
||||
* gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value
|
||||
* @gpio: gpio to change
|
||||
* @value: non-zero to use active low, i.e. inverted values
|
||||
*
|
||||
* Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute.
|
||||
* The GPIO does not have to be exported yet. If poll(2) support has
|
||||
* been enabled for either rising or falling edge, it will be
|
||||
* reconfigured to follow the new polarity.
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
|
||||
{
|
||||
struct device *dev = NULL;
|
||||
int status = -EINVAL;
|
||||
|
||||
if (!desc) {
|
||||
pr_warn("%s: invalid GPIO\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
dev = class_find_device(&gpio_class, NULL, desc, match_export);
|
||||
if (dev == NULL) {
|
||||
status = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
status = sysfs_set_active_low(desc, dev, value);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
if (status)
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
|
||||
|
||||
/**
|
||||
* gpiod_unexport - reverse effect of gpio_export()
|
||||
* @gpio: gpio to make unavailable
|
||||
*
|
||||
* This is implicit on gpio_free().
|
||||
*/
|
||||
void gpiod_unexport(struct gpio_desc *desc)
|
||||
{
|
||||
int status = 0;
|
||||
struct device *dev = NULL;
|
||||
|
||||
if (!desc) {
|
||||
pr_warn("%s: invalid GPIO\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
|
||||
dev = class_find_device(&gpio_class, NULL, desc, match_export);
|
||||
if (dev) {
|
||||
gpio_setup_irq(desc, dev, 0);
|
||||
clear_bit(FLAG_EXPORT, &desc->flags);
|
||||
} else
|
||||
status = -ENODEV;
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
if (dev) {
|
||||
device_unregister(dev);
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
if (status)
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_unexport);
|
||||
|
||||
int gpiochip_export(struct gpio_chip *chip)
|
||||
{
|
||||
int status;
|
||||
struct device *dev;
|
||||
|
||||
/* Many systems register gpio chips for SOC support very early,
|
||||
* before driver model support is available. In those cases we
|
||||
* export this later, in gpiolib_sysfs_init() ... here we just
|
||||
* verify that _some_ field of gpio_class got initialized.
|
||||
*/
|
||||
if (!gpio_class.p)
|
||||
return 0;
|
||||
|
||||
/* use chip->base for the ID; it's already known to be unique */
|
||||
mutex_lock(&sysfs_lock);
|
||||
dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,
|
||||
"gpiochip%d", chip->base);
|
||||
if (!IS_ERR(dev)) {
|
||||
status = sysfs_create_group(&dev->kobj,
|
||||
&gpiochip_attr_group);
|
||||
} else
|
||||
status = PTR_ERR(dev);
|
||||
chip->exported = (status == 0);
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
if (status)
|
||||
chip_dbg(chip, "%s: status %d\n", __func__, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void gpiochip_unexport(struct gpio_chip *chip)
|
||||
{
|
||||
int status;
|
||||
struct device *dev;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
dev = class_find_device(&gpio_class, NULL, chip, match_export);
|
||||
if (dev) {
|
||||
put_device(dev);
|
||||
device_unregister(dev);
|
||||
chip->exported = false;
|
||||
status = 0;
|
||||
} else
|
||||
status = -ENODEV;
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
if (status)
|
||||
chip_dbg(chip, "%s: status %d\n", __func__, status);
|
||||
}
|
||||
|
||||
static int __init gpiolib_sysfs_init(void)
|
||||
{
|
||||
int status;
|
||||
unsigned long flags;
|
||||
struct gpio_chip *chip;
|
||||
|
||||
status = class_register(&gpio_class);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
/* Scan and register the gpio_chips which registered very
|
||||
* early (e.g. before the class_register above was called).
|
||||
*
|
||||
* We run before arch_initcall() so chip->dev nodes can have
|
||||
* registered, and so arch_initcall() can always gpio_export().
|
||||
*/
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
list_for_each_entry(chip, &gpio_chips, list) {
|
||||
if (chip->exported)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* TODO we yield gpio_lock here because gpiochip_export()
|
||||
* acquires a mutex. This is unsafe and needs to be fixed.
|
||||
*
|
||||
* Also it would be nice to use gpiochip_find() here so we
|
||||
* can keep gpio_chips local to gpiolib.c, but the yield of
|
||||
* gpio_lock prevents us from doing this.
|
||||
*/
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
status = gpiochip_export(chip);
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
postcore_initcall(gpiolib_sysfs_init);
|
File diff suppressed because it is too large
Load diff
|
@ -31,12 +31,21 @@ struct acpi_gpio_info {
|
|||
void acpi_gpiochip_add(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_remove(struct gpio_chip *chip);
|
||||
|
||||
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
|
||||
|
||||
struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
|
||||
struct acpi_gpio_info *info);
|
||||
#else
|
||||
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
|
||||
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
|
||||
|
||||
static inline void
|
||||
acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
|
||||
|
||||
static inline void
|
||||
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
|
||||
|
||||
static inline struct gpio_desc *
|
||||
acpi_get_gpiod_by_index(struct device *dev, int index,
|
||||
struct acpi_gpio_info *info)
|
||||
|
@ -45,10 +54,100 @@ acpi_get_gpiod_by_index(struct device *dev, int index,
|
|||
}
|
||||
#endif
|
||||
|
||||
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label);
|
||||
void gpiochip_free_own_desc(struct gpio_desc *desc);
|
||||
|
||||
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
||||
const char *list_name, int index, enum of_gpio_flags *flags);
|
||||
|
||||
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
|
||||
|
||||
extern struct spinlock gpio_lock;
|
||||
extern struct list_head gpio_chips;
|
||||
|
||||
struct gpio_desc {
|
||||
struct gpio_chip *chip;
|
||||
unsigned long flags;
|
||||
/* flag symbols are bit numbers */
|
||||
#define FLAG_REQUESTED 0
|
||||
#define FLAG_IS_OUT 1
|
||||
#define FLAG_EXPORT 2 /* protected by sysfs_lock */
|
||||
#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
|
||||
#define FLAG_TRIG_FALL 4 /* trigger on falling edge */
|
||||
#define FLAG_TRIG_RISE 5 /* trigger on rising edge */
|
||||
#define FLAG_ACTIVE_LOW 6 /* value has active low */
|
||||
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
|
||||
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
|
||||
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
|
||||
|
||||
#define ID_SHIFT 16 /* add new flags before this one */
|
||||
|
||||
#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
|
||||
#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
|
||||
|
||||
const char *label;
|
||||
};
|
||||
|
||||
int gpiod_request(struct gpio_desc *desc, const char *label);
|
||||
void gpiod_free(struct gpio_desc *desc);
|
||||
|
||||
/*
|
||||
* Return the GPIO number of the passed descriptor relative to its chip
|
||||
*/
|
||||
static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
|
||||
{
|
||||
return desc - &desc->chip->desc[0];
|
||||
}
|
||||
|
||||
/* With descriptor prefix */
|
||||
|
||||
#define gpiod_emerg(desc, fmt, ...) \
|
||||
pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
|
||||
##__VA_ARGS__)
|
||||
#define gpiod_crit(desc, fmt, ...) \
|
||||
pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
|
||||
##__VA_ARGS__)
|
||||
#define gpiod_err(desc, fmt, ...) \
|
||||
pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
|
||||
##__VA_ARGS__)
|
||||
#define gpiod_warn(desc, fmt, ...) \
|
||||
pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
|
||||
##__VA_ARGS__)
|
||||
#define gpiod_info(desc, fmt, ...) \
|
||||
pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
|
||||
##__VA_ARGS__)
|
||||
#define gpiod_dbg(desc, fmt, ...) \
|
||||
pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
|
||||
##__VA_ARGS__)
|
||||
|
||||
/* With chip prefix */
|
||||
|
||||
#define chip_emerg(chip, fmt, ...) \
|
||||
pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
|
||||
#define chip_crit(chip, fmt, ...) \
|
||||
pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
|
||||
#define chip_err(chip, fmt, ...) \
|
||||
pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
|
||||
#define chip_warn(chip, fmt, ...) \
|
||||
pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
|
||||
#define chip_info(chip, fmt, ...) \
|
||||
pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
|
||||
#define chip_dbg(chip, fmt, ...) \
|
||||
pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
|
||||
|
||||
#ifdef CONFIG_GPIO_SYSFS
|
||||
|
||||
int gpiochip_export(struct gpio_chip *chip);
|
||||
void gpiochip_unexport(struct gpio_chip *chip);
|
||||
|
||||
#else
|
||||
|
||||
static inline int gpiochip_export(struct gpio_chip *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void gpiochip_unexport(struct gpio_chip *chip)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIO_SYSFS */
|
||||
|
||||
#endif /* GPIOLIB_H */
|
||||
|
|
|
@ -110,9 +110,6 @@ static inline int __gpio_to_irq(unsigned gpio)
|
|||
return gpiod_to_irq(gpio_to_desc(gpio));
|
||||
}
|
||||
|
||||
extern int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
extern void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
|
||||
extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
|
||||
extern int gpio_request_array(const struct gpio *array, size_t num);
|
||||
extern void gpio_free_array(const struct gpio *array, size_t num);
|
||||
|
|
|
@ -18,30 +18,79 @@ struct gpio_desc;
|
|||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
#define GPIOD_FLAGS_BIT_DIR_SET BIT(0)
|
||||
#define GPIOD_FLAGS_BIT_DIR_OUT BIT(1)
|
||||
#define GPIOD_FLAGS_BIT_DIR_VAL BIT(2)
|
||||
|
||||
/**
|
||||
* Optional flags that can be passed to one of gpiod_* to configure direction
|
||||
* and output value. These values cannot be OR'd.
|
||||
*/
|
||||
enum gpiod_flags {
|
||||
GPIOD_ASIS = 0,
|
||||
GPIOD_IN = GPIOD_FLAGS_BIT_DIR_SET,
|
||||
GPIOD_OUT_LOW = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT,
|
||||
GPIOD_OUT_HIGH = GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT |
|
||||
GPIOD_FLAGS_BIT_DIR_VAL,
|
||||
};
|
||||
|
||||
/* Acquire and dispose GPIOs */
|
||||
struct gpio_desc *__must_check gpiod_get(struct device *dev,
|
||||
const char *con_id);
|
||||
struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
||||
struct gpio_desc *__must_check __gpiod_get(struct device *dev,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags);
|
||||
#define __gpiod_get(dev, con_id, flags, ...) __gpiod_get(dev, con_id, flags)
|
||||
#define gpiod_get(varargs...) __gpiod_get(varargs, 0)
|
||||
struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx);
|
||||
struct gpio_desc *__must_check gpiod_get_optional(struct device *dev,
|
||||
const char *con_id);
|
||||
struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev,
|
||||
unsigned int idx,
|
||||
enum gpiod_flags flags);
|
||||
#define __gpiod_get_index(dev, con_id, index, flags, ...) \
|
||||
__gpiod_get_index(dev, con_id, index, flags)
|
||||
#define gpiod_get_index(varargs...) __gpiod_get_index(varargs, 0)
|
||||
struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags);
|
||||
#define __gpiod_get_optional(dev, con_id, flags, ...) \
|
||||
__gpiod_get_optional(dev, con_id, flags)
|
||||
#define gpiod_get_optional(varargs...) __gpiod_get_optional(varargs, 0)
|
||||
struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int index);
|
||||
unsigned int index,
|
||||
enum gpiod_flags flags);
|
||||
#define __gpiod_get_index_optional(dev, con_id, index, flags, ...) \
|
||||
__gpiod_get_index_optional(dev, con_id, index, flags)
|
||||
#define gpiod_get_index_optional(varargs...) \
|
||||
__gpiod_get_index_optional(varargs, 0)
|
||||
|
||||
void gpiod_put(struct gpio_desc *desc);
|
||||
|
||||
struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
|
||||
const char *con_id);
|
||||
struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
|
||||
struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags);
|
||||
#define __devm_gpiod_get(dev, con_id, flags, ...) \
|
||||
__devm_gpiod_get(dev, con_id, flags)
|
||||
#define devm_gpiod_get(varargs...) __devm_gpiod_get(varargs, 0)
|
||||
struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
|
||||
const char *con_id,
|
||||
unsigned int idx);
|
||||
struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
|
||||
const char *con_id);
|
||||
unsigned int idx,
|
||||
enum gpiod_flags flags);
|
||||
#define __devm_gpiod_get_index(dev, con_id, index, flags, ...) \
|
||||
__devm_gpiod_get_index(dev, con_id, index, flags)
|
||||
#define devm_gpiod_get_index(varargs...) __devm_gpiod_get_index(varargs, 0)
|
||||
struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags);
|
||||
#define __devm_gpiod_get_optional(dev, con_id, flags, ...) \
|
||||
__devm_gpiod_get_optional(dev, con_id, flags)
|
||||
#define devm_gpiod_get_optional(varargs...) \
|
||||
__devm_gpiod_get_optional(varargs, 0)
|
||||
struct gpio_desc *__must_check
|
||||
devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
|
||||
unsigned int index);
|
||||
__devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
|
||||
unsigned int index, enum gpiod_flags flags);
|
||||
#define __devm_gpiod_get_index_optional(dev, con_id, index, flags, ...) \
|
||||
__devm_gpiod_get_index_optional(dev, con_id, index, flags)
|
||||
#define devm_gpiod_get_index_optional(varargs...) \
|
||||
__devm_gpiod_get_index_optional(varargs, 0)
|
||||
|
||||
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
|
||||
|
||||
|
|
|
@ -141,73 +141,16 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
|
|||
|
||||
/* add/remove chips */
|
||||
extern int gpiochip_add(struct gpio_chip *chip);
|
||||
extern int __must_check gpiochip_remove(struct gpio_chip *chip);
|
||||
extern int gpiochip_remove(struct gpio_chip *chip);
|
||||
extern struct gpio_chip *gpiochip_find(void *data,
|
||||
int (*match)(struct gpio_chip *chip, void *data));
|
||||
|
||||
/* lock/unlock as IRQ */
|
||||
int gpiod_lock_as_irq(struct gpio_desc *desc);
|
||||
void gpiod_unlock_as_irq(struct gpio_desc *desc);
|
||||
int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
|
||||
|
||||
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
|
||||
|
||||
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
|
||||
u16 hwnum);
|
||||
|
||||
enum gpio_lookup_flags {
|
||||
GPIO_ACTIVE_HIGH = (0 << 0),
|
||||
GPIO_ACTIVE_LOW = (1 << 0),
|
||||
GPIO_OPEN_DRAIN = (1 << 1),
|
||||
GPIO_OPEN_SOURCE = (1 << 2),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct gpiod_lookup - lookup table
|
||||
* @chip_label: name of the chip the GPIO belongs to
|
||||
* @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO
|
||||
* @con_id: name of the GPIO from the device's point of view
|
||||
* @idx: index of the GPIO in case several GPIOs share the same name
|
||||
* @flags: mask of GPIO_* values
|
||||
*
|
||||
* gpiod_lookup is a lookup table for associating GPIOs to specific devices and
|
||||
* functions using platform data.
|
||||
*/
|
||||
struct gpiod_lookup {
|
||||
const char *chip_label;
|
||||
u16 chip_hwnum;
|
||||
const char *con_id;
|
||||
unsigned int idx;
|
||||
enum gpio_lookup_flags flags;
|
||||
};
|
||||
|
||||
struct gpiod_lookup_table {
|
||||
struct list_head list;
|
||||
const char *dev_id;
|
||||
struct gpiod_lookup table[];
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple definition of a single GPIO under a con_id
|
||||
*/
|
||||
#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \
|
||||
GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags)
|
||||
|
||||
/*
|
||||
* Use this macro if you need to have several GPIOs under the same con_id.
|
||||
* Each GPIO needs to use a different index and can be accessed using
|
||||
* gpiod_get_index()
|
||||
*/
|
||||
#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags) \
|
||||
{ \
|
||||
.chip_label = _chip_label, \
|
||||
.chip_hwnum = _chip_hwnum, \
|
||||
.con_id = _con_id, \
|
||||
.idx = _idx, \
|
||||
.flags = _flags, \
|
||||
}
|
||||
|
||||
void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||
|
||||
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||
|
@ -223,6 +166,9 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
|
|||
|
||||
#endif /* CONFIG_GPIO_IRQCHIP */
|
||||
|
||||
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label);
|
||||
void gpiochip_free_own_desc(struct gpio_desc *desc);
|
||||
|
||||
#else /* CONFIG_GPIOLIB */
|
||||
|
||||
static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
|
||||
|
|
61
include/linux/gpio/machine.h
Normal file
61
include/linux/gpio/machine.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#ifndef __LINUX_GPIO_MACHINE_H
|
||||
#define __LINUX_GPIO_MACHINE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
enum gpio_lookup_flags {
|
||||
GPIO_ACTIVE_HIGH = (0 << 0),
|
||||
GPIO_ACTIVE_LOW = (1 << 0),
|
||||
GPIO_OPEN_DRAIN = (1 << 1),
|
||||
GPIO_OPEN_SOURCE = (1 << 2),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct gpiod_lookup - lookup table
|
||||
* @chip_label: name of the chip the GPIO belongs to
|
||||
* @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO
|
||||
* @con_id: name of the GPIO from the device's point of view
|
||||
* @idx: index of the GPIO in case several GPIOs share the same name
|
||||
* @flags: mask of GPIO_* values
|
||||
*
|
||||
* gpiod_lookup is a lookup table for associating GPIOs to specific devices and
|
||||
* functions using platform data.
|
||||
*/
|
||||
struct gpiod_lookup {
|
||||
const char *chip_label;
|
||||
u16 chip_hwnum;
|
||||
const char *con_id;
|
||||
unsigned int idx;
|
||||
enum gpio_lookup_flags flags;
|
||||
};
|
||||
|
||||
struct gpiod_lookup_table {
|
||||
struct list_head list;
|
||||
const char *dev_id;
|
||||
struct gpiod_lookup table[];
|
||||
};
|
||||
|
||||
/*
|
||||
* Simple definition of a single GPIO under a con_id
|
||||
*/
|
||||
#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \
|
||||
GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags)
|
||||
|
||||
/*
|
||||
* Use this macro if you need to have several GPIOs under the same con_id.
|
||||
* Each GPIO needs to use a different index and can be accessed using
|
||||
* gpiod_get_index()
|
||||
*/
|
||||
#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags) \
|
||||
{ \
|
||||
.chip_label = _chip_label, \
|
||||
.chip_hwnum = _chip_hwnum, \
|
||||
.con_id = _con_id, \
|
||||
.idx = _idx, \
|
||||
.flags = _flags, \
|
||||
}
|
||||
|
||||
void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
|
||||
|
||||
#endif /* __LINUX_GPIO_MACHINE_H */
|
Loading…
Reference in a new issue