mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 18:39:59 +00:00
This is the bulk of GPIO changes for the v4.18 development
cycle. Core changes: - We have killed off VLA from the core library and all drivers. The background should be clear for everyone at this point: https://lwn.net/Articles/749064/ Also I just don't like VLA's, kernel developers hate it when compilers do things behind their back. It's as simple as that. I'm sorry that they even slipped in to begin with. Kudos to Laura Abbott for exorcising them. - Support GPIO hogs in machines/board files. New drivers and chip support: - R-Car r8a77470 (RZ/G1C) - R-Car r8a77965 (M3-N) - R-Car r8a77990 (E3) - PCA953x driver improvements to accomodate more variants. Improvements and new features: - Support one interrupt per line on port A in the DesignWare dwapb driver. Misc: - Random cleanups, right header files in the drivers, some size optimizations etc. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJbGOMeAAoJEEEQszewGV1zGR0P/Rq/Mh6BRum7kZee8v22aKJE imtSamaVk7eOSdLC00VLvJ5QYJBMWz2GV5ZJkaxAwHBh1GhfddTDj35uXoOkRRWs vRXSYthujluGJ5YYfRNrXZhD4ahVYPnJV5XxLy4OF+aQBAd4jjRAqXLhQT1PVK9Q AQD/BOjToxrjgPREaLX9sQTW8DbICmjRhEWieJoQab2mZC+qD/aCen0rkj+UD0Qu wQRk5mSEsrC0qmWNS/rhzFa7/nRa4qWOMkHxim7/GqwGzgOTpv+TctmQOqMUjHqq k0ikVgBfZbaz3MqcuqLbKJ00mRK6G/yQIlECP4xcMbxKRxXucJj1ytOedIdG4nJE 5porXbW1d1bIhv3Zv8tt7vh00x+mEF+hv6p8DUa9ppe7qwsdbhUdzeczeyR8eM7U ZBi80jMJfp9wEugZ0F8syIUs3PPgp7y461hJDbZRuHp4P4jmpdUBMAF4XvWl6XPy DAlPHnSc2ZNaqWJtfc1ja4e6DlwltEV81Sd9Y0clLhkD95k95gZ7EzoyGPAIO4FG ir0getZE1mfh9K/EfkTOkcKHJh3b5rA5TiSbTVVaPO9SzqPtIK+xhDJI0r9IJkW1 XKgScOaJqpYEe2Y/Y/ezfnjxDLVxwOz6R77GsZCle1uPevOcxqN9fmjEn7gGYzmX PDf5pOuRrWApqix4a3Jr =Ly/0 -----END PGP SIGNATURE----- Merge tag 'gpio-v4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO updates from Linus Walleij: "This is the bulk of GPIO changes for the v4.18 development cycle. Core changes: - We have killed off VLA from the core library and all drivers. The background should be clear for everyone at this point: https://lwn.net/Articles/749064/ Also I just don't like VLA's, kernel developers hate it when compilers do things behind their back. It's as simple as that. I'm sorry that they even slipped in to begin with. Kudos to Laura Abbott for exorcising them. - Support GPIO hogs in machines/board files. New drivers and chip support: - R-Car r8a77470 (RZ/G1C) - R-Car r8a77965 (M3-N) - R-Car r8a77990 (E3) - PCA953x driver improvements to accomodate more variants. Improvements and new features: - Support one interrupt per line on port A in the DesignWare dwapb driver. Misc: - Random cleanups, right header files in the drivers, some size optimizations etc" * tag 'gpio-v4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (73 commits) gpio: davinci: fix build warning when !CONFIG_OF gpio: dwapb: Fix rework support for 1 interrupt per port A GPIO gpio: pxa: Include the right header gpio: pl061: Include the right header gpio: pch: Include the right header gpio: pcf857x: Include the right header gpio: pca953x: Include the right header gpio: palmas: Include the right header gpio: omap: Include the right header gpio: octeon: Include the right header gpio: mxs: Switch to SPDX identifier gpio: Remove VLA from stmpe driver gpio: mxc: Switch to SPDX identifier gpio: mxc: add clock operation gpio: Remove VLA from gpiolib gpio: aspeed: Use a cache of output data registers gpio: aspeed: Set output latch before changing direction gpio: pca953x: fix address calculation for pcal6524 gpio: pca953x: define masks for addressing common and extended registers gpio: pca953x: set the PCA_PCAL flag also when matching by DT ...
This commit is contained in:
commit
ea125dedbc
54 changed files with 643 additions and 289 deletions
|
@ -31,10 +31,15 @@ Required properties:
|
||||||
ti,tca9554
|
ti,tca9554
|
||||||
onnn,pca9654
|
onnn,pca9654
|
||||||
exar,xra1202
|
exar,xra1202
|
||||||
|
- gpio-controller: if used as gpio expander.
|
||||||
|
- #gpio-cells: if used as gpio expander.
|
||||||
|
- interrupt-controller: if to be used as interrupt expander.
|
||||||
|
- #interrupt-cells: if to be used as interrupt expander.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- reset-gpios: GPIO specification for the RESET input. This is an
|
- reset-gpios: GPIO specification for the RESET input. This is an
|
||||||
active low signal to the PCA953x.
|
active low signal to the PCA953x.
|
||||||
|
- vcc-supply: power supply regulator.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -47,3 +52,32 @@ Example:
|
||||||
interrupt-parent = <&gpio3>;
|
interrupt-parent = <&gpio3>;
|
||||||
interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
|
interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Example with Interrupts:
|
||||||
|
|
||||||
|
|
||||||
|
gpio99: gpio@22 {
|
||||||
|
compatible = "nxp,pcal6524";
|
||||||
|
reg = <0x22>;
|
||||||
|
interrupt-parent = <&gpio6>;
|
||||||
|
interrupts = <1 IRQ_TYPE_EDGE_FALLING>; /* gpio6_161 */
|
||||||
|
interrupt-controller;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
vcc-supply = <&vdds_1v8_main>;
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
gpio-line-names =
|
||||||
|
"hdmi-ct-hpd", "hdmi.ls-oe", "p02", "p03", "vibra", "fault2", "p06", "p07",
|
||||||
|
"en-usb", "en-host1", "en-host2", "chg-int", "p14", "p15", "mic-int", "en-modem",
|
||||||
|
"shdn-hs-amp", "chg-status+red", "green", "blue", "en-esata", "fault1", "p26", "p27";
|
||||||
|
};
|
||||||
|
|
||||||
|
ts3a227@3b {
|
||||||
|
compatible = "ti,ts3a227e";
|
||||||
|
reg = <0x3b>;
|
||||||
|
interrupt-parent = <&gpio99>;
|
||||||
|
interrupts = <14 IRQ_TYPE_EDGE_RISING>;
|
||||||
|
ti,micbias = <0>; /* 2.1V */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ Required Properties:
|
||||||
- compatible: should contain one or more of the following:
|
- compatible: should contain one or more of the following:
|
||||||
- "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller.
|
- "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller.
|
||||||
- "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
|
- "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
|
||||||
|
- "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller.
|
||||||
- "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller.
|
- "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller.
|
||||||
- "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
|
- "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
|
||||||
- "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
|
- "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
|
||||||
|
@ -14,7 +15,9 @@ Required Properties:
|
||||||
- "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller.
|
- "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller.
|
||||||
- "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller.
|
- "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller.
|
||||||
- "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller.
|
- "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller.
|
||||||
|
- "renesas,gpio-r8a77965": for R8A77965 (R-Car M3-N) compatible GPIO controller.
|
||||||
- "renesas,gpio-r8a77970": for R8A77970 (R-Car V3M) compatible GPIO controller.
|
- "renesas,gpio-r8a77970": for R8A77970 (R-Car V3M) compatible GPIO controller.
|
||||||
|
- "renesas,gpio-r8a77990": for R8A77990 (R-Car E3) compatible GPIO controller.
|
||||||
- "renesas,gpio-r8a77995": for R8A77995 (R-Car D3) compatible GPIO controller.
|
- "renesas,gpio-r8a77995": for R8A77995 (R-Car D3) compatible GPIO controller.
|
||||||
- "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller.
|
- "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller.
|
||||||
- "renesas,rcar-gen2-gpio": for a generic R-Car Gen2 or RZ/G1 GPIO controller.
|
- "renesas,rcar-gen2-gpio": for a generic R-Car Gen2 or RZ/G1 GPIO controller.
|
||||||
|
|
|
@ -26,8 +26,13 @@ controller.
|
||||||
the second encodes the triger flags encoded as described in
|
the second encodes the triger flags encoded as described in
|
||||||
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||||
- interrupt-parent : The parent interrupt controller.
|
- interrupt-parent : The parent interrupt controller.
|
||||||
- interrupts : The interrupt to the parent controller raised when GPIOs
|
- interrupts : The interrupts to the parent controller raised when GPIOs
|
||||||
generate the interrupts.
|
generate the interrupts. If the controller provides one combined interrupt
|
||||||
|
for all GPIOs, specify a single interrupt. If the controller provides one
|
||||||
|
interrupt for each GPIO, provide a list of interrupts that correspond to each
|
||||||
|
of the GPIO pins. When specifying multiple interrupts, if any are unconnected,
|
||||||
|
use the interrupts-extended property to specify the interrupts and set the
|
||||||
|
interrupt controller handle for unused interrupts to 0.
|
||||||
- snps,nr-gpios : The number of pins in the port, a single cell.
|
- snps,nr-gpios : The number of pins in the port, a single cell.
|
||||||
- resets : Reset line for the controller.
|
- resets : Reset line for the controller.
|
||||||
|
|
||||||
|
|
|
@ -177,3 +177,19 @@ mapping and is thus transparent to GPIO consumers.
|
||||||
|
|
||||||
A set of functions such as gpiod_set_value() is available to work with
|
A set of functions such as gpiod_set_value() is available to work with
|
||||||
the new descriptor-oriented interface.
|
the new descriptor-oriented interface.
|
||||||
|
|
||||||
|
Boards using platform data can also hog GPIO lines by defining GPIO hog tables.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
struct gpiod_hog gpio_hog_table[] = {
|
||||||
|
GPIO_HOG("gpio.0", 10, "foo", GPIO_ACTIVE_LOW, GPIOD_OUT_HIGH),
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
And the table can be added to the board code as follows::
|
||||||
|
|
||||||
|
gpiod_add_hogs(gpio_hog_table);
|
||||||
|
|
||||||
|
The line will be hogged as soon as the gpiochip is created or - in case the
|
||||||
|
chip was created earlier - when the hog table is registered.
|
||||||
|
|
|
@ -85,6 +85,10 @@ hardware descriptions such as device tree or ACPI:
|
||||||
any other serio bus to the system and makes it possible to connect drivers
|
any other serio bus to the system and makes it possible to connect drivers
|
||||||
for e.g. keyboards and other PS/2 protocol based devices.
|
for e.g. keyboards and other PS/2 protocol based devices.
|
||||||
|
|
||||||
|
- cec-gpio: drivers/media/platform/cec-gpio/ is used to interact with a CEC
|
||||||
|
Consumer Electronics Control bus using only GPIO. It is used to communicate
|
||||||
|
with devices on the HDMI bus.
|
||||||
|
|
||||||
Apart from this there are special GPIO drivers in subsystems like MMC/SD to
|
Apart from this there are special GPIO drivers in subsystems like MMC/SD to
|
||||||
read card detect and write protect GPIO lines, and in the TTY serial subsystem
|
read card detect and write protect GPIO lines, and in the TTY serial subsystem
|
||||||
to emulate MCTRL (modem control) signals CTS/RTS by using two GPIO lines. The
|
to emulate MCTRL (modem control) signals CTS/RTS by using two GPIO lines. The
|
||||||
|
|
|
@ -22,6 +22,18 @@ menuconfig GPIOLIB
|
||||||
|
|
||||||
if GPIOLIB
|
if GPIOLIB
|
||||||
|
|
||||||
|
config GPIOLIB_FASTPATH_LIMIT
|
||||||
|
int "Maximum number of GPIOs for fast path"
|
||||||
|
range 32 512
|
||||||
|
default 512
|
||||||
|
help
|
||||||
|
This adjusts the point at which certain APIs will switch from
|
||||||
|
using a stack allocated buffer to a dynamically allocated buffer.
|
||||||
|
|
||||||
|
You shouldn't need to change this unless you really need to
|
||||||
|
optimize either stack space or performance. Change this carefully
|
||||||
|
since setting an incorrect value could cause stack corruption.
|
||||||
|
|
||||||
config OF_GPIO
|
config OF_GPIO
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on OF
|
depends on OF
|
||||||
|
|
|
@ -188,7 +188,7 @@ static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||||
{
|
{
|
||||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||||
size_t i;
|
size_t i;
|
||||||
const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
|
static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
|
||||||
const unsigned int gpio_reg_size = 8;
|
const unsigned int gpio_reg_size = 8;
|
||||||
unsigned int bits_offset;
|
unsigned int bits_offset;
|
||||||
size_t word_index;
|
size_t word_index;
|
||||||
|
|
|
@ -94,7 +94,7 @@ static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||||
{
|
{
|
||||||
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
|
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
|
||||||
size_t i;
|
size_t i;
|
||||||
const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
|
static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
|
||||||
const unsigned int gpio_reg_size = 8;
|
const unsigned int gpio_reg_size = 8;
|
||||||
unsigned int bits_offset;
|
unsigned int bits_offset;
|
||||||
size_t word_index;
|
size_t word_index;
|
||||||
|
|
|
@ -105,27 +105,22 @@ static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||||
|
|
||||||
static int mmio_74xx_gpio_probe(struct platform_device *pdev)
|
static int mmio_74xx_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const struct of_device_id *of_id;
|
|
||||||
struct mmio_74xx_gpio_priv *priv;
|
struct mmio_74xx_gpio_priv *priv;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
void __iomem *dat;
|
void __iomem *dat;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
of_id = of_match_device(mmio_74xx_gpio_ids, &pdev->dev);
|
|
||||||
if (!of_id)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->flags = (uintptr_t)of_device_get_match_data(&pdev->dev);
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
dat = devm_ioremap_resource(&pdev->dev, res);
|
dat = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(dat))
|
if (IS_ERR(dat))
|
||||||
return PTR_ERR(dat);
|
return PTR_ERR(dat);
|
||||||
|
|
||||||
priv->flags = (uintptr_t) of_id->data;
|
|
||||||
|
|
||||||
err = bgpio_init(&priv->gc, &pdev->dev,
|
err = bgpio_init(&priv->gc, &pdev->dev,
|
||||||
DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8),
|
DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8),
|
||||||
dat, NULL, NULL, NULL, NULL, 0);
|
dat, NULL, NULL, NULL, NULL, 0);
|
||||||
|
|
|
@ -54,6 +54,8 @@ struct aspeed_gpio {
|
||||||
u8 *offset_timer;
|
u8 *offset_timer;
|
||||||
unsigned int timer_users[4];
|
unsigned int timer_users[4];
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
|
||||||
|
u32 *dcache;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct aspeed_gpio_bank {
|
struct aspeed_gpio_bank {
|
||||||
|
@ -231,12 +233,13 @@ static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
addr = bank_val_reg(gpio, bank, GPIO_DATA);
|
addr = bank_val_reg(gpio, bank, GPIO_DATA);
|
||||||
reg = ioread32(addr);
|
reg = gpio->dcache[GPIO_BANK(offset)];
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
reg |= GPIO_BIT(offset);
|
reg |= GPIO_BIT(offset);
|
||||||
else
|
else
|
||||||
reg &= ~GPIO_BIT(offset);
|
reg &= ~GPIO_BIT(offset);
|
||||||
|
gpio->dcache[GPIO_BANK(offset)] = reg;
|
||||||
|
|
||||||
iowrite32(reg, addr);
|
iowrite32(reg, addr);
|
||||||
}
|
}
|
||||||
|
@ -287,11 +290,10 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc,
|
||||||
|
|
||||||
spin_lock_irqsave(&gpio->lock, flags);
|
spin_lock_irqsave(&gpio->lock, flags);
|
||||||
|
|
||||||
|
__aspeed_gpio_set(gc, offset, val);
|
||||||
reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR));
|
reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR));
|
||||||
iowrite32(reg | GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR));
|
iowrite32(reg | GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR));
|
||||||
|
|
||||||
__aspeed_gpio_set(gc, offset, val);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&gpio->lock, flags);
|
spin_unlock_irqrestore(&gpio->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -852,7 +854,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
||||||
const struct of_device_id *gpio_id;
|
const struct of_device_id *gpio_id;
|
||||||
struct aspeed_gpio *gpio;
|
struct aspeed_gpio *gpio;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int rc;
|
int rc, i, banks;
|
||||||
|
|
||||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||||
if (!gpio)
|
if (!gpio)
|
||||||
|
@ -893,6 +895,20 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
||||||
gpio->chip.base = -1;
|
gpio->chip.base = -1;
|
||||||
gpio->chip.irq.need_valid_mask = true;
|
gpio->chip.irq.need_valid_mask = true;
|
||||||
|
|
||||||
|
/* Allocate a cache of the output registers */
|
||||||
|
banks = gpio->config->nr_gpios >> 5;
|
||||||
|
gpio->dcache = devm_kzalloc(&pdev->dev,
|
||||||
|
sizeof(u32) * banks, GFP_KERNEL);
|
||||||
|
if (!gpio->dcache)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* Populate it with initial values read from the HW */
|
||||||
|
for (i = 0; i < banks; i++) {
|
||||||
|
const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i];
|
||||||
|
gpio->dcache[i] = ioread32(gpio->base + bank->val_regs +
|
||||||
|
GPIO_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
|
rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -610,14 +610,12 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_OF)
|
|
||||||
static const struct of_device_id davinci_gpio_ids[] = {
|
static const struct of_device_id davinci_gpio_ids[] = {
|
||||||
{ .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
|
{ .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
|
||||||
{ .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip},
|
{ .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip},
|
||||||
{ /* sentinel */ },
|
{ /* sentinel */ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, davinci_gpio_ids);
|
MODULE_DEVICE_TABLE(of, davinci_gpio_ids);
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct platform_driver davinci_gpio_driver = {
|
static struct platform_driver davinci_gpio_driver = {
|
||||||
.probe = davinci_gpio_probe,
|
.probe = davinci_gpio_probe,
|
||||||
|
|
|
@ -441,14 +441,19 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
|
||||||
irq_gc->chip_types[1].handler = handle_edge_irq;
|
irq_gc->chip_types[1].handler = handle_edge_irq;
|
||||||
|
|
||||||
if (!pp->irq_shared) {
|
if (!pp->irq_shared) {
|
||||||
irq_set_chained_handler_and_data(pp->irq, dwapb_irq_handler,
|
int i;
|
||||||
gpio);
|
|
||||||
|
for (i = 0; i < pp->ngpio; i++) {
|
||||||
|
if (pp->irq[i] >= 0)
|
||||||
|
irq_set_chained_handler_and_data(pp->irq[i],
|
||||||
|
dwapb_irq_handler, gpio);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Request a shared IRQ since where MFD would have devices
|
* Request a shared IRQ since where MFD would have devices
|
||||||
* using the same irq pin
|
* using the same irq pin
|
||||||
*/
|
*/
|
||||||
err = devm_request_irq(gpio->dev, pp->irq,
|
err = devm_request_irq(gpio->dev, pp->irq[0],
|
||||||
dwapb_irq_handler_mfd,
|
dwapb_irq_handler_mfd,
|
||||||
IRQF_SHARED, "gpio-dwapb-mfd", gpio);
|
IRQF_SHARED, "gpio-dwapb-mfd", gpio);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -524,7 +529,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
|
||||||
if (pp->idx == 0)
|
if (pp->idx == 0)
|
||||||
port->gc.set_config = dwapb_gpio_set_config;
|
port->gc.set_config = dwapb_gpio_set_config;
|
||||||
|
|
||||||
if (pp->irq)
|
if (pp->has_irq)
|
||||||
dwapb_configure_irqs(gpio, port, pp);
|
dwapb_configure_irqs(gpio, port, pp);
|
||||||
|
|
||||||
err = gpiochip_add_data(&port->gc, port);
|
err = gpiochip_add_data(&port->gc, port);
|
||||||
|
@ -535,7 +540,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
|
||||||
port->is_registered = true;
|
port->is_registered = true;
|
||||||
|
|
||||||
/* Add GPIO-signaled ACPI event support */
|
/* Add GPIO-signaled ACPI event support */
|
||||||
if (pp->irq)
|
if (pp->has_irq)
|
||||||
acpi_gpiochip_request_interrupts(&port->gc);
|
acpi_gpiochip_request_interrupts(&port->gc);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -557,7 +562,7 @@ dwapb_gpio_get_pdata(struct device *dev)
|
||||||
struct dwapb_platform_data *pdata;
|
struct dwapb_platform_data *pdata;
|
||||||
struct dwapb_port_property *pp;
|
struct dwapb_port_property *pp;
|
||||||
int nports;
|
int nports;
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
nports = device_get_child_node_count(dev);
|
nports = device_get_child_node_count(dev);
|
||||||
if (nports == 0)
|
if (nports == 0)
|
||||||
|
@ -575,6 +580,8 @@ dwapb_gpio_get_pdata(struct device *dev)
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
device_for_each_child_node(dev, fwnode) {
|
device_for_each_child_node(dev, fwnode) {
|
||||||
|
struct device_node *np = NULL;
|
||||||
|
|
||||||
pp = &pdata->properties[i++];
|
pp = &pdata->properties[i++];
|
||||||
pp->fwnode = fwnode;
|
pp->fwnode = fwnode;
|
||||||
|
|
||||||
|
@ -594,23 +601,35 @@ dwapb_gpio_get_pdata(struct device *dev)
|
||||||
pp->ngpio = 32;
|
pp->ngpio = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp->irq_shared = false;
|
||||||
|
pp->gpio_base = -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only port A can provide interrupts in all configurations of
|
* Only port A can provide interrupts in all configurations of
|
||||||
* the IP.
|
* the IP.
|
||||||
*/
|
*/
|
||||||
if (dev->of_node && pp->idx == 0 &&
|
if (pp->idx != 0)
|
||||||
fwnode_property_read_bool(fwnode,
|
continue;
|
||||||
|
|
||||||
|
if (dev->of_node && fwnode_property_read_bool(fwnode,
|
||||||
"interrupt-controller")) {
|
"interrupt-controller")) {
|
||||||
pp->irq = irq_of_parse_and_map(to_of_node(fwnode), 0);
|
np = to_of_node(fwnode);
|
||||||
if (!pp->irq)
|
|
||||||
dev_warn(dev, "no irq for port%d\n", pp->idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_acpi_companion(dev) && pp->idx == 0)
|
for (j = 0; j < pp->ngpio; j++) {
|
||||||
pp->irq = platform_get_irq(to_platform_device(dev), 0);
|
pp->irq[j] = -ENXIO;
|
||||||
|
|
||||||
pp->irq_shared = false;
|
if (np)
|
||||||
pp->gpio_base = -1;
|
pp->irq[j] = of_irq_get(np, j);
|
||||||
|
else if (has_acpi_companion(dev))
|
||||||
|
pp->irq[j] = platform_get_irq(to_platform_device(dev), j);
|
||||||
|
|
||||||
|
if (pp->irq[j] >= 0)
|
||||||
|
pp->has_irq = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pp->has_irq)
|
||||||
|
dev_warn(dev, "no irq for port%d\n", pp->idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pdata;
|
return pdata;
|
||||||
|
@ -684,13 +703,7 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
gpio->flags = 0;
|
gpio->flags = 0;
|
||||||
if (dev->of_node) {
|
if (dev->of_node) {
|
||||||
const struct of_device_id *of_devid;
|
gpio->flags = (uintptr_t)of_device_get_match_data(dev);
|
||||||
|
|
||||||
of_devid = of_match_device(dwapb_of_match, dev);
|
|
||||||
if (of_devid) {
|
|
||||||
if (of_devid->data)
|
|
||||||
gpio->flags = (uintptr_t)of_devid->data;
|
|
||||||
}
|
|
||||||
} else if (has_acpi_companion(dev)) {
|
} else if (has_acpi_companion(dev)) {
|
||||||
const struct acpi_device_id *acpi_id;
|
const struct acpi_device_id *acpi_id;
|
||||||
|
|
||||||
|
|
|
@ -300,6 +300,7 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||||
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||||
u32 offset = irqd_to_hwirq(data);
|
u32 offset = irqd_to_hwirq(data);
|
||||||
|
int state;
|
||||||
|
|
||||||
switch (sprd_eic->type) {
|
switch (sprd_eic->type) {
|
||||||
case SPRD_EIC_DEBOUNCE:
|
case SPRD_EIC_DEBOUNCE:
|
||||||
|
@ -310,6 +311,17 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||||
case IRQ_TYPE_LEVEL_LOW:
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
|
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
|
||||||
break;
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_RISING:
|
||||||
|
case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
case IRQ_TYPE_EDGE_BOTH:
|
||||||
|
state = sprd_eic_get(chip, offset);
|
||||||
|
if (state)
|
||||||
|
sprd_eic_update(chip, offset,
|
||||||
|
SPRD_EIC_DBNC_IEV, 0);
|
||||||
|
else
|
||||||
|
sprd_eic_update(chip, offset,
|
||||||
|
SPRD_EIC_DBNC_IEV, 1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -324,6 +336,17 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||||
case IRQ_TYPE_LEVEL_LOW:
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
|
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
|
||||||
break;
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_RISING:
|
||||||
|
case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
case IRQ_TYPE_EDGE_BOTH:
|
||||||
|
state = sprd_eic_get(chip, offset);
|
||||||
|
if (state)
|
||||||
|
sprd_eic_update(chip, offset,
|
||||||
|
SPRD_EIC_LATCH_INTPOL, 0);
|
||||||
|
else
|
||||||
|
sprd_eic_update(chip, offset,
|
||||||
|
SPRD_EIC_LATCH_INTPOL, 1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -405,6 +428,55 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sprd_eic_toggle_trigger(struct gpio_chip *chip, unsigned int irq,
|
||||||
|
unsigned int offset)
|
||||||
|
{
|
||||||
|
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||||
|
struct irq_data *data = irq_get_irq_data(irq);
|
||||||
|
u32 trigger = irqd_get_trigger_type(data);
|
||||||
|
int state, post_state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The debounce EIC and latch EIC can only support level trigger, so we
|
||||||
|
* can toggle the level trigger to emulate the edge trigger.
|
||||||
|
*/
|
||||||
|
if ((sprd_eic->type != SPRD_EIC_DEBOUNCE &&
|
||||||
|
sprd_eic->type != SPRD_EIC_LATCH) ||
|
||||||
|
!(trigger & IRQ_TYPE_EDGE_BOTH))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sprd_eic_irq_mask(data);
|
||||||
|
state = sprd_eic_get(chip, offset);
|
||||||
|
|
||||||
|
retry:
|
||||||
|
switch (sprd_eic->type) {
|
||||||
|
case SPRD_EIC_DEBOUNCE:
|
||||||
|
if (state)
|
||||||
|
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
|
||||||
|
else
|
||||||
|
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1);
|
||||||
|
break;
|
||||||
|
case SPRD_EIC_LATCH:
|
||||||
|
if (state)
|
||||||
|
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0);
|
||||||
|
else
|
||||||
|
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sprd_eic_irq_unmask(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
post_state = sprd_eic_get(chip, offset);
|
||||||
|
if (state != post_state) {
|
||||||
|
dev_warn(chip->parent, "EIC level was changed.\n");
|
||||||
|
state = post_state;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprd_eic_irq_unmask(data);
|
||||||
|
}
|
||||||
|
|
||||||
static int sprd_eic_match_chip_by_type(struct gpio_chip *chip, void *data)
|
static int sprd_eic_match_chip_by_type(struct gpio_chip *chip, void *data)
|
||||||
{
|
{
|
||||||
enum sprd_eic_type type = *(enum sprd_eic_type *)data;
|
enum sprd_eic_type type = *(enum sprd_eic_type *)data;
|
||||||
|
@ -448,6 +520,7 @@ static void sprd_eic_handle_one_type(struct gpio_chip *chip)
|
||||||
bank * SPRD_EIC_PER_BANK_NR + n);
|
bank * SPRD_EIC_PER_BANK_NR + n);
|
||||||
|
|
||||||
generic_handle_irq(girq);
|
generic_handle_irq(girq);
|
||||||
|
sprd_eic_toggle_trigger(chip, girq, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,6 @@ MODULE_DEVICE_TABLE(of, gef_gpio_ids);
|
||||||
|
|
||||||
static int __init gef_gpio_probe(struct platform_device *pdev)
|
static int __init gef_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const struct of_device_id *of_id =
|
|
||||||
of_match_device(gef_gpio_ids, &pdev->dev);
|
|
||||||
struct gpio_chip *gc;
|
struct gpio_chip *gc;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -82,7 +80,7 @@ static int __init gef_gpio_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
gc->base = -1;
|
gc->base = -1;
|
||||||
gc->ngpio = (u16)(uintptr_t)of_id->data;
|
gc->ngpio = (u16)(uintptr_t)of_device_get_match_data(&pdev->dev);
|
||||||
gc->of_gpio_n_cells = 2;
|
gc->of_gpio_n_cells = 2;
|
||||||
gc->of_node = pdev->dev.of_node;
|
gc->of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||||
{
|
{
|
||||||
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
||||||
size_t i;
|
size_t i;
|
||||||
const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
|
static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
|
||||||
const unsigned int gpio_reg_size = 8;
|
const unsigned int gpio_reg_size = 8;
|
||||||
unsigned int bits_offset;
|
unsigned int bits_offset;
|
||||||
size_t word_index;
|
size_t word_index;
|
||||||
|
|
|
@ -285,8 +285,6 @@ MODULE_DEVICE_TABLE(of, ingenic_gpio_of_match);
|
||||||
static int ingenic_gpio_probe(struct platform_device *pdev)
|
static int ingenic_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
const struct of_device_id *of_id = of_match_device(
|
|
||||||
ingenic_gpio_of_match, dev);
|
|
||||||
struct ingenic_gpio_chip *jzgc;
|
struct ingenic_gpio_chip *jzgc;
|
||||||
u32 bank;
|
u32 bank;
|
||||||
int err;
|
int err;
|
||||||
|
@ -323,7 +321,7 @@ static int ingenic_gpio_probe(struct platform_device *pdev)
|
||||||
jzgc->gc.parent = dev;
|
jzgc->gc.parent = dev;
|
||||||
jzgc->gc.of_node = dev->of_node;
|
jzgc->gc.of_node = dev->of_node;
|
||||||
jzgc->gc.owner = THIS_MODULE;
|
jzgc->gc.owner = THIS_MODULE;
|
||||||
jzgc->version = (enum jz_version)of_id->data;
|
jzgc->version = (enum jz_version)of_device_get_match_data(dev);
|
||||||
|
|
||||||
jzgc->gc.set = ingenic_gpio_set;
|
jzgc->gc.set = ingenic_gpio_set;
|
||||||
jzgc->gc.get = ingenic_gpio_get;
|
jzgc->gc.get = ingenic_gpio_get;
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/gpio/driver.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
#include <loongson.h>
|
#include <loongson.h>
|
||||||
#include <linux/gpio.h>
|
|
||||||
|
|
||||||
#define STLS2F_N_GPIO 4
|
#define STLS2F_N_GPIO 4
|
||||||
#define STLS3A_N_GPIO 16
|
#define STLS3A_N_GPIO 16
|
||||||
|
@ -30,19 +32,48 @@
|
||||||
#define LOONGSON_N_GPIO STLS2F_N_GPIO
|
#define LOONGSON_N_GPIO STLS2F_N_GPIO
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Offset into the register where we read lines, we write them from offset 0.
|
||||||
|
* This offset is the only thing that stand between us and using
|
||||||
|
* GPIO_GENERIC.
|
||||||
|
*/
|
||||||
#define LOONGSON_GPIO_IN_OFFSET 16
|
#define LOONGSON_GPIO_IN_OFFSET 16
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(gpio_lock);
|
static DEFINE_SPINLOCK(gpio_lock);
|
||||||
|
|
||||||
|
static int loongson_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
spin_lock(&gpio_lock);
|
||||||
|
val = LOONGSON_GPIODATA;
|
||||||
|
spin_unlock(&gpio_lock);
|
||||||
|
|
||||||
|
return !!(val & BIT(gpio + LOONGSON_GPIO_IN_OFFSET));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loongson_gpio_set_value(struct gpio_chip *chip,
|
||||||
|
unsigned gpio, int value)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
spin_lock(&gpio_lock);
|
||||||
|
val = LOONGSON_GPIODATA;
|
||||||
|
if (value)
|
||||||
|
val |= BIT(gpio);
|
||||||
|
else
|
||||||
|
val &= ~BIT(gpio);
|
||||||
|
LOONGSON_GPIODATA = val;
|
||||||
|
spin_unlock(&gpio_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
||||||
{
|
{
|
||||||
u32 temp;
|
u32 temp;
|
||||||
u32 mask;
|
|
||||||
|
|
||||||
spin_lock(&gpio_lock);
|
spin_lock(&gpio_lock);
|
||||||
mask = 1 << gpio;
|
|
||||||
temp = LOONGSON_GPIOIE;
|
temp = LOONGSON_GPIOIE;
|
||||||
temp |= mask;
|
temp |= BIT(gpio);
|
||||||
LOONGSON_GPIOIE = temp;
|
LOONGSON_GPIOIE = temp;
|
||||||
spin_unlock(&gpio_lock);
|
spin_unlock(&gpio_lock);
|
||||||
|
|
||||||
|
@ -53,63 +84,56 @@ static int loongson_gpio_direction_output(struct gpio_chip *chip,
|
||||||
unsigned gpio, int level)
|
unsigned gpio, int level)
|
||||||
{
|
{
|
||||||
u32 temp;
|
u32 temp;
|
||||||
u32 mask;
|
|
||||||
|
|
||||||
gpio_set_value(gpio, level);
|
loongson_gpio_set_value(chip, gpio, level);
|
||||||
spin_lock(&gpio_lock);
|
spin_lock(&gpio_lock);
|
||||||
mask = 1 << gpio;
|
|
||||||
temp = LOONGSON_GPIOIE;
|
temp = LOONGSON_GPIOIE;
|
||||||
temp &= (~mask);
|
temp &= ~BIT(gpio);
|
||||||
LOONGSON_GPIOIE = temp;
|
LOONGSON_GPIOIE = temp;
|
||||||
spin_unlock(&gpio_lock);
|
spin_unlock(&gpio_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int loongson_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
|
static int loongson_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
u32 val;
|
struct gpio_chip *gc;
|
||||||
u32 mask;
|
struct device *dev = &pdev->dev;
|
||||||
|
|
||||||
mask = 1 << (gpio + LOONGSON_GPIO_IN_OFFSET);
|
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
|
||||||
spin_lock(&gpio_lock);
|
if (!gc)
|
||||||
val = LOONGSON_GPIODATA;
|
return -ENOMEM;
|
||||||
spin_unlock(&gpio_lock);
|
|
||||||
|
|
||||||
return (val & mask) != 0;
|
gc->label = "loongson-gpio-chip";
|
||||||
|
gc->base = 0;
|
||||||
|
gc->ngpio = LOONGSON_N_GPIO;
|
||||||
|
gc->get = loongson_gpio_get_value;
|
||||||
|
gc->set = loongson_gpio_set_value;
|
||||||
|
gc->direction_input = loongson_gpio_direction_input;
|
||||||
|
gc->direction_output = loongson_gpio_direction_output;
|
||||||
|
|
||||||
|
return gpiochip_add_data(gc, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loongson_gpio_set_value(struct gpio_chip *chip,
|
static struct platform_driver loongson_gpio_driver = {
|
||||||
unsigned gpio, int value)
|
.driver = {
|
||||||
{
|
.name = "loongson-gpio",
|
||||||
u32 val;
|
},
|
||||||
u32 mask;
|
.probe = loongson_gpio_probe,
|
||||||
|
|
||||||
mask = 1 << gpio;
|
|
||||||
|
|
||||||
spin_lock(&gpio_lock);
|
|
||||||
val = LOONGSON_GPIODATA;
|
|
||||||
if (value)
|
|
||||||
val |= mask;
|
|
||||||
else
|
|
||||||
val &= (~mask);
|
|
||||||
LOONGSON_GPIODATA = val;
|
|
||||||
spin_unlock(&gpio_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct gpio_chip loongson_chip = {
|
|
||||||
.label = "Loongson-gpio-chip",
|
|
||||||
.direction_input = loongson_gpio_direction_input,
|
|
||||||
.get = loongson_gpio_get_value,
|
|
||||||
.direction_output = loongson_gpio_direction_output,
|
|
||||||
.set = loongson_gpio_set_value,
|
|
||||||
.base = 0,
|
|
||||||
.ngpio = LOONGSON_N_GPIO,
|
|
||||||
.can_sleep = false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init loongson_gpio_setup(void)
|
static int __init loongson_gpio_setup(void)
|
||||||
{
|
{
|
||||||
return gpiochip_add_data(&loongson_chip, NULL);
|
struct platform_device *pdev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = platform_driver_register(&loongson_gpio_driver);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("error registering loongson GPIO driver\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdev = platform_device_register_simple("loongson-gpio", -1, NULL, 0);
|
||||||
|
return PTR_ERR_OR_ZERO(pdev);
|
||||||
}
|
}
|
||||||
postcore_initcall(loongson_gpio_setup);
|
postcore_initcall(loongson_gpio_setup);
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/mfd/lp3943.h>
|
#include <linux/mfd/lp3943.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* Based on the TPS65218 driver
|
* Based on the TPS65218 driver
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
|
|
|
@ -20,9 +20,8 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_gpio.h>
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/spi/max7301.h>
|
#include <linux/spi/max7301.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/mc33880.h>
|
#include <linux/spi/mc33880.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
|
|
||||||
#define GPIO_GROUP_NUM 2
|
#define GPIO_GROUP_NUM 2
|
||||||
#define GPIO_NUM_PER_GROUP 8
|
#define GPIO_NUM_PER_GROUP 8
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
/*
|
/*
|
||||||
* GPIO Testing Device Driver
|
* GPIO Testing Device Driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Kamlakant Patel <kamlakant.patel@broadcom.com>
|
* Copyright (C) 2014 Kamlakant Patel <kamlakant.patel@broadcom.com>
|
||||||
* Copyright (C) 2015-2016 Bamvor Jian Zhang <bamv2005@gmail.com>
|
* Copyright (C) 2015-2016 Bamvor Jian Zhang <bamv2005@gmail.com>
|
||||||
* Copyright (C) 2017 Bartosz Golaszewski <brgl@bgdev.pl>
|
* Copyright (C) 2017 Bartosz Golaszewski <brgl@bgdev.pl>
|
||||||
*
|
|
||||||
* 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/init.h>
|
#include <linux/init.h>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/mfd/intel_msic.h>
|
#include <linux/mfd/intel_msic.h>
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,8 @@
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
@ -51,8 +52,6 @@
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#include "gpiolib.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPIO unit register offsets.
|
* GPIO unit register offsets.
|
||||||
*/
|
*/
|
||||||
|
@ -608,19 +607,16 @@ static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
if (mvpwm->gpiod) {
|
if (mvpwm->gpiod) {
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
} else {
|
} else {
|
||||||
desc = gpio_to_desc(mvchip->chip.base + pwm->hwpwm);
|
desc = gpiochip_request_own_desc(&mvchip->chip,
|
||||||
if (!desc) {
|
pwm->hwpwm, "mvebu-pwm");
|
||||||
ret = -ENODEV;
|
if (IS_ERR(desc)) {
|
||||||
|
ret = PTR_ERR(desc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gpiod_request(desc, "mvebu-pwm");
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = gpiod_direction_output(desc, 0);
|
ret = gpiod_direction_output(desc, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
gpiod_free(desc);
|
gpiochip_free_own_desc(desc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +633,7 @@ static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||||
gpiod_free(mvpwm->gpiod);
|
gpiochip_free_own_desc(mvpwm->gpiod);
|
||||||
mvpwm->gpiod = NULL;
|
mvpwm->gpiod = NULL;
|
||||||
spin_unlock_irqrestore(&mvpwm->lock, flags);
|
spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,13 @@
|
||||||
/*
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
* MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
|
//
|
||||||
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
|
// MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
|
||||||
*
|
// Copyright 2008 Juergen Beisert, kernel@pengutronix.de
|
||||||
* Based on code from Freescale Semiconductor,
|
//
|
||||||
* Authors: Daniel Mack, Juergen Beisert.
|
// Based on code from Freescale Semiconductor,
|
||||||
* Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
|
// Authors: Daniel Mack, Juergen Beisert.
|
||||||
*
|
// Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||||
* 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.
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
@ -30,8 +18,6 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/gpio/driver.h>
|
||||||
/* FIXME: for gpio_get_value() replace this with direct register read */
|
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/bug.h>
|
#include <linux/bug.h>
|
||||||
|
@ -62,6 +48,7 @@ struct mxc_gpio_hwdata {
|
||||||
struct mxc_gpio_port {
|
struct mxc_gpio_port {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
struct clk *clk;
|
||||||
int irq;
|
int irq;
|
||||||
int irq_high;
|
int irq_high;
|
||||||
struct irq_domain *domain;
|
struct irq_domain *domain;
|
||||||
|
@ -174,7 +161,6 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
|
||||||
struct mxc_gpio_port *port = gc->private;
|
struct mxc_gpio_port *port = gc->private;
|
||||||
u32 bit, val;
|
u32 bit, val;
|
||||||
u32 gpio_idx = d->hwirq;
|
u32 gpio_idx = d->hwirq;
|
||||||
u32 gpio = port->gc.base + gpio_idx;
|
|
||||||
int edge;
|
int edge;
|
||||||
void __iomem *reg = port->base;
|
void __iomem *reg = port->base;
|
||||||
|
|
||||||
|
@ -190,13 +176,13 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type)
|
||||||
if (GPIO_EDGE_SEL >= 0) {
|
if (GPIO_EDGE_SEL >= 0) {
|
||||||
edge = GPIO_INT_BOTH_EDGES;
|
edge = GPIO_INT_BOTH_EDGES;
|
||||||
} else {
|
} else {
|
||||||
val = gpio_get_value(gpio);
|
val = port->gc.get(&port->gc, gpio_idx);
|
||||||
if (val) {
|
if (val) {
|
||||||
edge = GPIO_INT_LOW_LEV;
|
edge = GPIO_INT_LOW_LEV;
|
||||||
pr_debug("mxc: set GPIO %d to low trigger\n", gpio);
|
pr_debug("mxc: set GPIO %d to low trigger\n", gpio_idx);
|
||||||
} else {
|
} else {
|
||||||
edge = GPIO_INT_HIGH_LEV;
|
edge = GPIO_INT_HIGH_LEV;
|
||||||
pr_debug("mxc: set GPIO %d to high trigger\n", gpio);
|
pr_debug("mxc: set GPIO %d to high trigger\n", gpio_idx);
|
||||||
}
|
}
|
||||||
port->both_edges |= 1 << gpio_idx;
|
port->both_edges |= 1 << gpio_idx;
|
||||||
}
|
}
|
||||||
|
@ -437,6 +423,17 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
||||||
if (port->irq < 0)
|
if (port->irq < 0)
|
||||||
return port->irq;
|
return port->irq;
|
||||||
|
|
||||||
|
/* the controller clock is optional */
|
||||||
|
port->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(port->clk))
|
||||||
|
port->clk = NULL;
|
||||||
|
|
||||||
|
err = clk_prepare_enable(port->clk);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* disable the interrupt and clear the status */
|
/* disable the interrupt and clear the status */
|
||||||
writel(0, port->base + GPIO_IMR);
|
writel(0, port->base + GPIO_IMR);
|
||||||
writel(~0, port->base + GPIO_ISR);
|
writel(~0, port->base + GPIO_ISR);
|
||||||
|
@ -505,6 +502,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
||||||
out_irqdomain_remove:
|
out_irqdomain_remove:
|
||||||
irq_domain_remove(port->domain);
|
irq_domain_remove(port->domain);
|
||||||
out_bgio:
|
out_bgio:
|
||||||
|
clk_disable_unprepare(port->clk);
|
||||||
dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
|
dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,10 @@
|
||||||
/*
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
* MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
|
//
|
||||||
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
|
// MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
|
||||||
*
|
// Copyright 2008 Juergen Beisert, kernel@pengutronix.de
|
||||||
* Based on code from Freescale,
|
//
|
||||||
* Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
|
// Based on code from Freescale,
|
||||||
*
|
// Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||||
* 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.
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
||||||
* MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -290,8 +276,6 @@ MODULE_DEVICE_TABLE(of, mxs_gpio_dt_ids);
|
||||||
|
|
||||||
static int mxs_gpio_probe(struct platform_device *pdev)
|
static int mxs_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const struct of_device_id *of_id =
|
|
||||||
of_match_device(mxs_gpio_dt_ids, &pdev->dev);
|
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct device_node *parent;
|
struct device_node *parent;
|
||||||
static void __iomem *base;
|
static void __iomem *base;
|
||||||
|
@ -306,7 +290,7 @@ static int mxs_gpio_probe(struct platform_device *pdev)
|
||||||
port->id = of_alias_get_id(np, "gpio");
|
port->id = of_alias_get_id(np, "gpio");
|
||||||
if (port->id < 0)
|
if (port->id < 0)
|
||||||
return port->id;
|
return port->id;
|
||||||
port->devid = (enum mxs_gpio_id) of_id->data;
|
port->devid = (enum mxs_gpio_id)of_device_get_match_data(&pdev->dev);
|
||||||
port->dev = &pdev->dev;
|
port->dev = &pdev->dev;
|
||||||
port->irq = platform_get_irq(pdev, 0);
|
port->irq = platform_get_irq(pdev, 0);
|
||||||
if (port->irq < 0)
|
if (port->irq < 0)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
|
||||||
#include <asm/octeon/octeon.h>
|
#include <asm/octeon/octeon.h>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/platform_data/gpio-omap.h>
|
#include <linux/platform_data/gpio-omap.h>
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/mfd/palmas.h>
|
#include <linux/mfd/palmas.h>
|
||||||
|
@ -159,13 +159,9 @@ static int palmas_gpio_probe(struct platform_device *pdev)
|
||||||
struct palmas_platform_data *palmas_pdata;
|
struct palmas_platform_data *palmas_pdata;
|
||||||
struct palmas_gpio *palmas_gpio;
|
struct palmas_gpio *palmas_gpio;
|
||||||
int ret;
|
int ret;
|
||||||
const struct of_device_id *match;
|
|
||||||
const struct palmas_device_data *dev_data;
|
const struct palmas_device_data *dev_data;
|
||||||
|
|
||||||
match = of_match_device(of_palmas_gpio_match, &pdev->dev);
|
dev_data = of_device_get_match_data(&pdev->dev);
|
||||||
if (!match)
|
|
||||||
return -ENODEV;
|
|
||||||
dev_data = match->data;
|
|
||||||
if (!dev_data)
|
if (!dev_data)
|
||||||
dev_data = &palmas_dev_data;
|
dev_data = &palmas_dev_data;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -25,29 +25,44 @@
|
||||||
|
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#define PCA953X_INPUT 0
|
#define PCA953X_INPUT 0x00
|
||||||
#define PCA953X_OUTPUT 1
|
#define PCA953X_OUTPUT 0x01
|
||||||
#define PCA953X_INVERT 2
|
#define PCA953X_INVERT 0x02
|
||||||
#define PCA953X_DIRECTION 3
|
#define PCA953X_DIRECTION 0x03
|
||||||
|
|
||||||
#define REG_ADDR_AI 0x80
|
#define REG_ADDR_AI 0x80
|
||||||
|
|
||||||
#define PCA957X_IN 0
|
#define PCA957X_IN 0x00
|
||||||
#define PCA957X_INVRT 1
|
#define PCA957X_INVRT 0x01
|
||||||
#define PCA957X_BKEN 2
|
#define PCA957X_BKEN 0x02
|
||||||
#define PCA957X_PUPD 3
|
#define PCA957X_PUPD 0x03
|
||||||
#define PCA957X_CFG 4
|
#define PCA957X_CFG 0x04
|
||||||
#define PCA957X_OUT 5
|
#define PCA957X_OUT 0x05
|
||||||
#define PCA957X_MSK 6
|
#define PCA957X_MSK 0x06
|
||||||
#define PCA957X_INTS 7
|
#define PCA957X_INTS 0x07
|
||||||
|
|
||||||
#define PCAL953X_IN_LATCH 34
|
#define PCAL953X_OUT_STRENGTH 0x20
|
||||||
#define PCAL953X_INT_MASK 37
|
#define PCAL953X_IN_LATCH 0x22
|
||||||
#define PCAL953X_INT_STAT 38
|
#define PCAL953X_PULL_EN 0x23
|
||||||
|
#define PCAL953X_PULL_SEL 0x24
|
||||||
|
#define PCAL953X_INT_MASK 0x25
|
||||||
|
#define PCAL953X_INT_STAT 0x26
|
||||||
|
#define PCAL953X_OUT_CONF 0x27
|
||||||
|
|
||||||
|
#define PCAL6524_INT_EDGE 0x28
|
||||||
|
#define PCAL6524_INT_CLR 0x2a
|
||||||
|
#define PCAL6524_IN_STATUS 0x2b
|
||||||
|
#define PCAL6524_OUT_INDCONF 0x2c
|
||||||
|
#define PCAL6524_DEBOUNCE 0x2d
|
||||||
|
|
||||||
#define PCA_GPIO_MASK 0x00FF
|
#define PCA_GPIO_MASK 0x00FF
|
||||||
|
|
||||||
|
#define PCAL_GPIO_MASK 0x1f
|
||||||
|
#define PCAL_PINCTRL_MASK 0xe0
|
||||||
|
|
||||||
#define PCA_INT 0x0100
|
#define PCA_INT 0x0100
|
||||||
#define PCA_PCAL 0x0200
|
#define PCA_PCAL 0x0200
|
||||||
|
#define PCA_LATCH_INT (PCA_PCAL | PCA_INT)
|
||||||
#define PCA953X_TYPE 0x1000
|
#define PCA953X_TYPE 0x1000
|
||||||
#define PCA957X_TYPE 0x2000
|
#define PCA957X_TYPE 0x2000
|
||||||
#define PCA_TYPE_MASK 0xF000
|
#define PCA_TYPE_MASK 0xF000
|
||||||
|
@ -207,9 +222,11 @@ static int pca957x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
|
||||||
static int pca953x_write_regs_24(struct pca953x_chip *chip, int reg, u8 *val)
|
static int pca953x_write_regs_24(struct pca953x_chip *chip, int reg, u8 *val)
|
||||||
{
|
{
|
||||||
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||||
|
int addr = (reg & PCAL_GPIO_MASK) << bank_shift;
|
||||||
|
int pinctrl = (reg & PCAL_PINCTRL_MASK) << 1;
|
||||||
|
|
||||||
return i2c_smbus_write_i2c_block_data(chip->client,
|
return i2c_smbus_write_i2c_block_data(chip->client,
|
||||||
(reg << bank_shift) | REG_ADDR_AI,
|
pinctrl | addr | REG_ADDR_AI,
|
||||||
NBANK(chip), val);
|
NBANK(chip), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,9 +266,11 @@ static int pca953x_read_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
|
||||||
static int pca953x_read_regs_24(struct pca953x_chip *chip, int reg, u8 *val)
|
static int pca953x_read_regs_24(struct pca953x_chip *chip, int reg, u8 *val)
|
||||||
{
|
{
|
||||||
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
|
||||||
|
int addr = (reg & PCAL_GPIO_MASK) << bank_shift;
|
||||||
|
int pinctrl = (reg & PCAL_PINCTRL_MASK) << 1;
|
||||||
|
|
||||||
return i2c_smbus_read_i2c_block_data(chip->client,
|
return i2c_smbus_read_i2c_block_data(chip->client,
|
||||||
(reg << bank_shift) | REG_ADDR_AI,
|
pinctrl | addr | REG_ADDR_AI,
|
||||||
NBANK(chip), val);
|
NBANK(chip), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,6 +541,15 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pca953x_irq_shutdown(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||||
|
u8 mask = 1 << (d->hwirq % BANK_SZ);
|
||||||
|
|
||||||
|
chip->irq_trig_raise[d->hwirq / BANK_SZ] &= ~mask;
|
||||||
|
chip->irq_trig_fall[d->hwirq / BANK_SZ] &= ~mask;
|
||||||
|
}
|
||||||
|
|
||||||
static struct irq_chip pca953x_irq_chip = {
|
static struct irq_chip pca953x_irq_chip = {
|
||||||
.name = "pca953x",
|
.name = "pca953x",
|
||||||
.irq_mask = pca953x_irq_mask,
|
.irq_mask = pca953x_irq_mask,
|
||||||
|
@ -529,6 +557,7 @@ static struct irq_chip pca953x_irq_chip = {
|
||||||
.irq_bus_lock = pca953x_irq_bus_lock,
|
.irq_bus_lock = pca953x_irq_bus_lock,
|
||||||
.irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock,
|
.irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock,
|
||||||
.irq_set_type = pca953x_irq_set_type,
|
.irq_set_type = pca953x_irq_set_type,
|
||||||
|
.irq_shutdown = pca953x_irq_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
||||||
|
@ -810,13 +839,11 @@ static int pca953x_probe(struct i2c_client *client,
|
||||||
chip->driver_data = i2c_id->driver_data;
|
chip->driver_data = i2c_id->driver_data;
|
||||||
} else {
|
} else {
|
||||||
const struct acpi_device_id *acpi_id;
|
const struct acpi_device_id *acpi_id;
|
||||||
const struct of_device_id *match;
|
struct device *dev = &client->dev;
|
||||||
|
|
||||||
match = of_match_device(pca953x_dt_ids, &client->dev);
|
chip->driver_data = (uintptr_t)of_device_get_match_data(dev);
|
||||||
if (match) {
|
if (!chip->driver_data) {
|
||||||
chip->driver_data = (int)(uintptr_t)match->data;
|
acpi_id = acpi_match_device(pca953x_acpi_ids, dev);
|
||||||
} else {
|
|
||||||
acpi_id = acpi_match_device(pca953x_acpi_ids, &client->dev);
|
|
||||||
if (!acpi_id) {
|
if (!acpi_id) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
|
@ -936,8 +963,8 @@ static const struct of_device_id pca953x_dt_ids[] = {
|
||||||
{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
|
{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
|
||||||
{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
|
{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
|
||||||
|
|
||||||
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_INT), },
|
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
|
||||||
{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_INT), },
|
{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
|
||||||
|
|
||||||
{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
|
{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
|
||||||
{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
|
{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_data/pcf857x.h>
|
#include <linux/platform_data/pcf857x.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/irqchip/chained_irq.h>
|
#include <linux/irqchip/chained_irq.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/amba/bus.h>
|
#include <linux/amba/bus.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
|
@ -178,6 +178,14 @@ static int sprd_pmic_eic_irq_set_type(struct irq_data *data,
|
||||||
case IRQ_TYPE_LEVEL_LOW:
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
pmic_eic->reg[REG_IEV] = 0;
|
pmic_eic->reg[REG_IEV] = 0;
|
||||||
break;
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_RISING:
|
||||||
|
case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
case IRQ_TYPE_EDGE_BOTH:
|
||||||
|
/*
|
||||||
|
* Will set the trigger level according to current EIC level
|
||||||
|
* in irq_bus_sync_unlock() interface, so here nothing to do.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -197,11 +205,22 @@ static void sprd_pmic_eic_bus_sync_unlock(struct irq_data *data)
|
||||||
{
|
{
|
||||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||||
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
||||||
|
u32 trigger = irqd_get_trigger_type(data);
|
||||||
u32 offset = irqd_to_hwirq(data);
|
u32 offset = irqd_to_hwirq(data);
|
||||||
|
int state;
|
||||||
|
|
||||||
/* Set irq type */
|
/* Set irq type */
|
||||||
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV,
|
if (trigger & IRQ_TYPE_EDGE_BOTH) {
|
||||||
pmic_eic->reg[REG_IEV]);
|
state = sprd_pmic_eic_get(chip, offset);
|
||||||
|
if (state)
|
||||||
|
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, 0);
|
||||||
|
else
|
||||||
|
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, 1);
|
||||||
|
} else {
|
||||||
|
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV,
|
||||||
|
pmic_eic->reg[REG_IEV]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set irq unmask */
|
/* Set irq unmask */
|
||||||
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IE,
|
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IE,
|
||||||
pmic_eic->reg[REG_IE]);
|
pmic_eic->reg[REG_IE]);
|
||||||
|
@ -212,6 +231,35 @@ static void sprd_pmic_eic_bus_sync_unlock(struct irq_data *data)
|
||||||
mutex_unlock(&pmic_eic->buslock);
|
mutex_unlock(&pmic_eic->buslock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sprd_pmic_eic_toggle_trigger(struct gpio_chip *chip,
|
||||||
|
unsigned int irq, unsigned int offset)
|
||||||
|
{
|
||||||
|
u32 trigger = irq_get_trigger_type(irq);
|
||||||
|
int state, post_state;
|
||||||
|
|
||||||
|
if (!(trigger & IRQ_TYPE_EDGE_BOTH))
|
||||||
|
return;
|
||||||
|
|
||||||
|
state = sprd_pmic_eic_get(chip, offset);
|
||||||
|
retry:
|
||||||
|
if (state)
|
||||||
|
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, 0);
|
||||||
|
else
|
||||||
|
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, 1);
|
||||||
|
|
||||||
|
post_state = sprd_pmic_eic_get(chip, offset);
|
||||||
|
if (state != post_state) {
|
||||||
|
dev_warn(chip->parent, "PMIC EIC level was changed.\n");
|
||||||
|
state = post_state;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set irq unmask */
|
||||||
|
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IE, 1);
|
||||||
|
/* Generate trigger start pulse for debounce EIC */
|
||||||
|
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_TRIG, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t sprd_pmic_eic_irq_handler(int irq, void *data)
|
static irqreturn_t sprd_pmic_eic_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct sprd_pmic_eic *pmic_eic = data;
|
struct sprd_pmic_eic *pmic_eic = data;
|
||||||
|
@ -233,6 +281,12 @@ static irqreturn_t sprd_pmic_eic_irq_handler(int irq, void *data)
|
||||||
|
|
||||||
girq = irq_find_mapping(chip->irq.domain, n);
|
girq = irq_find_mapping(chip->irq.domain, n);
|
||||||
handle_nested_irq(girq);
|
handle_nested_irq(girq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The PMIC EIC can only support level trigger, so we can
|
||||||
|
* toggle the level trigger to emulate the edge trigger.
|
||||||
|
*/
|
||||||
|
sprd_pmic_eic_toggle_trigger(chip, girq, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/gpio-pxa.h>
|
#include <linux/gpio-pxa.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
@ -579,15 +579,9 @@ static int pxa_gpio_probe_dt(struct platform_device *pdev,
|
||||||
struct pxa_gpio_chip *pchip)
|
struct pxa_gpio_chip *pchip)
|
||||||
{
|
{
|
||||||
int nr_gpios;
|
int nr_gpios;
|
||||||
const struct of_device_id *of_id =
|
|
||||||
of_match_device(pxa_gpio_dt_ids, &pdev->dev);
|
|
||||||
const struct pxa_gpio_id *gpio_id;
|
const struct pxa_gpio_id *gpio_id;
|
||||||
|
|
||||||
if (!of_id || !of_id->data) {
|
gpio_id = of_device_get_match_data(&pdev->dev);
|
||||||
dev_err(&pdev->dev, "Failed to find gpio controller\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
gpio_id = of_id->data;
|
|
||||||
gpio_type = gpio_id->type;
|
gpio_type = gpio_id->type;
|
||||||
|
|
||||||
nr_gpios = gpio_id->gpio_nums;
|
nr_gpios = gpio_id->gpio_nums;
|
||||||
|
|
|
@ -363,13 +363,15 @@ static struct irq_chip stmpe_gpio_irq_chip = {
|
||||||
.irq_set_type = stmpe_gpio_irq_set_type,
|
.irq_set_type = stmpe_gpio_irq_set_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAX_GPIOS 24
|
||||||
|
|
||||||
static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
|
static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
|
||||||
{
|
{
|
||||||
struct stmpe_gpio *stmpe_gpio = dev;
|
struct stmpe_gpio *stmpe_gpio = dev;
|
||||||
struct stmpe *stmpe = stmpe_gpio->stmpe;
|
struct stmpe *stmpe = stmpe_gpio->stmpe;
|
||||||
u8 statmsbreg;
|
u8 statmsbreg;
|
||||||
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
|
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
|
||||||
u8 status[num_banks];
|
u8 status[DIV_ROUND_UP(MAX_GPIOS, 8)];
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -434,6 +436,11 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
|
||||||
struct stmpe_gpio *stmpe_gpio;
|
struct stmpe_gpio *stmpe_gpio;
|
||||||
int ret, irq;
|
int ret, irq;
|
||||||
|
|
||||||
|
if (stmpe->num_gpios > MAX_GPIOS) {
|
||||||
|
dev_err(&pdev->dev, "Need to increase maximum GPIO number\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
stmpe_gpio = kzalloc(sizeof(*stmpe_gpio), GFP_KERNEL);
|
stmpe_gpio = kzalloc(sizeof(*stmpe_gpio), GFP_KERNEL);
|
||||||
if (!stmpe_gpio)
|
if (!stmpe_gpio)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -182,20 +182,15 @@ MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
|
||||||
static int syscon_gpio_probe(struct platform_device *pdev)
|
static int syscon_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
const struct of_device_id *of_id;
|
|
||||||
struct syscon_gpio_priv *priv;
|
struct syscon_gpio_priv *priv;
|
||||||
struct device_node *np = dev->of_node;
|
struct device_node *np = dev->of_node;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
of_id = of_match_device(syscon_gpio_ids, dev);
|
|
||||||
if (!of_id)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
priv->data = of_id->data;
|
priv->data = of_device_get_match_data(dev);
|
||||||
|
|
||||||
if (priv->data->compatible) {
|
if (priv->data->compatible) {
|
||||||
priv->syscon = syscon_regmap_lookup_by_compatible(
|
priv->syscon = syscon_regmap_lookup_by_compatible(
|
||||||
|
@ -205,6 +200,8 @@ static int syscon_gpio_probe(struct platform_device *pdev)
|
||||||
} else {
|
} else {
|
||||||
priv->syscon =
|
priv->syscon =
|
||||||
syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");
|
syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");
|
||||||
|
if (IS_ERR(priv->syscon) && np->parent)
|
||||||
|
priv->syscon = syscon_node_to_regmap(np->parent);
|
||||||
if (IS_ERR(priv->syscon))
|
if (IS_ERR(priv->syscon))
|
||||||
return PTR_ERR(priv->syscon);
|
return PTR_ERR(priv->syscon);
|
||||||
|
|
||||||
|
|
|
@ -128,15 +128,10 @@ MODULE_DEVICE_TABLE(of, ts4900_gpio_of_match_table);
|
||||||
static int ts4900_gpio_probe(struct i2c_client *client,
|
static int ts4900_gpio_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
const struct of_device_id *match;
|
|
||||||
struct ts4900_gpio_priv *priv;
|
struct ts4900_gpio_priv *priv;
|
||||||
u32 ngpio;
|
u32 ngpio;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
match = of_match_device(ts4900_gpio_of_match_table, &client->dev);
|
|
||||||
if (!match)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (of_property_read_u32(client->dev.of_node, "ngpios", &ngpio))
|
if (of_property_read_u32(client->dev.of_node, "ngpios", &ngpio))
|
||||||
ngpio = DEFAULT_PIN_NUMBER;
|
ngpio = DEFAULT_PIN_NUMBER;
|
||||||
|
|
||||||
|
@ -148,7 +143,7 @@ static int ts4900_gpio_probe(struct i2c_client *client,
|
||||||
priv->gpio_chip.label = "ts4900-gpio";
|
priv->gpio_chip.label = "ts4900-gpio";
|
||||||
priv->gpio_chip.ngpio = ngpio;
|
priv->gpio_chip.ngpio = ngpio;
|
||||||
priv->gpio_chip.parent = &client->dev;
|
priv->gpio_chip.parent = &client->dev;
|
||||||
priv->input_bit = (uintptr_t)match->data;
|
priv->input_bit = (uintptr_t)of_device_get_match_data(&client->dev);
|
||||||
|
|
||||||
priv->regmap = devm_regmap_init_i2c(client, &ts4900_regmap_config);
|
priv->regmap = devm_regmap_init_i2c(client, &ts4900_regmap_config);
|
||||||
if (IS_ERR(priv->regmap)) {
|
if (IS_ERR(priv->regmap)) {
|
||||||
|
|
|
@ -254,8 +254,6 @@ static struct irq_chip vf610_gpio_irq_chip = {
|
||||||
|
|
||||||
static int vf610_gpio_probe(struct platform_device *pdev)
|
static int vf610_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const struct of_device_id *of_id = of_match_device(vf610_gpio_dt_ids,
|
|
||||||
&pdev->dev);
|
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct device_node *np = dev->of_node;
|
struct device_node *np = dev->of_node;
|
||||||
struct vf610_gpio_port *port;
|
struct vf610_gpio_port *port;
|
||||||
|
@ -267,7 +265,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
||||||
if (!port)
|
if (!port)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
port->sdata = of_id->data;
|
port->sdata = of_device_get_match_data(dev);
|
||||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
port->base = devm_ioremap_resource(dev, iores);
|
port->base = devm_ioremap_resource(dev, iores);
|
||||||
if (IS_ERR(port->base))
|
if (IS_ERR(port->base))
|
||||||
|
|
|
@ -322,14 +322,7 @@ static int xlp_gpio_probe(struct platform_device *pdev)
|
||||||
return irq;
|
return irq;
|
||||||
|
|
||||||
if (pdev->dev.of_node) {
|
if (pdev->dev.of_node) {
|
||||||
const struct of_device_id *of_id;
|
soc_type = (uintptr_t)of_device_get_match_data(&pdev->dev);
|
||||||
|
|
||||||
of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev);
|
|
||||||
if (!of_id) {
|
|
||||||
dev_err(&pdev->dev, "Unable to match OF ID\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
soc_type = (uintptr_t) of_id->data;
|
|
||||||
} else {
|
} else {
|
||||||
const struct acpi_device_id *acpi_id;
|
const struct acpi_device_id *acpi_id;
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#define XRA_REIR 0x10 /* Input Rising Edge Interrupt Enable */
|
#define XRA_REIR 0x10 /* Input Rising Edge Interrupt Enable */
|
||||||
#define XRA_FEIR 0x12 /* Input Falling Edge Interrupt Enable */
|
#define XRA_FEIR 0x12 /* Input Falling Edge Interrupt Enable */
|
||||||
#define XRA_IFR 0x14 /* Input Filter Enable/Disable */
|
#define XRA_IFR 0x14 /* Input Filter Enable/Disable */
|
||||||
|
#define XRA_LAST 0x15 /* Bounds */
|
||||||
|
|
||||||
struct xra1403 {
|
struct xra1403 {
|
||||||
struct gpio_chip chip;
|
struct gpio_chip chip;
|
||||||
|
@ -50,7 +51,7 @@ static const struct regmap_config xra1403_regmap_cfg = {
|
||||||
.pad_bits = 1,
|
.pad_bits = 1,
|
||||||
.val_bits = 8,
|
.val_bits = 8,
|
||||||
|
|
||||||
.max_register = XRA_IFR | 0x01,
|
.max_register = XRA_LAST,
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int to_reg(unsigned int reg, unsigned int offset)
|
static unsigned int to_reg(unsigned int reg, unsigned int offset)
|
||||||
|
@ -126,21 +127,16 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
{
|
{
|
||||||
int reg;
|
int reg;
|
||||||
struct xra1403 *xra = gpiochip_get_data(chip);
|
struct xra1403 *xra = gpiochip_get_data(chip);
|
||||||
int *value;
|
int value[XRA_LAST];
|
||||||
int i;
|
int i;
|
||||||
unsigned int gcr;
|
unsigned int gcr;
|
||||||
unsigned int gsr;
|
unsigned int gsr;
|
||||||
|
|
||||||
value = kmalloc_array(xra1403_regmap_cfg.max_register, sizeof(*value),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
seq_puts(s, "xra reg:");
|
seq_puts(s, "xra reg:");
|
||||||
for (reg = 0; reg <= xra1403_regmap_cfg.max_register; reg++)
|
for (reg = 0; reg <= XRA_LAST; reg++)
|
||||||
seq_printf(s, " %2.2x", reg);
|
seq_printf(s, " %2.2x", reg);
|
||||||
seq_puts(s, "\n value:");
|
seq_puts(s, "\n value:");
|
||||||
for (reg = 0; reg < xra1403_regmap_cfg.max_register; reg++) {
|
for (reg = 0; reg < XRA_LAST; reg++) {
|
||||||
regmap_read(xra->regmap, reg, &value[reg]);
|
regmap_read(xra->regmap, reg, &value[reg]);
|
||||||
seq_printf(s, " %2.2x", value[reg]);
|
seq_printf(s, " %2.2x", value[reg]);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +155,6 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
(gcr & BIT(i)) ? "in" : "out",
|
(gcr & BIT(i)) ? "in" : "out",
|
||||||
(gsr & BIT(i)) ? "hi" : "lo");
|
(gsr & BIT(i)) ? "hi" : "lo");
|
||||||
}
|
}
|
||||||
kfree(value);
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define xra1403_dbg_show NULL
|
#define xra1403_dbg_show NULL
|
||||||
|
|
|
@ -665,10 +665,8 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio)
|
||||||
|
|
||||||
static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
struct zynq_gpio *gpio = dev_get_drvdata(dev);
|
||||||
int irq = platform_get_irq(pdev, 0);
|
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
||||||
struct irq_data *data = irq_get_irq_data(irq);
|
|
||||||
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
if (!irqd_is_wakeup_set(data)) {
|
if (!irqd_is_wakeup_set(data)) {
|
||||||
zynq_gpio_save_context(gpio);
|
zynq_gpio_save_context(gpio);
|
||||||
|
@ -680,10 +678,8 @@ static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
||||||
|
|
||||||
static int __maybe_unused zynq_gpio_resume(struct device *dev)
|
static int __maybe_unused zynq_gpio_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
struct zynq_gpio *gpio = dev_get_drvdata(dev);
|
||||||
int irq = platform_get_irq(pdev, 0);
|
struct irq_data *data = irq_get_irq_data(gpio->irq);
|
||||||
struct irq_data *data = irq_get_irq_data(irq);
|
|
||||||
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!irqd_is_wakeup_set(data)) {
|
if (!irqd_is_wakeup_set(data)) {
|
||||||
|
@ -831,7 +827,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||||
chip->free = zynq_gpio_free;
|
chip->free = zynq_gpio_free;
|
||||||
chip->direction_input = zynq_gpio_dir_in;
|
chip->direction_input = zynq_gpio_dir_in;
|
||||||
chip->direction_output = zynq_gpio_dir_out;
|
chip->direction_output = zynq_gpio_dir_out;
|
||||||
chip->base = -1;
|
chip->base = of_alias_get_id(pdev->dev.of_node, "gpio");
|
||||||
chip->ngpio = gpio->p_data->ngpio;
|
chip->ngpio = gpio->p_data->ngpio;
|
||||||
|
|
||||||
/* Retrieve GPIO clock */
|
/* Retrieve GPIO clock */
|
||||||
|
|
|
@ -210,11 +210,8 @@ static struct gpio_desc *of_find_regulator_gpio(struct device *dev, const char *
|
||||||
if (!con_id)
|
if (!con_id)
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(whitelist); i++)
|
i = match_string(whitelist, ARRAY_SIZE(whitelist), con_id);
|
||||||
if (!strcmp(con_id, whitelist[i]))
|
if (i < 0)
|
||||||
break;
|
|
||||||
|
|
||||||
if (i == ARRAY_SIZE(whitelist))
|
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
desc = of_get_named_gpiod_flags(np, con_id, 0, of_flags);
|
desc = of_get_named_gpiod_flags(np, con_id, 0, of_flags);
|
||||||
|
|
|
@ -61,6 +61,11 @@ static struct bus_type gpio_bus_type = {
|
||||||
.name = "gpio",
|
.name = "gpio",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of GPIOs to use for the fast path in set array
|
||||||
|
*/
|
||||||
|
#define FASTPATH_NGPIO CONFIG_GPIOLIB_FASTPATH_LIMIT
|
||||||
|
|
||||||
/* gpio_lock prevents conflicts during gpio_desc[] table updates.
|
/* gpio_lock prevents conflicts during gpio_desc[] table updates.
|
||||||
* While any GPIO is requested, its gpio_chip is not removable;
|
* While any GPIO is requested, its gpio_chip is not removable;
|
||||||
* each GPIO's "requested" flag serves as a lock and refcount.
|
* each GPIO's "requested" flag serves as a lock and refcount.
|
||||||
|
@ -71,6 +76,9 @@ static DEFINE_MUTEX(gpio_lookup_lock);
|
||||||
static LIST_HEAD(gpio_lookup_list);
|
static LIST_HEAD(gpio_lookup_list);
|
||||||
LIST_HEAD(gpio_devices);
|
LIST_HEAD(gpio_devices);
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(gpio_machine_hogs_mutex);
|
||||||
|
static LIST_HEAD(gpio_machine_hogs);
|
||||||
|
|
||||||
static void gpiochip_free_hogs(struct gpio_chip *chip);
|
static void gpiochip_free_hogs(struct gpio_chip *chip);
|
||||||
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
|
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
|
||||||
struct lock_class_key *lock_key,
|
struct lock_class_key *lock_key,
|
||||||
|
@ -450,12 +458,11 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
|
||||||
vals[i] = !!ghd.values[i];
|
vals[i] = !!ghd.values[i];
|
||||||
|
|
||||||
/* Reuse the array setting function */
|
/* Reuse the array setting function */
|
||||||
gpiod_set_array_value_complex(false,
|
return gpiod_set_array_value_complex(false,
|
||||||
true,
|
true,
|
||||||
lh->numdescs,
|
lh->numdescs,
|
||||||
lh->descs,
|
lh->descs,
|
||||||
vals);
|
vals);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1172,6 +1179,41 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gpiochip_machine_hog(struct gpio_chip *chip, struct gpiod_hog *hog)
|
||||||
|
{
|
||||||
|
struct gpio_desc *desc;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
desc = gpiochip_get_desc(chip, hog->chip_hwnum);
|
||||||
|
if (IS_ERR(desc)) {
|
||||||
|
pr_err("%s: unable to get GPIO desc: %ld\n",
|
||||||
|
__func__, PTR_ERR(desc));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test_bit(FLAG_IS_HOGGED, &desc->flags))
|
||||||
|
return;
|
||||||
|
|
||||||
|
rv = gpiod_hog(desc, hog->line_name, hog->lflags, hog->dflags);
|
||||||
|
if (rv)
|
||||||
|
pr_err("%s: unable to hog GPIO line (%s:%u): %d\n",
|
||||||
|
__func__, chip->label, hog->chip_hwnum, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_gpiochip_add(struct gpio_chip *chip)
|
||||||
|
{
|
||||||
|
struct gpiod_hog *hog;
|
||||||
|
|
||||||
|
mutex_lock(&gpio_machine_hogs_mutex);
|
||||||
|
|
||||||
|
list_for_each_entry(hog, &gpio_machine_hogs, list) {
|
||||||
|
if (!strcmp(chip->label, hog->chip_label))
|
||||||
|
gpiochip_machine_hog(chip, hog);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&gpio_machine_hogs_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
static void gpiochip_setup_devs(void)
|
static void gpiochip_setup_devs(void)
|
||||||
{
|
{
|
||||||
struct gpio_device *gdev;
|
struct gpio_device *gdev;
|
||||||
|
@ -1244,6 +1286,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
||||||
goto err_free_descs;
|
goto err_free_descs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chip->ngpio > FASTPATH_NGPIO)
|
||||||
|
chip_warn(chip, "line cnt %u is greater than fast path cnt %u\n",
|
||||||
|
chip->ngpio, FASTPATH_NGPIO);
|
||||||
|
|
||||||
gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL);
|
gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL);
|
||||||
if (!gdev->label) {
|
if (!gdev->label) {
|
||||||
status = -ENOMEM;
|
status = -ENOMEM;
|
||||||
|
@ -1327,6 +1373,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
||||||
|
|
||||||
acpi_gpiochip_add(chip);
|
acpi_gpiochip_add(chip);
|
||||||
|
|
||||||
|
machine_gpiochip_add(chip);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* By first adding the chardev, and then adding the device,
|
* By first adding the chardev, and then adding the device,
|
||||||
* we get a device node entry in sysfs under
|
* we get a device node entry in sysfs under
|
||||||
|
@ -2729,16 +2777,28 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
||||||
|
|
||||||
while (i < array_size) {
|
while (i < array_size) {
|
||||||
struct gpio_chip *chip = desc_array[i]->gdev->chip;
|
struct gpio_chip *chip = desc_array[i]->gdev->chip;
|
||||||
unsigned long mask[BITS_TO_LONGS(chip->ngpio)];
|
unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
|
||||||
unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
|
unsigned long *mask, *bits;
|
||||||
int first, j, ret;
|
int first, j, ret;
|
||||||
|
|
||||||
|
if (likely(chip->ngpio <= FASTPATH_NGPIO)) {
|
||||||
|
mask = fastpath;
|
||||||
|
} else {
|
||||||
|
mask = kmalloc_array(2 * BITS_TO_LONGS(chip->ngpio),
|
||||||
|
sizeof(*mask),
|
||||||
|
can_sleep ? GFP_KERNEL : GFP_ATOMIC);
|
||||||
|
if (!mask)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
bits = mask + BITS_TO_LONGS(chip->ngpio);
|
||||||
|
bitmap_zero(mask, chip->ngpio);
|
||||||
|
|
||||||
if (!can_sleep)
|
if (!can_sleep)
|
||||||
WARN_ON(chip->can_sleep);
|
WARN_ON(chip->can_sleep);
|
||||||
|
|
||||||
/* collect all inputs belonging to the same chip */
|
/* collect all inputs belonging to the same chip */
|
||||||
first = i;
|
first = i;
|
||||||
memset(mask, 0, sizeof(mask));
|
|
||||||
do {
|
do {
|
||||||
const struct gpio_desc *desc = desc_array[i];
|
const struct gpio_desc *desc = desc_array[i];
|
||||||
int hwgpio = gpio_chip_hwgpio(desc);
|
int hwgpio = gpio_chip_hwgpio(desc);
|
||||||
|
@ -2749,8 +2809,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
||||||
(desc_array[i]->gdev->chip == chip));
|
(desc_array[i]->gdev->chip == chip));
|
||||||
|
|
||||||
ret = gpio_chip_get_multiple(chip, mask, bits);
|
ret = gpio_chip_get_multiple(chip, mask, bits);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
if (mask != fastpath)
|
||||||
|
kfree(mask);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
for (j = first; j < i; j++) {
|
for (j = first; j < i; j++) {
|
||||||
const struct gpio_desc *desc = desc_array[j];
|
const struct gpio_desc *desc = desc_array[j];
|
||||||
|
@ -2762,6 +2825,9 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
||||||
value_array[j] = value;
|
value_array[j] = value;
|
||||||
trace_gpio_value(desc_to_gpio(desc), 1, value);
|
trace_gpio_value(desc_to_gpio(desc), 1, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mask != fastpath)
|
||||||
|
kfree(mask);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2945,7 +3011,7 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
int gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
||||||
unsigned int array_size,
|
unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array)
|
int *value_array)
|
||||||
|
@ -2954,14 +3020,26 @@ void gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
||||||
|
|
||||||
while (i < array_size) {
|
while (i < array_size) {
|
||||||
struct gpio_chip *chip = desc_array[i]->gdev->chip;
|
struct gpio_chip *chip = desc_array[i]->gdev->chip;
|
||||||
unsigned long mask[BITS_TO_LONGS(chip->ngpio)];
|
unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
|
||||||
unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
|
unsigned long *mask, *bits;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
if (likely(chip->ngpio <= FASTPATH_NGPIO)) {
|
||||||
|
mask = fastpath;
|
||||||
|
} else {
|
||||||
|
mask = kmalloc_array(2 * BITS_TO_LONGS(chip->ngpio),
|
||||||
|
sizeof(*mask),
|
||||||
|
can_sleep ? GFP_KERNEL : GFP_ATOMIC);
|
||||||
|
if (!mask)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
bits = mask + BITS_TO_LONGS(chip->ngpio);
|
||||||
|
bitmap_zero(mask, chip->ngpio);
|
||||||
|
|
||||||
if (!can_sleep)
|
if (!can_sleep)
|
||||||
WARN_ON(chip->can_sleep);
|
WARN_ON(chip->can_sleep);
|
||||||
|
|
||||||
memset(mask, 0, sizeof(mask));
|
|
||||||
do {
|
do {
|
||||||
struct gpio_desc *desc = desc_array[i];
|
struct gpio_desc *desc = desc_array[i];
|
||||||
int hwgpio = gpio_chip_hwgpio(desc);
|
int hwgpio = gpio_chip_hwgpio(desc);
|
||||||
|
@ -2992,7 +3070,11 @@ void gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
||||||
/* push collected bits to outputs */
|
/* push collected bits to outputs */
|
||||||
if (count != 0)
|
if (count != 0)
|
||||||
gpio_chip_set_multiple(chip, mask, bits);
|
gpio_chip_set_multiple(chip, mask, bits);
|
||||||
|
|
||||||
|
if (mask != fastpath)
|
||||||
|
kfree(mask);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3067,13 +3149,13 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
|
||||||
* This function should be called from contexts where we cannot sleep, and will
|
* This function should be called from contexts where we cannot sleep, and will
|
||||||
* complain if the GPIO chip functions potentially sleep.
|
* complain if the GPIO chip functions potentially sleep.
|
||||||
*/
|
*/
|
||||||
void gpiod_set_raw_array_value(unsigned int array_size,
|
int gpiod_set_raw_array_value(unsigned int array_size,
|
||||||
struct gpio_desc **desc_array, int *value_array)
|
struct gpio_desc **desc_array, int *value_array)
|
||||||
{
|
{
|
||||||
if (!desc_array)
|
if (!desc_array)
|
||||||
return;
|
return -EINVAL;
|
||||||
gpiod_set_array_value_complex(true, false, array_size, desc_array,
|
return gpiod_set_array_value_complex(true, false, array_size,
|
||||||
value_array);
|
desc_array, value_array);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
|
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
|
||||||
|
|
||||||
|
@ -3393,14 +3475,14 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
|
||||||
*
|
*
|
||||||
* This function is to be called from contexts that can sleep.
|
* This function is to be called from contexts that can sleep.
|
||||||
*/
|
*/
|
||||||
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array)
|
int *value_array)
|
||||||
{
|
{
|
||||||
might_sleep_if(extra_checks);
|
might_sleep_if(extra_checks);
|
||||||
if (!desc_array)
|
if (!desc_array)
|
||||||
return;
|
return -EINVAL;
|
||||||
gpiod_set_array_value_complex(true, true, array_size, desc_array,
|
return gpiod_set_array_value_complex(true, true, array_size, desc_array,
|
||||||
value_array);
|
value_array);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
|
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
|
||||||
|
@ -3473,6 +3555,33 @@ void gpiod_remove_lookup_table(struct gpiod_lookup_table *table)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table);
|
EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpiod_add_hogs() - register a set of GPIO hogs from machine code
|
||||||
|
* @hogs: table of gpio hog entries with a zeroed sentinel at the end
|
||||||
|
*/
|
||||||
|
void gpiod_add_hogs(struct gpiod_hog *hogs)
|
||||||
|
{
|
||||||
|
struct gpio_chip *chip;
|
||||||
|
struct gpiod_hog *hog;
|
||||||
|
|
||||||
|
mutex_lock(&gpio_machine_hogs_mutex);
|
||||||
|
|
||||||
|
for (hog = &hogs[0]; hog->chip_label; hog++) {
|
||||||
|
list_add_tail(&hog->list, &gpio_machine_hogs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The chip may have been registered earlier, so check if it
|
||||||
|
* exists and, if so, try to hog the line now.
|
||||||
|
*/
|
||||||
|
chip = find_chip_by_name(hog->chip_label);
|
||||||
|
if (chip)
|
||||||
|
gpiochip_machine_hog(chip, hog);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&gpio_machine_hogs_mutex);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(gpiod_add_hogs);
|
||||||
|
|
||||||
static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
|
static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
|
||||||
{
|
{
|
||||||
const char *dev_id = dev ? dev_name(dev) : NULL;
|
const char *dev_id = dev ? dev_name(dev) : NULL;
|
||||||
|
|
|
@ -188,7 +188,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
||||||
unsigned int array_size,
|
unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array);
|
int *value_array);
|
||||||
void gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
int gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
||||||
unsigned int array_size,
|
unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array);
|
int *value_array);
|
||||||
|
|
|
@ -233,7 +233,8 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell)
|
||||||
pdata->properties->idx = 0;
|
pdata->properties->idx = 0;
|
||||||
pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO;
|
pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO;
|
||||||
pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE;
|
pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE;
|
||||||
pdata->properties->irq = pdev->irq;
|
pdata->properties->irq[0] = pdev->irq;
|
||||||
|
pdata->properties->has_irq = true;
|
||||||
pdata->properties->irq_shared = true;
|
pdata->properties->irq_shared = true;
|
||||||
|
|
||||||
cell->platform_data = pdata;
|
cell->platform_data = pdata;
|
||||||
|
|
|
@ -116,7 +116,7 @@ int gpiod_get_raw_array_value(unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array);
|
int *value_array);
|
||||||
void gpiod_set_raw_value(struct gpio_desc *desc, int value);
|
void gpiod_set_raw_value(struct gpio_desc *desc, int value);
|
||||||
void gpiod_set_raw_array_value(unsigned int array_size,
|
int gpiod_set_raw_array_value(unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array);
|
int *value_array);
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array);
|
int *value_array);
|
||||||
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
|
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
|
||||||
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array);
|
int *value_array);
|
||||||
|
|
||||||
|
@ -369,12 +369,13 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
||||||
/* GPIO can never have been requested */
|
/* GPIO can never have been requested */
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
}
|
}
|
||||||
static inline void gpiod_set_raw_array_value(unsigned int array_size,
|
static inline int gpiod_set_raw_array_value(unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array)
|
int *value_array)
|
||||||
{
|
{
|
||||||
/* GPIO can never have been requested */
|
/* GPIO can never have been requested */
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc)
|
static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc)
|
||||||
|
@ -423,12 +424,13 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
|
||||||
/* GPIO can never have been requested */
|
/* GPIO can never have been requested */
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
}
|
}
|
||||||
static inline void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array)
|
int *value_array)
|
||||||
{
|
{
|
||||||
/* GPIO can never have been requested */
|
/* GPIO can never have been requested */
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
|
static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
|
||||||
|
|
|
@ -39,6 +39,23 @@ struct gpiod_lookup_table {
|
||||||
struct gpiod_lookup table[];
|
struct gpiod_lookup table[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct gpiod_hog - GPIO line hog table
|
||||||
|
* @chip_label: name of the chip the GPIO belongs to
|
||||||
|
* @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO
|
||||||
|
* @line_name: consumer name for the hogged line
|
||||||
|
* @lflags: mask of GPIO lookup flags
|
||||||
|
* @dflags: GPIO flags used to specify the direction and value
|
||||||
|
*/
|
||||||
|
struct gpiod_hog {
|
||||||
|
struct list_head list;
|
||||||
|
const char *chip_label;
|
||||||
|
u16 chip_hwnum;
|
||||||
|
const char *line_name;
|
||||||
|
enum gpio_lookup_flags lflags;
|
||||||
|
int dflags;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Simple definition of a single GPIO under a con_id
|
* Simple definition of a single GPIO under a con_id
|
||||||
*/
|
*/
|
||||||
|
@ -59,10 +76,23 @@ struct gpiod_lookup_table {
|
||||||
.flags = _flags, \
|
.flags = _flags, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple definition of a single GPIO hog in an array.
|
||||||
|
*/
|
||||||
|
#define GPIO_HOG(_chip_label, _chip_hwnum, _line_name, _lflags, _dflags) \
|
||||||
|
{ \
|
||||||
|
.chip_label = _chip_label, \
|
||||||
|
.chip_hwnum = _chip_hwnum, \
|
||||||
|
.line_name = _line_name, \
|
||||||
|
.lflags = _lflags, \
|
||||||
|
.dflags = _dflags, \
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_GPIOLIB
|
#ifdef CONFIG_GPIOLIB
|
||||||
void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
|
void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
|
||||||
void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n);
|
void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n);
|
||||||
void gpiod_remove_lookup_table(struct gpiod_lookup_table *table);
|
void gpiod_remove_lookup_table(struct gpiod_lookup_table *table);
|
||||||
|
void gpiod_add_hogs(struct gpiod_hog *hogs);
|
||||||
#else
|
#else
|
||||||
static inline
|
static inline
|
||||||
void gpiod_add_lookup_table(struct gpiod_lookup_table *table) {}
|
void gpiod_add_lookup_table(struct gpiod_lookup_table *table) {}
|
||||||
|
@ -70,6 +100,7 @@ static inline
|
||||||
void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) {}
|
void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) {}
|
||||||
static inline
|
static inline
|
||||||
void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) {}
|
void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) {}
|
||||||
|
static inline void gpiod_add_hogs(struct gpiod_hog *hogs) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __LINUX_GPIO_MACHINE_H */
|
#endif /* __LINUX_GPIO_MACHINE_H */
|
||||||
|
|
|
@ -19,7 +19,8 @@ struct dwapb_port_property {
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
unsigned int ngpio;
|
unsigned int ngpio;
|
||||||
unsigned int gpio_base;
|
unsigned int gpio_base;
|
||||||
unsigned int irq;
|
int irq[32];
|
||||||
|
bool has_irq;
|
||||||
bool irq_shared;
|
bool irq_shared;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue