Commit 828907ef authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v5.7-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 development for the v5.7 kernel cycle.

  Core and userspace API:

   - The userspace API KFIFOs have been imoproved with locks that do not
     block interrupts. This makes us better at getting events to
     userspace without blocking or disturbing new events arriving in the
     same time. This was reviewed by the KFIFO maintainer Stefani. This
     is a generic improvement which paves the road for similar
     improvements in other subsystems.

   - We provide a new ioctl() for monitoring changes in the line
     information, such as when multiple clients are taking lines and
     giving them back, possibly reconfiguring them in the process: we
     can now monitor that and not get stuck with stale static
     information.

   - An example tool 'gpio-watch' is provided to showcase this
     functionality.

   - Timestamps for events are switched to ktime_get_ns() which is
     monotonic. We previously had a 'realtime' stamp which could move
     forward and *backward* in time, which probably would just cause
     silent bugs and weird behaviour. In the long run we see two
     relevant timestamps: ktime_get_ns() or the timestamp sometimes
     provided by the GPIO hardware itself, if that exists.

   - Device Tree overlay support for GPIO hogs. On systems that load
     overlays, these overlays can now contain hogs, and will then be
     respected.

   - Handle pin control interaction with nonexisting pin ranges in the
     GPIO library core instead of in the individual drivers.

  New drivers:

   - New driver for the Mellanox BlueField 2 GPIO controller.

  Driver improvements:

   - Introduce the BGPIOF_NO_SET_ON_INPUT flag to the generic MMIO GPIO
     library and use this flag in the MT7621 driver.

   - Texas Instruments OMAP CPU power management improvements, such as
     blocking of idle on pending GPIO interrupts"

* tag 'gpio-v5.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (59 commits)
  Revert "gpio: eic-sprd: Use devm_platform_ioremap_resource()"
  pinctrl: Unconditionally assign .request()/.free()
  gpio: Unconditionally assign .request()/.free()
  gpio: export of_pinctrl_get to modules
  pinctrl: Define of_pinctrl_get() dummy for !PINCTRL
  gpio: Rename variable in core APIs
  gpio: Avoid using pin ranges with !PINCTRL
  gpiolib: Remove unused gpio_chip parameter from gpio_set_bias()
  gpiolib: Pass gpio_desc to gpio_set_config()
  gpiolib: Introduce gpiod_set_config()
  tools: gpio: Fix out-of-tree build regression
  gpio: gpiolib: fix a doc warning
  gpio: tegra186: Add Tegra194 pin ranges for GG.0 and GG.1
  gpio: tegra186: Add support for pin ranges
  gpio: Support GPIO controllers without pin-ranges
  ARM: integrator: impd1: Use GPIO_LOOKUP() helper macro
  gpio: brcmstb: support gpio-line-names property
  tools: gpio: Fix typo in gpio-utils
  tools: gpio-hammer: Apply scripts/Lindent and retain good changes
  gpiolib: gpio_name_to_desc: factor out !name check
  ...
parents 6f43bae3 4ed7d7dd
...@@ -416,7 +416,7 @@ The preferred way to set up the helpers is to fill in the ...@@ -416,7 +416,7 @@ The preferred way to set up the helpers is to fill in the
struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip. struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
If you do this, the additional irq_chip will be set up by gpiolib at the If you do this, the additional irq_chip will be set up by gpiolib at the
same time as setting up the rest of the GPIO functionality. The following same time as setting up the rest of the GPIO functionality. The following
is a typical example of a cascaded interrupt handler using gpio_irq_chip:: is a typical example of a cascaded interrupt handler using gpio_irq_chip:
.. code-block:: c .. code-block:: c
...@@ -453,7 +453,7 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip:: ...@@ -453,7 +453,7 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip::
return devm_gpiochip_add_data(dev, &g->gc, g); return devm_gpiochip_add_data(dev, &g->gc, g);
The helper support using hierarchical interrupt controllers as well. The helper support using hierarchical interrupt controllers as well.
In this case the typical set-up will look like this:: In this case the typical set-up will look like this:
.. code-block:: c .. code-block:: c
......
...@@ -410,13 +410,10 @@ static int __ref impd1_probe(struct lm_device *dev) ...@@ -410,13 +410,10 @@ static int __ref impd1_probe(struct lm_device *dev)
* 5 = Key lower right * 5 = Key lower right
*/ */
/* We need the two MMCI GPIO entries */ /* We need the two MMCI GPIO entries */
lookup->table[0].chip_label = chipname; lookup->table[0] = (struct gpiod_lookup)
lookup->table[0].chip_hwnum = 3; GPIO_LOOKUP(chipname, 3, "wp", 0);
lookup->table[0].con_id = "wp"; lookup->table[1] = (struct gpiod_lookup)
lookup->table[1].chip_label = chipname; GPIO_LOOKUP(chipname, 4, "cd", GPIO_ACTIVE_LOW);
lookup->table[1].chip_hwnum = 4;
lookup->table[1].con_id = "cd";
lookup->table[1].flags = GPIO_ACTIVE_LOW;
gpiod_add_lookup_table(lookup); gpiod_add_lookup_table(lookup);
} }
......
...@@ -109,6 +109,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, ...@@ -109,6 +109,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
int index) int index)
{ {
struct omap3_idle_statedata *cx = &omap3_idle_data[index]; struct omap3_idle_statedata *cx = &omap3_idle_data[index];
int error;
if (omap_irq_pending() || need_resched()) if (omap_irq_pending() || need_resched())
goto return_sleep_time; goto return_sleep_time;
...@@ -125,8 +126,11 @@ static int omap3_enter_idle(struct cpuidle_device *dev, ...@@ -125,8 +126,11 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
* Call idle CPU PM enter notifier chain so that * Call idle CPU PM enter notifier chain so that
* VFP context is saved. * VFP context is saved.
*/ */
if (cx->mpu_state == PWRDM_POWER_OFF) if (cx->mpu_state == PWRDM_POWER_OFF) {
cpu_pm_enter(); error = cpu_pm_enter();
if (error)
goto out_clkdm_set;
}
/* Execute ARM wfi */ /* Execute ARM wfi */
omap_sram_idle(); omap_sram_idle();
...@@ -139,6 +143,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, ...@@ -139,6 +143,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF) pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF)
cpu_pm_exit(); cpu_pm_exit();
out_clkdm_set:
/* Re-allow idle for C1 */ /* Re-allow idle for C1 */
if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE)
clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]); clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]);
......
...@@ -122,6 +122,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -122,6 +122,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
{ {
struct idle_statedata *cx = state_ptr + index; struct idle_statedata *cx = state_ptr + index;
u32 mpuss_can_lose_context = 0; u32 mpuss_can_lose_context = 0;
int error;
/* /*
* CPU0 has to wait and stay ON until CPU1 is OFF state. * CPU0 has to wait and stay ON until CPU1 is OFF state.
...@@ -159,7 +160,9 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -159,7 +160,9 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
* Call idle CPU PM enter notifier chain so that * Call idle CPU PM enter notifier chain so that
* VFP and per CPU interrupt context is saved. * VFP and per CPU interrupt context is saved.
*/ */
cpu_pm_enter(); error = cpu_pm_enter();
if (error)
goto cpu_pm_out;
if (dev->cpu == 0) { if (dev->cpu == 0) {
pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state); pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
...@@ -169,13 +172,17 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -169,13 +172,17 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
* Call idle CPU cluster PM enter notifier chain * Call idle CPU cluster PM enter notifier chain
* to save GIC and wakeupgen context. * to save GIC and wakeupgen context.
*/ */
if (mpuss_can_lose_context) if (mpuss_can_lose_context) {
cpu_cluster_pm_enter(); error = cpu_cluster_pm_enter();
if (error)
goto cpu_cluster_pm_out;
}
} }
omap4_enter_lowpower(dev->cpu, cx->cpu_state); omap4_enter_lowpower(dev->cpu, cx->cpu_state);
cpu_done[dev->cpu] = true; cpu_done[dev->cpu] = true;
cpu_cluster_pm_out:
/* Wakeup CPU1 only if it is not offlined */ /* Wakeup CPU1 only if it is not offlined */
if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) {
...@@ -197,12 +204,6 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -197,12 +204,6 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
} }
} }
/*
* Call idle CPU PM exit notifier chain to restore
* VFP and per CPU IRQ context.
*/
cpu_pm_exit();
/* /*
* Call idle CPU cluster PM exit notifier chain * Call idle CPU cluster PM exit notifier chain
* to restore GIC and wakeupgen context. * to restore GIC and wakeupgen context.
...@@ -210,6 +211,13 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, ...@@ -210,6 +211,13 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
if (dev->cpu == 0 && mpuss_can_lose_context) if (dev->cpu == 0 && mpuss_can_lose_context)
cpu_cluster_pm_exit(); cpu_cluster_pm_exit();
/*
* Call idle CPU PM exit notifier chain to restore
* VFP and per CPU IRQ context.
*/
cpu_pm_exit();
cpu_pm_out:
tick_broadcast_exit(); tick_broadcast_exit();
fail: fail:
......
...@@ -191,6 +191,7 @@ void omap_sram_idle(void) ...@@ -191,6 +191,7 @@ void omap_sram_idle(void)
int per_next_state = PWRDM_POWER_ON; int per_next_state = PWRDM_POWER_ON;
int core_next_state = PWRDM_POWER_ON; int core_next_state = PWRDM_POWER_ON;
u32 sdrc_pwr = 0; u32 sdrc_pwr = 0;
int error;
mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
switch (mpu_next_state) { switch (mpu_next_state) {
...@@ -219,8 +220,11 @@ void omap_sram_idle(void) ...@@ -219,8 +220,11 @@ void omap_sram_idle(void)
pwrdm_pre_transition(NULL); pwrdm_pre_transition(NULL);
/* PER */ /* PER */
if (per_next_state == PWRDM_POWER_OFF) if (per_next_state == PWRDM_POWER_OFF) {
cpu_cluster_pm_enter(); error = cpu_cluster_pm_enter();
if (error)
return;
}
/* CORE */ /* CORE */
if (core_next_state < PWRDM_POWER_ON) { if (core_next_state < PWRDM_POWER_ON) {
......
...@@ -394,13 +394,13 @@ config GPIO_MVEBU ...@@ -394,13 +394,13 @@ config GPIO_MVEBU
config GPIO_MXC config GPIO_MXC
def_bool y def_bool y
depends on ARCH_MXC depends on ARCH_MXC || COMPILE_TEST
select GPIO_GENERIC select GPIO_GENERIC
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
config GPIO_MXS config GPIO_MXS
def_bool y def_bool y
depends on ARCH_MXS depends on ARCH_MXS || COMPILE_TEST
select GPIO_GENERIC select GPIO_GENERIC
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
...@@ -1399,6 +1399,13 @@ config GPIO_MLXBF ...@@ -1399,6 +1399,13 @@ config GPIO_MLXBF
help help
Say Y here if you want GPIO support on Mellanox BlueField SoC. Say Y here if you want GPIO support on Mellanox BlueField SoC.
config GPIO_MLXBF2
tristate "Mellanox BlueField 2 SoC GPIO"
depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || (64BIT && COMPILE_TEST)
select GPIO_GENERIC
help
Say Y here if you want GPIO support on Mellanox BlueField 2 SoC.
config GPIO_ML_IOH config GPIO_ML_IOH
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
depends on X86 || COMPILE_TEST depends on X86 || COMPILE_TEST
......
...@@ -93,6 +93,7 @@ obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o ...@@ -93,6 +93,7 @@ obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o obj-$(CONFIG_GPIO_MLXBF) += gpio-mlxbf.o
obj-$(CONFIG_GPIO_MLXBF2) += gpio-mlxbf2.o
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o
......
...@@ -603,6 +603,49 @@ static const struct dev_pm_ops brcmstb_gpio_pm_ops = { ...@@ -603,6 +603,49 @@ static const struct dev_pm_ops brcmstb_gpio_pm_ops = {
.resume_noirq = brcmstb_gpio_resume, .resume_noirq = brcmstb_gpio_resume,
}; };
static void brcmstb_gpio_set_names(struct device *dev,
struct brcmstb_gpio_bank *bank)
{
struct device_node *np = dev->of_node;
const char **names;
int nstrings, base;
unsigned int i;
base = bank->id * MAX_GPIO_PER_BANK;
nstrings = of_property_count_strings(np, "gpio-line-names");
if (nstrings <= base)
/* Line names not present */
return;
names = devm_kcalloc(dev, MAX_GPIO_PER_BANK, sizeof(*names),
GFP_KERNEL);
if (!names)
return;
/*
* Make sure to not index beyond the end of the number of descriptors
* of the GPIO device.
*/
for (i = 0; i < bank->width; i++) {
const char *name;
int ret;
ret = of_property_read_string_index(np, "gpio-line-names",
base + i, &name);
if (ret) {
if (ret != -ENODATA)
dev_err(dev, "unable to name line %d: %d\n",
base + i, ret);
break;
}
if (*name)
names[i] = name;
}
bank->gc.names = names;
}
static int brcmstb_gpio_probe(struct platform_device *pdev) static int brcmstb_gpio_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -726,6 +769,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) ...@@ -726,6 +769,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
gc->write_reg(reg_base + GIO_MASK(bank->id), 0); gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
brcmstb_gpio_set_names(dev, bank);
err = gpiochip_add_data(gc, bank); err = gpiochip_add_data(gc, bank);
if (err) { if (err) {
dev_err(dev, "Could not add gpiochip for bank %d\n", dev_err(dev, "Could not add gpiochip for bank %d\n",
......
...@@ -259,11 +259,8 @@ static int davinci_gpio_probe(struct platform_device *pdev) ...@@ -259,11 +259,8 @@ static int davinci_gpio_probe(struct platform_device *pdev)
chips->chip.of_gpio_n_cells = 2; chips->chip.of_gpio_n_cells = 2;
chips->chip.parent = dev; chips->chip.parent = dev;
chips->chip.of_node = dev->of_node; chips->chip.of_node = dev->of_node;
chips->chip.request = gpiochip_generic_request;
if (of_property_read_bool(dev->of_node, "gpio-ranges")) { chips->chip.free = gpiochip_generic_free;
chips->chip.request = gpiochip_generic_request;
chips->chip.free = gpiochip_generic_free;
}
#endif #endif
spin_lock_init(&chips->lock); spin_lock_init(&chips->lock);
......
...@@ -569,6 +569,7 @@ static int sprd_eic_probe(struct platform_device *pdev) ...@@ -569,6 +569,7 @@ static int sprd_eic_probe(struct platform_device *pdev)
const struct sprd_eic_variant_data *pdata; const struct sprd_eic_variant_data *pdata;
struct gpio_irq_chip *irq; struct gpio_irq_chip *irq;
struct sprd_eic *sprd_eic; struct sprd_eic *sprd_eic;
struct resource *res;
int ret, i; int ret, i;
pdata = of_device_get_match_data(&pdev->dev); pdata = of_device_get_match_data(&pdev->dev);
...@@ -595,9 +596,13 @@ static int sprd_eic_probe(struct platform_device *pdev) ...@@ -595,9 +596,13 @@ static int sprd_eic_probe(struct platform_device *pdev)
* have one bank EIC, thus base[1] and base[2] can be * have one bank EIC, thus base[1] and base[2] can be
* optional. * optional.
*/ */
sprd_eic->base[i] = devm_platform_ioremap_resource(pdev, i); res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (IS_ERR(sprd_eic->base[i])) if (!res)
continue; continue;
sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(sprd_eic->base[i]))
return PTR_ERR(sprd_eic->base[i]);
} }
sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type]; sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type];
......
// SPDX-License-Identifier: GPL-2.0
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/resource.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/version.h>
/*
* There are 3 YU GPIO blocks:
* gpio[0]: HOST_GPIO0->HOST_GPIO31
* gpio[1]: HOST_GPIO32->HOST_GPIO63
* gpio[2]: HOST_GPIO64->HOST_GPIO69
*/
#define MLXBF2_GPIO_MAX_PINS_PER_BLOCK 32
/*
* arm_gpio_lock register:
* bit[31] lock status: active if set
* bit[15:0] set lock
* The lock is enabled only if 0xd42f is written to this field
*/
#define YU_ARM_GPIO_LOCK_ADDR 0x2801088
#define YU_ARM_GPIO_LOCK_SIZE 0x8
#define YU_LOCK_ACTIVE_BIT(val) (val >> 31)
#define YU_ARM_GPIO_LOCK_ACQUIRE 0xd42f
#define YU_ARM_GPIO_LOCK_RELEASE 0x0
/*
* gpio[x] block registers and their offset
*/
#define YU_GPIO_DATAIN 0x04
#define YU_GPIO_MODE1 0x08
#define YU_GPIO_MODE0 0x0c
#define YU_GPIO_DATASET 0x14
#define YU_GPIO_DATACLEAR 0x18
#define YU_GPIO_MODE1_CLEAR 0x50
#define YU_GPIO_MODE0_SET 0x54
#define YU_GPIO_MODE0_CLEAR 0x58
#ifdef CONFIG_PM
struct mlxbf2_gpio_context_save_regs {
u32 gpio_mode0;
u32 gpio_mode1;
};
#endif
/* BlueField-2 gpio block context structure. */
struct mlxbf2_gpio_context {
struct gpio_chip gc;
/* YU GPIO blocks address */
void __iomem *gpio_io;
#ifdef CONFIG_PM
struct mlxbf2_gpio_context_save_regs *csave_regs;
#endif
};
/* BlueField-2 gpio shared structure. */
struct mlxbf2_gpio_param {
void __iomem *io;
struct resource *res;
struct mutex *lock;
};
static struct resource yu_arm_gpio_lock_res = {
.start = YU_ARM_GPIO_LOCK_ADDR,
.end = YU_ARM_GPIO_LOCK_ADDR + YU_ARM_GPIO_LOCK_SIZE - 1,
.name = "YU_ARM_GPIO_LOCK",
};
static DEFINE_MUTEX(yu_arm_gpio_lock_mutex);
static struct mlxbf2_gpio_param yu_arm_gpio_lock_param = {
.res = &yu_arm_gpio_lock_res,
.lock = &yu_arm_gpio_lock_mutex,
};
/* Request memory region and map yu_arm_gpio_lock resource */
static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
resource_size_t size;
int ret = 0;
mutex_lock(yu_arm_gpio_lock_param.lock);
/* Check if the memory map already exists */
if (yu_arm_gpio_lock_param.io)
goto exit;
res = yu_arm_gpio_lock_param.res;
size = resource_size(res);
if (!devm_request_mem_region(dev, res->start, size, res->name)) {
ret = -EFAULT;
goto exit;
}
yu_arm_gpio_lock_param.io = devm_ioremap(dev, res->start, size);
if (IS_ERR(yu_arm_gpio_lock_param.io))
ret = PTR_ERR(yu_arm_gpio_lock_param.io);
exit:
mutex_unlock(yu_arm_gpio_lock_param.lock);
return ret;
}
/*
* Acquire the YU arm_gpio_lock to be able to change the direction
* mode. If the lock_active bit is already set, return an error.
*/
static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs)
{
u32 arm_gpio_lock_val;
spin_lock(&gs->gc.bgpio_lock);
mutex_lock(yu_arm_gpio_lock_param.lock);
arm_gpio_lock_val = readl(yu_arm_gpio_lock_param.io);
/*
* When lock active bit[31] is set, ModeX is write enabled
*/
if (YU_LOCK_ACTIVE_BIT(arm_gpio_lock_val)) {
mutex_unlock(yu_arm_gpio_lock_param.lock);
spin_unlock(&gs->gc.bgpio_lock);
return -EINVAL;
}
writel(YU_ARM_GPIO_LOCK_ACQUIRE, yu_arm_gpio_lock_param.io);
return 0;
}
/*
* Release the YU arm_gpio_lock after changing the direction mode.
*/
static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs)
{
writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io);
mutex_unlock(yu_arm_gpio_lock_param.lock);
spin_unlock(&gs->gc.bgpio_lock);
}
/*
* mode0 and mode1 are both locked by the gpio_lock field.
*
* Together, mode0 and mode1 define the gpio Mode dependeing also
* on Reg_DataOut.
*
* {mode1,mode0}:{Reg_DataOut=0,Reg_DataOut=1}->{DataOut=0,DataOut=1}
*
* {0,0}:Reg_DataOut{0,1}->{Z,Z} Input PAD
* {0,1}:Reg_DataOut{0,1}->{0,1} Full drive Output PAD
* {1,0}:Reg_DataOut{0,1}->{0,Z} 0-set PAD to low, 1-float
* {1,1}:Reg_DataOut{0,1}->{Z,1} 0-float, 1-set PAD to high
*/
/*
* Set input direction:
* {mode1,mode0} = {0,0}
*/
static int mlxbf2_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip);
int ret;
/*
* Although the arm_gpio_lock was set in the probe function, check again
* if it is still enabled to be able to write to the ModeX registers.
*/
ret = mlxbf2_gpio_lock_acquire(gs);
if (ret < 0)
return ret;
writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_CLEAR);
writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR);
mlxbf2_gpio_lock_release(gs);
return ret;
}
/*
* Set output direction:
* {mode1,mode0} = {0,1}
*/
static int mlxbf2_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset,
int value)
{
struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip);
int ret = 0;
/*
* Although the arm_gpio_lock was set in the probe function,
* check again it is still enabled to be able to write to the
* ModeX registers.
*/
ret = mlxbf2_gpio_lock_acquire(gs);
if (ret < 0)
return ret;
writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR);
writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_SET);
mlxbf2_gpio_lock_release(gs);
return ret;
}
/* BlueField-2 GPIO driver initialization routine. */
static int
mlxbf2_gpio_probe(struct platform_device *pdev)
{
struct mlxbf2_gpio_context *gs;
struct device *dev = &pdev->dev;
struct gpio_chip *gc;
struct resource *res;
unsigned int npins;
int ret;
gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL);
if (!gs)
return -ENOMEM;
/* YU GPIO block address */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
gs->gpio_io = devm_ioremap(dev, res->start, resource_size(res));
if (!gs->gpio_io)
return -ENOMEM;
ret = mlxbf2_gpio_get_lock_res(pdev);
if (ret) {
dev_err(dev, "Failed to get yu_arm_gpio_lock resource\n");
return ret;
}
if (device_property_read_u32(dev, "npins", &npins))
npins = MLXBF2_GPIO_MAX_PINS_PER_BLOCK;
gc = &gs->gc;
ret = bgpio_init(gc, dev, 4,
gs->gpio_io + YU_GPIO_DATAIN,
gs->gpio_io + YU_GPIO_DATASET,
gs->gpio_io + YU_GPIO_DATACLEAR,
NULL,
NULL,
0);
gc->direction_input = mlxbf2_gpio_direction_input;
gc->direction_output = mlxbf2_gpio_direction_output;
gc->ngpio = npins;
gc->owner = THIS_MODULE;
platform_set_drvdata(pdev, gs);
ret = devm_gpiochip_add_data(dev, &gs->gc, gs);
if (ret) {
dev_err(dev, "Failed adding memory mapped gpiochip\n");
return ret;
}
return 0;
}
#ifdef CONFIG_PM
static int mlxbf2_gpio_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev);
gs->csave_regs->gpio_mode0 = readl(gs->gpio_io +
YU_GPIO_MODE0);
gs->csave_regs->gpio_mode1 = readl(gs->gpio_io +
YU_GPIO_MODE1);
return 0;
}
static int mlxbf2_gpio_resume(struct platform_device *pdev)
{
struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev);
writel(gs->csave_regs->gpio_mode0, gs->gpio_io +
YU_GPIO_MODE0);
writel(gs->csave_regs->gpio_mode1, gs->gpio_io +
YU_GPIO_MODE1);
return 0;
}
#endif
static const struct acpi_device_id mlxbf2_gpio_acpi_match[] = {
{ "MLNXBF22", 0 },
{},
};
MODULE_DEVICE_TABLE(acpi, mlxbf2_gpio_acpi_match);
static struct platform_driver mlxbf2_gpio_driver = {
.driver = {
.name = "mlxbf2_gpio",
.acpi_match_table = ACPI_PTR(mlxbf2_gpio_acpi_match),
},
.probe = mlxbf2_gpio_probe,
#ifdef CONFIG_PM
.suspend = mlxbf2_gpio_suspend,
.resume = mlxbf2_gpio_resume,
#endif
};
module_platform_driver(mlxbf2_gpio_driver);
MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver");
MODULE_AUTHOR("Mellanox Technologies");
MODULE_LICENSE("GPL v2");
...@@ -389,12 +389,10 @@ static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) ...@@ -389,12 +389,10 @@ static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
return GPIO_LINE_DIRECTION_IN; return GPIO_LINE_DIRECTION_IN;
} }
static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{ {
unsigned long flags; unsigned long flags;
gc->set(gc, gpio, val);
spin_lock_irqsave(&gc->bgpio_lock, flags); spin_lock_irqsave(&gc->bgpio_lock, flags);
gc->bgpio_dir |= bgpio_line2mask(gc, gpio); gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
...@@ -405,7 +403,21 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) ...@@ -405,7 +403,21 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
spin_unlock_irqrestore(&gc->bgpio_lock, flags); spin_unlock_irqrestore(&gc->bgpio_lock, flags);
}
static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
int val)
{
bgpio_dir_out(gc, gpio, val);
gc->set(gc, gpio, val);
return 0;
}
static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
int val)
{
gc->set(gc, gpio, val);
bgpio_dir_out(gc, gpio, val);
return 0; return 0;
} }
...@@ -538,7 +550,10 @@ static int bgpio_setup_direction(struct gpio_chip *gc, ...@@ -538,7 +550,10 @@ static int bgpio_setup_direction(struct gpio_chip *gc,
if (dirout || dirin) { if (dirout || dirin) {
gc->reg_dir_out = dirout; gc->reg_dir_out = dirout;
gc->reg_dir_in = dirin; gc->reg_dir_in = dirin;
gc->direction_output = bgpio_dir_out; if (flags & BGPIOF_NO_SET_ON_INPUT)
gc->direction_output = bgpio_dir_out_dir_first;
else
gc->direction_output = bgpio_dir_out_val_first;
gc->direction_input = bgpio_dir_in; gc->direction_input = bgpio_dir_in;
gc->get_direction = bgpio_get_dir; gc->get_direction = bgpio_get_dir;
} else { } else {
......
...@@ -171,7 +171,7 @@ static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip, ...@@ -171,7 +171,7 @@ static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip,
/* Change the value unless we're actively driving the line. */ /* Change the value unless we're actively driving the line. */
if (!test_bit(FLAG_REQUESTED, &desc->flags) || if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
!test_bit(FLAG_IS_OUT, &desc->flags)) !test_bit(FLAG_IS_OUT, &desc->flags))
__gpio_mockup_set(chip, offset, value); __gpio_mockup_set(chip, offset, value);
out: out:
......
...@@ -227,8 +227,8 @@ mediatek_gpio_bank_probe(struct device *dev, ...@@ -227,8 +227,8 @@ mediatek_gpio_bank_probe(struct device *dev,
ctrl = mtk->base + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_STRIDE); ctrl = mtk->base + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_STRIDE);
diro = mtk->base + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_STRIDE); diro = mtk->base + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_STRIDE);
ret = bgpio_init(&rg->chip, dev, 4, ret = bgpio_init(&rg->chip, dev, 4, dat, set, ctrl, diro, NULL,
dat, set, ctrl, diro, NULL, 0); BGPIOF_NO_SET_ON_INPUT);
if (ret) { if (ret) {
dev_err(dev, "bgpio_init() failed\n"); dev_err(dev, "bgpio_init() failed\n");
return ret; return ret;
......
...@@ -1247,7 +1247,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) ...@@ -1247,7 +1247,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
* pins. * pins.
*/ */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
int irq = platform_get_irq(pdev, i); int irq = platform_get_irq_optional(pdev, i);
if (irq < 0) if (irq < 0)
continue; continue;
......
...@@ -485,11 +485,8 @@ static int mxc_gpio_probe(struct platform_device *pdev) ...@@ -485,11 +485,8 @@ static int mxc_gpio_probe(struct platform_device *pdev)
if (err) if (err)
goto out_bgio; goto out_bgio;
if (of_property_read_bool(np, "gpio-ranges")) { port->gc.request = gpiochip_generic_request;
port->gc.request = gpiochip_generic_request; port->gc.free = gpiochip_generic_free;
port->gc.free = gpiochip_generic_free;
}
port->gc.to_irq = mxc_gpio_to_irq; port->gc.to_irq = mxc_gpio_to_irq;
port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 : port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
pdev->id * 32; pdev->id * 32;
......
...@@ -1102,23 +1102,13 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context) ...@@ -1102,23 +1102,13 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
{ {
struct device *dev = bank->chip.parent; struct device *dev = bank->chip.parent;
void __iomem *base = bank->base; void __iomem *base = bank->base;
u32 mask, nowake; u32 nowake;
bank->saved_datain = readl_relaxed(base + bank->regs->datain); bank->saved_datain = readl_relaxed(base + bank->regs->datain);
if (!bank->enabled_non_wakeup_gpios) if (!bank->enabled_non_wakeup_gpios)
goto update_gpio_context_count; goto update_gpio_context_count;
/* Check for pending EDGE_FALLING, ignore EDGE_BOTH */
mask = bank->enabled_non_wakeup_gpios & bank->context.fallingdetect;
mask &= ~bank->context.risingdetect;
bank->saved_datain |= mask;
/* Check for pending EDGE_RISING, ignore EDGE_BOTH */
mask = bank->enabled_non_wakeup_gpios & bank->context.risingdetect;
mask &= ~bank->context.fallingdetect;
bank->saved_datain &= ~mask;
if (!may_lose_context) if (!may_lose_context)
goto update_gpio_context_count; goto update_gpio_context_count;
...@@ -1237,26 +1227,35 @@ static int gpio_omap_cpu_notifier(struct notifier_block *nb, ...@@ -1237,26 +1227,35 @@ static int gpio_omap_cpu_notifier(struct notifier_block *nb,
{ {
struct gpio_bank *bank; struct gpio_bank *bank;
unsigned long flags; unsigned long flags;
int ret = NOTIFY_OK;
u32 isr, mask;
bank = container_of(nb, struct gpio_bank, nb); bank = container_of(nb, struct gpio_bank, nb);
raw_spin_lock_irqsave(&bank->lock, flags); raw_spin_lock_irqsave(&bank->lock, flags);
if (bank->is_suspended)
goto out_unlock;
switch (cmd) { switch (cmd) {
case CPU_CLUSTER_PM_ENTER: case CPU_CLUSTER_PM_ENTER:
if (bank->is_suspended) mask = omap_get_gpio_irqbank_mask(bank);
isr = readl_relaxed(bank->base + bank->regs->irqstatus) & mask;
if (isr) {
ret = NOTIFY_BAD;
break; break;
}
omap_gpio_idle(bank, true); omap_gpio_idle(bank, true);
break; break;
case CPU_CLUSTER_PM_ENTER_FAILED: case CPU_CLUSTER_PM_ENTER_FAILED:
case CPU_CLUSTER_PM_EXIT: case CPU_CLUSTER_PM_EXIT:
if (bank->is_suspended)
break;
omap_gpio_unidle(bank); omap_gpio_unidle(bank);
break; break;
} }
out_unlock:
raw_spin_unlock_irqrestore(&bank->lock, flags); raw_spin_unlock_irqrestore(&bank->lock, flags);
return NOTIFY_OK; return ret;
} }
static const struct omap_gpio_reg_offs omap2_gpio_regs = { static const struct omap_gpio_reg_offs omap2_gpio_regs = {
......
...@@ -298,11 +298,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -298,11 +298,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
return PTR_ERR(pl061->base); return PTR_ERR(pl061->base);
raw_spin_lock_init(&pl061->lock); raw_spin_lock_init(&pl061->lock);
if (of_property_read_bool(dev->of_node, "gpio-ranges")) { pl061->gc.request = gpiochip_generic_request;
pl061->gc.request = gpiochip_generic_request; pl061->gc.free = gpiochip_generic_free;
pl061->gc.free = gpiochip_generic_free;
}
pl061->gc.base = -1; pl061->gc.base = -1;
pl061->gc.get_direction = pl061_get_direction; pl061->gc.get_direction = pl061_get_direction;
pl061->gc.direction_input = pl061_direction_input; pl061->gc.direction_input = pl061_direction_input;
...@@ -326,10 +323,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -326,10 +323,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
writeb(0, pl061->base + GPIOIE); /* disable irqs */ writeb(0, pl061->base + GPIOIE); /* disable irqs */
irq = adev->irq[0]; irq = adev->irq[0];
if (irq < 0) { if (!irq)
dev_err(&adev->dev, "invalid IRQ\n"); dev_warn(&adev->dev, "IRQ support disabled\n");
return -ENODEV;
}
pl061->parent_irq = irq; pl061->parent_irq = irq;
girq = &pl061->gc.irq; girq = &pl061->gc.irq;
......
...@@ -361,11 +361,8 @@ static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio, ...@@ -361,11 +361,8 @@ static int pxa_init_gpio_chip(struct pxa_gpio_chip *pchip, int ngpio,
pchip->chip.set = pxa_gpio_set; pchip->chip.set = pxa_gpio_set;
pchip->chip.to_irq = pxa_gpio_to_irq; pchip->chip.to_irq = pxa_gpio_to_irq;
pchip->chip.ngpio = ngpio; pchip->chip.ngpio = ngpio;
pchip->chip.request = gpiochip_generic_request;
if (pxa_gpio_has_pinctrl()) { pchip->chip.free = gpiochip_generic_free;
pchip->chip.request = gpiochip_generic_request;
pchip->chip.free = gpiochip_generic_free;
}
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
pchip->chip.of_node = np; pchip->chip.of_node = np;
...@@ -652,8 +649,8 @@ static int pxa_gpio_probe(struct platform_device *pdev) ...@@ -652,8 +649,8 @@ static int pxa_gpio_probe(struct platform_device *pdev)
if (!pchip->irqdomain) if (!pchip->irqdomain)
return -ENOMEM; return -ENOMEM;
irq0 = platform_get_irq_byname(pdev, "gpio0"); irq0 = platform_get_irq_byname_optional(pdev, "gpio0");
irq1 = platform_get_irq_byname(pdev, "gpio1"); irq1 = platform_get_irq_byname_optional(pdev, "gpio1");
irq_mux = platform_get_irq_byname(pdev, "gpio_mux"); irq_mux = platform_get_irq_byname(pdev, "gpio_mux");
if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0) if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0)
|| (irq_mux <= 0)) || (irq_mux <= 0))
......
...@@ -116,7 +116,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, ...@@ -116,7 +116,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
spin_lock_irqsave(&p->lock, flags); spin_lock_irqsave(&p->lock, flags);
/* Configure postive or negative logic in POSNEG */ /* Configure positive or negative logic in POSNEG */
gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge); gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge);
/* Configure edge or level trigger in EDGLEVEL */ /* Configure edge or level trigger in EDGLEVEL */
...@@ -228,7 +228,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip, ...@@ -228,7 +228,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
spin_lock_irqsave(&p->lock, flags); spin_lock_irqsave(&p->lock, flags);
/* Configure postive logic in POSNEG */ /* Configure positive logic in POSNEG */
gpio_rcar_modify_bit(p, POSNEG, gpio, false); gpio_rcar_modify_bit(p, POSNEG, gpio, false);
/* Select "General Input/Output Mode" in IOINTSEL */ /* Select "General Input/Output Mode" in IOINTSEL */
......
...@@ -15,7 +15,7 @@ struct gpio_siox_ddata { ...@@ -15,7 +15,7 @@ struct gpio_siox_ddata {
u8 setdata[1]; u8 setdata[1];
u8 getdata[3]; u8 getdata[3];
spinlock_t irqlock; raw_spinlock_t irqlock;
u32 irq_enable; u32 irq_enable;
u32 irq_status; u32 irq_status;
u32 irq_type[20]; u32 irq_type[20];
...@@ -44,7 +44,7 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[]) ...@@ -44,7 +44,7 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
mutex_lock(&ddata->lock); mutex_lock(&ddata->lock);
spin_lock_irq(&ddata->irqlock); raw_spin_lock_irq(&ddata->irqlock);
for (offset = 0; offset < 12; ++offset) { for (offset = 0; offset < 12; ++offset) {
unsigned int bitpos = 11 - offset; unsigned int bitpos = 11 - offset;
...@@ -66,7 +66,7 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[]) ...@@ -66,7 +66,7 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
trigger = ddata->irq_status & ddata->irq_enable; trigger = ddata->irq_status & ddata->irq_enable;
spin_unlock_irq(&ddata->irqlock); raw_spin_unlock_irq(&ddata->irqlock);
ddata->getdata[0] = buf[0]; ddata->getdata[0] = buf[0];
ddata->getdata[1] = buf[1]; ddata->getdata[1] = buf[1];
...@@ -84,9 +84,9 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[]) ...@@ -84,9 +84,9 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
* handler of the irq chip. But it doesn't, so we have * handler of the irq chip. But it doesn't, so we have
* to clean the irq_status here. * to clean the irq_status here.
*/ */
spin_lock_irq(&ddata->irqlock); raw_spin_lock_irq(&ddata->irqlock);
ddata->irq_status &= ~(1 << offset); ddata->irq_status &= ~(1 << offset);
spin_unlock_irq(&ddata->irqlock); raw_spin_unlock_irq(&ddata->irqlock);
handle_nested_irq(irq); handle_nested_irq(irq);
} }
...@@ -101,9 +101,9 @@ static void gpio_siox_irq_ack(struct irq_data *d) ...@@ -101,9 +101,9 @@ static void gpio_siox_irq_ack(struct irq_data *d)
struct gpio_siox_ddata *ddata = struct gpio_siox_ddata *ddata =
container_of(ic, struct gpio_siox_ddata, ichip); container_of(ic, struct gpio_siox_ddata, ichip);
spin_lock_irq(&ddata->irqlock); raw_spin_lock(&ddata->irqlock);
ddata->irq_status &= ~(1 << d->hwirq); ddata->irq_status &= ~(1 << d->hwirq);
spin_unlock_irq(&ddata->irqlock); raw_spin_unlock(&ddata->irqlock);
} }
static void gpio_siox_irq_mask(struct irq_data *d) static void gpio_siox_irq_mask(struct irq_data *d)
...@@ -112,9 +112,9 @@ static void gpio_siox_irq_mask(struct irq_data *d) ...@@ -112,9 +112,9 @@ static void gpio_siox_irq_mask(struct irq_data *d)
struct gpio_siox_ddata *ddata = struct gpio_siox_ddata *ddata =
container_of(ic, struct gpio_siox_ddata, ichip); container_of(ic, struct gpio_siox_ddata, ichip);
spin_lock_irq(&ddata->irqlock); raw_spin_lock(&ddata->irqlock);
ddata->irq_enable &= ~(1 << d->hwirq); ddata->irq_enable &= ~(1 << d->hwirq);
spin_unlock_irq(&ddata->irqlock); raw_spin_unlock(&ddata->irqlock);
} }
static void gpio_siox_irq_unmask(struct irq_data *d) static void gpio_siox_irq_unmask(struct irq_data *d)
...@@ -123,9 +123,9 @@ static void gpio_siox_irq_unmask(struct irq_data *d) ...@@ -123,9 +123,9 @@ static void gpio_siox_irq_unmask(struct irq_data *d)
struct gpio_siox_ddata *ddata = struct gpio_siox_ddata *ddata =
container_of(ic, struct gpio_siox_ddata, ichip); container_of(ic, struct gpio_siox_ddata, ichip);
spin_lock_irq(&ddata->irqlock); raw_spin_lock(&ddata->irqlock);
ddata->irq_enable |= 1 << d->hwirq; ddata->irq_enable |= 1 << d->hwirq;
spin_unlock_irq(&ddata->irqlock); raw_spin_unlock(&ddata->irqlock);
} }
static int gpio_siox_irq_set_type(struct irq_data *d, u32 type) static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
...@@ -134,9 +134,9 @@ static int gpio_siox_irq_set_type(struct irq_data *d, u32 type) ...@@ -134,9 +134,9 @@ static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
struct gpio_siox_ddata *ddata = struct gpio_siox_ddata *ddata =
container_of(ic, struct gpio_siox_ddata, ichip); container_of(ic, struct gpio_siox_ddata, ichip);
spin_lock_irq(&ddata->irqlock); raw_spin_lock(&ddata->irqlock);
ddata->irq_type[d->hwirq] = type; ddata->irq_type[d->hwirq] = type;
spin_unlock_irq(&ddata->irqlock); raw_spin_unlock(&ddata->irqlock);
return 0; return 0;
} }
...@@ -222,7 +222,7 @@ static int gpio_siox_probe(struct siox_device *sdevice) ...@@ -222,7 +222,7 @@ static int gpio_siox_probe(struct siox_device *sdevice)
dev_set_drvdata(dev, ddata); dev_set_drvdata(dev, ddata);
mutex_init(&ddata->lock); mutex_init(&ddata->lock);
spin_lock_init(&ddata->irqlock); raw_spin_lock_init(&ddata->irqlock);
ddata->gchip.base = -1; ddata->gchip.base = -1;
ddata->gchip.can_sleep = 1; ddata->gchip.can_sleep = 1;
......
...@@ -58,11 +58,20 @@ struct tegra_gpio_port { ...@@ -58,11 +58,20 @@ struct tegra_gpio_port {
unsigned int pins; unsigned int pins;
}; };
struct tegra186_pin_range {
unsigned int offset;
const char *group;
};
struct tegra_gpio_soc { struct tegra_gpio_soc {
const struct tegra_gpio_port *ports; const struct tegra_gpio_port *ports;
unsigned int num_ports; unsigned int num_ports;
const char *name; const char *name;
unsigned int instance; unsigned int instance;
const struct tegra186_pin_range *pin_ranges;
unsigned int num_pin_ranges;
const char *pinmux;
}; };
struct tegra_gpio { struct tegra_gpio {
...@@ -254,6 +263,50 @@ static int tegra186_gpio_set_config(struct gpio_chip *chip, ...@@ -254,6 +263,50 @@ static int tegra186_gpio_set_config(struct gpio_chip *chip,
return 0; return 0;
} }
static int tegra186_gpio_add_pin_ranges(struct gpio_chip *chip)
{
struct tegra_gpio *gpio = gpiochip_get_data(chip);
struct pinctrl_dev *pctldev;
struct device_node *np;
unsigned int i, j;
int err;
if (!gpio->soc->pinmux || gpio->soc->num_pin_ranges == 0)
return 0;
np = of_find_compatible_node(NULL, NULL, gpio->soc->pinmux);
if (!np)
return -ENODEV;
pctldev = of_pinctrl_get(np);
of_node_put(np);
if (!pctldev)
return -EPROBE_DEFER;
for (i = 0; i < gpio->soc->num_pin_ranges; i++) {
unsigned int pin = gpio->soc->pin_ranges[i].offset, port;
const char *group = gpio->soc->pin_ranges[i].group;
port = pin / 8;
pin = pin % 8;
if (port >= gpio->soc->num_ports) {
dev_warn(chip->parent, "invalid port %u for %s\n",
port, group);
continue;
}
for (j = 0; j < port; j++)
pin += gpio->soc->ports[j].pins;
err = gpiochip_add_pingroup_range(chip, pctldev, pin, group);
if (err < 0)
return err;
}
return 0;
}
static int tegra186_gpio_of_xlate(struct gpio_chip *chip, static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
const struct of_phandle_args *spec, const struct of_phandle_args *spec,
u32 *flags) u32 *flags)
...@@ -578,12 +631,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev) ...@@ -578,12 +631,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->gpio.label = gpio->soc->name; gpio->gpio.label = gpio->soc->name;
gpio->gpio.parent = &pdev->dev; gpio->gpio.parent = &pdev->dev;
gpio->gpio.request = gpiochip_generic_request;
gpio->gpio.free = gpiochip_generic_free;
gpio->gpio.get_direction = tegra186_gpio_get_direction; gpio->gpio.get_direction = tegra186_gpio_get_direction;
gpio->gpio.direction_input = tegra186_gpio_direction_input; gpio->gpio.direction_input = tegra186_gpio_direction_input;
gpio->gpio.direction_output = tegra186_gpio_direction_output; gpio->gpio.direction_output = tegra186_gpio_direction_output;
gpio->gpio.get = tegra186_gpio_get, gpio->gpio.get = tegra186_gpio_get,
gpio->gpio.set = tegra186_gpio_set; gpio->gpio.set = tegra186_gpio_set;
gpio->gpio.set_config = tegra186_gpio_set_config; gpio->gpio.set_config = tegra186_gpio_set_config;
gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges;
gpio->gpio.base = -1; gpio->gpio.base = -1;
...@@ -783,11 +839,19 @@ static const struct tegra_gpio_port tegra194_main_ports[] = { ...@@ -783,11 +839,19 @@ static const struct tegra_gpio_port tegra194_main_ports[] = {
TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2) TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2)
}; };
static const struct tegra186_pin_range tegra194_main_pin_ranges[] = {
{ TEGRA194_MAIN_GPIO(GG, 0), "pex_l5_clkreq_n_pgg0" },
{ TEGRA194_MAIN_GPIO(GG, 1), "pex_l5_rst_n_pgg1" },
};
static const struct tegra_gpio_soc tegra194_main_soc = { static const struct tegra_gpio_soc tegra194_main_soc = {
.num_ports = ARRAY_SIZE(tegra194_main_ports), .num_ports = ARRAY_SIZE(tegra194_main_ports),
.ports = tegra194_main_ports, .ports = tegra194_main_ports,
.name = "tegra194-gpio", .name = "tegra194-gpio",
.instance = 0, .instance = 0,
.num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges),
.pin_ranges = tegra194_main_pin_ranges,
.pinmux = "nvidia,tegra194-pinmux",
}; };
#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \ #define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \
......
...@@ -30,7 +30,7 @@ struct uniphier_gpio_priv { ...@@ -30,7 +30,7 @@ struct uniphier_gpio_priv {
struct irq_domain *domain; struct irq_domain *domain;
void __iomem *regs; void __iomem *regs;
spinlock_t lock; spinlock_t lock;
u32 saved_vals[0]; u32 saved_vals[];
}; };
static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank) static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank)
......
...@@ -57,16 +57,19 @@ static int wcd_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, ...@@ -57,16 +57,19 @@ static int wcd_gpio_direction_output(struct gpio_chip *chip, unsigned int pin,
static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin) static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin)
{ {
struct wcd_gpio_data *data = gpiochip_get_data(chip); struct wcd_gpio_data *data = gpiochip_get_data(chip);
int value; unsigned int value;
regmap_read(data->map, WCD_REG_VAL_CTL_OFFSET, &value); regmap_read(data->map, WCD_REG_VAL_CTL_OFFSET, &value);
return !!(value && WCD_PIN_MASK(pin)); return !!(value & WCD_PIN_MASK(pin));
} }
static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val) static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
{ {
wcd_gpio_direction_output(chip, pin, val); struct wcd_gpio_data *data = gpiochip_get_data(chip);
regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET,
WCD_PIN_MASK(pin), val ? WCD_PIN_MASK(pin) : 0);
} }
static int wcd_gpio_probe(struct platform_device *pdev) static int wcd_gpio_probe(struct platform_device *pdev)
......
...@@ -226,13 +226,11 @@ static int zx_gpio_probe(struct platform_device *pdev) ...@@ -226,13 +226,11 @@ static int zx_gpio_probe(struct platform_device *pdev)
if (IS_ERR(chip->base)) if (IS_ERR(chip->base))
return PTR_ERR(chip->base); return PTR_ERR(chip->base);
raw_spin_lock_init(&chip->lock);
if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
chip->gc.request = gpiochip_generic_request;
chip->gc.free = gpiochip_generic_free;
}
id = of_alias_get_id(dev->of_node, "gpio"); id = of_alias_get_id(dev->of_node, "gpio");
raw_spin_lock_init(&chip->lock);
chip->gc.request = gpiochip_generic_request;
chip->gc.free = gpiochip_generic_free;
chip->gc.direction_input = zx_direction_input; chip->gc.direction_input = zx_direction_input;
chip->gc.direction_output = zx_direction_output; chip->gc.direction_output = zx_direction_output;
chip->gc.get = zx_get_value; chip->gc.get = zx_get_value;
......
...@@ -478,3 +478,49 @@ void devm_gpio_free(struct device *dev, unsigned int gpio) ...@@ -478,3 +478,49 @@ void devm_gpio_free(struct device *dev, unsigned int gpio)
&gpio)); &gpio));
} }
EXPORT_SYMBOL_GPL(devm_gpio_free); EXPORT_SYMBOL_GPL(devm_gpio_free);
static void devm_gpio_chip_release(struct device *dev, void *res)
{
struct gpio_chip *gc = *(struct gpio_chip **)res;
gpiochip_remove(gc);
}
/**
* devm_gpiochip_add_data() - Resource managed gpiochip_add_data()
* @dev: pointer to the device that gpio_chip belongs to.
* @gc: the GPIO chip to register
* @data: driver-private data associated with this chip
*
* Context: potentially before irqs will work
*
* The gpio chip automatically be released when the device is unbound.
*
* Returns:
* A negative errno if the chip can't be registered, such as because the
* gc->base is invalid or already associated with a different chip.
* Otherwise it returns zero as a success code.
*/
int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *gc,
void *data)
{
struct gpio_chip **ptr;
int ret;
ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ret = gpiochip_add_data(gc, data);
if (ret < 0) {
devres_free(ptr);
return ret;
}
*ptr = gc;
devres_add(dev, ptr);
return 0;
}
EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
...@@ -604,6 +604,39 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, ...@@ -604,6 +604,39 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
return desc; return desc;
} }
/**
* of_gpiochip_add_hog - Add all hogs in a hog device node
* @chip: gpio chip to act on
* @hog: device node describing the hogs
*
* Returns error if it fails otherwise 0 on success.
*/
static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog)
{
enum gpiod_flags dflags;
struct gpio_desc *desc;
unsigned long lflags;
const char *name;
unsigned int i;
int ret;
for (i = 0;; i++) {
desc = of_parse_own_gpio(hog, chip, i, &name, &lflags, &dflags);
if (IS_ERR(desc))
break;
ret = gpiod_hog(desc, name, lflags, dflags);
if (ret < 0)
return ret;
#ifdef CONFIG_OF_DYNAMIC
desc->hog = hog;
#endif
}
return 0;
}
/** /**
* of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions
* @chip: gpio chip to act on * @chip: gpio chip to act on
...@@ -614,35 +647,109 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, ...@@ -614,35 +647,109 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
*/ */
static int of_gpiochip_scan_gpios(struct gpio_chip *chip) static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
{ {
struct gpio_desc *desc = NULL;
struct device_node *np; struct device_node *np;
const char *name;
unsigned long lflags;
enum gpiod_flags dflags;
unsigned int i;
int ret; int ret;
for_each_available_child_of_node(chip->of_node, np) { for_each_available_child_of_node(chip->of_node, np) {
if (!of_property_read_bool(np, "gpio-hog")) if (!of_property_read_bool(np, "gpio-hog"))
continue; continue;
for (i = 0;; i++) { ret = of_gpiochip_add_hog(chip, np);
desc = of_parse_own_gpio(np, chip, i, &name, &lflags, if (ret < 0) {
&dflags); of_node_put(np);
if (IS_ERR(desc)) return ret;
break;
ret = gpiod_hog(desc, name, lflags, dflags);
if (ret < 0) {
of_node_put(np);
return ret;
}
} }
of_node_set_flag(np, OF_POPULATED);
} }
return 0; return 0;
} }
#ifdef CONFIG_OF_DYNAMIC
/**
* of_gpiochip_remove_hog - Remove all hogs in a hog device node
* @chip: gpio chip to act on
* @hog: device node describing the hogs
*/
static void of_gpiochip_remove_hog(struct gpio_chip *chip,
struct device_node *hog)
{
struct gpio_desc *descs = chip->gpiodev->descs;
unsigned int i;
for (i = 0; i < chip->ngpio; i++) {
if (test_bit(FLAG_IS_HOGGED, &descs[i].flags) &&
descs[i].hog == hog)
gpiochip_free_own_desc(&descs[i]);
}
}
static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
{
return chip->gpiodev->dev.of_node == data;
}
static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
{
return gpiochip_find(np, of_gpiochip_match_node);
}
static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
void *arg)
{
struct of_reconfig_data *rd = arg;
struct gpio_chip *chip;
int ret;
/*
* This only supports adding and removing complete gpio-hog nodes.
* Modifying an existing gpio-hog node is not supported (except for
* changing its "status" property, which is treated the same as
* addition/removal).
*/
switch (of_reconfig_get_state_change(action, arg)) {
case OF_RECONFIG_CHANGE_ADD:
if (!of_property_read_bool(rd->dn, "gpio-hog"))
return NOTIFY_OK; /* not for us */
if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
return NOTIFY_OK;
chip = of_find_gpiochip_by_node(rd->dn->parent);
if (chip == NULL)
return NOTIFY_OK; /* not for us */
ret = of_gpiochip_add_hog(chip, rd->dn);
if (ret < 0) {
pr_err("%s: failed to add hogs for %pOF\n", __func__,
rd->dn);
of_node_clear_flag(rd->dn, OF_POPULATED);
return notifier_from_errno(ret);
}
break;
case OF_RECONFIG_CHANGE_REMOVE:
if (!of_node_check_flag(rd->dn, OF_POPULATED))
return NOTIFY_OK; /* already depopulated */
chip = of_find_gpiochip_by_node(rd->dn->parent);
if (chip == NULL)
return NOTIFY_OK; /* not for us */
of_gpiochip_remove_hog(chip, rd->dn);
of_node_clear_flag(rd->dn, OF_POPULATED);
break;
}
return NOTIFY_OK;
}
struct notifier_block gpio_of_notifier = {
.notifier_call = of_gpio_notify,
};
#endif /* CONFIG_OF_DYNAMIC */
/** /**
* of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags
* @gc: pointer to the gpio_chip structure * @gc: pointer to the gpio_chip structure
......
...@@ -35,4 +35,6 @@ static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc) ...@@ -35,4 +35,6 @@ static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
} }
#endif /* CONFIG_OF_GPIO */ #endif /* CONFIG_OF_GPIO */
extern struct notifier_block gpio_of_notifier;
#endif /* GPIOLIB_OF_H */ #endif /* GPIOLIB_OF_H */
...@@ -81,14 +81,14 @@ LIST_HEAD(gpio_devices); ...@@ -81,14 +81,14 @@ LIST_HEAD(gpio_devices);
static DEFINE_MUTEX(gpio_machine_hogs_mutex); static DEFINE_MUTEX(gpio_machine_hogs_mutex);
static LIST_HEAD(gpio_machine_hogs); static LIST_HEAD(gpio_machine_hogs);
static void gpiochip_free_hogs(struct gpio_chip *chip); static void gpiochip_free_hogs(struct gpio_chip *gc);
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, static int gpiochip_add_irqchip(struct gpio_chip *gc,
struct lock_class_key *lock_key, struct lock_class_key *lock_key,
struct lock_class_key *request_key); struct lock_class_key *request_key);
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); static void gpiochip_irqchip_remove(struct gpio_chip *gc);
static int gpiochip_irqchip_init_hw(struct gpio_chip *gpiochip); static int gpiochip_irqchip_init_hw(struct gpio_chip *gc);
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip); static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc);
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip); static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc);
static bool gpiolib_initialized; static bool gpiolib_initialized;
...@@ -132,17 +132,17 @@ EXPORT_SYMBOL_GPL(gpio_to_desc); ...@@ -132,17 +132,17 @@ EXPORT_SYMBOL_GPL(gpio_to_desc);
/** /**
* gpiochip_get_desc - get the GPIO descriptor corresponding to the given * gpiochip_get_desc - get the GPIO descriptor corresponding to the given
* hardware number for this chip * hardware number for this chip
* @chip: GPIO chip * @gc: GPIO chip
* @hwnum: hardware number of the GPIO for this chip * @hwnum: hardware number of the GPIO for this chip
* *
* Returns: * Returns:
* A pointer to the GPIO descriptor or %ERR_PTR(-EINVAL) if no GPIO exists * A pointer to the GPIO descriptor or ``ERR_PTR(-EINVAL)`` if no GPIO exists
* in the given chip for the specified hardware number. * in the given chip for the specified hardware number.
*/ */
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc,
unsigned int hwnum) unsigned int hwnum)
{ {
struct gpio_device *gdev = chip->gpiodev; struct gpio_device *gdev = gc->gpiodev;
if (hwnum >= gdev->ngpio) if (hwnum >= gdev->ngpio)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -214,11 +214,11 @@ static int gpiochip_find_base(int ngpio) ...@@ -214,11 +214,11 @@ static int gpiochip_find_base(int ngpio)
*/ */
int gpiod_get_direction(struct gpio_desc *desc) int gpiod_get_direction(struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *gc;
unsigned offset; unsigned offset;
int ret; int ret;
chip = gpiod_to_chip(desc); gc = gpiod_to_chip(desc);
offset = gpio_chip_hwgpio(desc); offset = gpio_chip_hwgpio(desc);
/* /*
...@@ -229,10 +229,10 @@ int gpiod_get_direction(struct gpio_desc *desc) ...@@ -229,10 +229,10 @@ int gpiod_get_direction(struct gpio_desc *desc)
test_bit(FLAG_IS_OUT, &desc->flags)) test_bit(FLAG_IS_OUT, &desc->flags))
return 0; return 0;
if (!chip->get_direction) if (!gc->get_direction)
return -ENOTSUPP; return -ENOTSUPP;
ret = chip->get_direction(chip, offset); ret = gc->get_direction(gc, offset);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -302,6 +302,9 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) ...@@ -302,6 +302,9 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
struct gpio_device *gdev; struct gpio_device *gdev;
unsigned long flags; unsigned long flags;
if (!name)
return NULL;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(gdev, &gpio_devices, list) { list_for_each_entry(gdev, &gpio_devices, list) {
...@@ -310,7 +313,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name) ...@@ -310,7 +313,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
for (i = 0; i != gdev->ngpio; ++i) { for (i = 0; i != gdev->ngpio; ++i) {
struct gpio_desc *desc = &gdev->descs[i]; struct gpio_desc *desc = &gdev->descs[i];
if (!desc->name || !name) if (!desc->name)
continue; continue;
if (!strcmp(desc->name, name)) { if (!strcmp(desc->name, name)) {
...@@ -357,16 +360,16 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc) ...@@ -357,16 +360,16 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
return 0; return 0;
} }
static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip) static unsigned long *gpiochip_allocate_mask(struct gpio_chip *gc)
{ {
unsigned long *p; unsigned long *p;
p = bitmap_alloc(chip->ngpio, GFP_KERNEL); p = bitmap_alloc(gc->ngpio, GFP_KERNEL);
if (!p) if (!p)
return NULL; return NULL;
/* Assume by default all GPIOs are valid */ /* Assume by default all GPIOs are valid */
bitmap_fill(p, chip->ngpio); bitmap_fill(p, gc->ngpio);
return p; return p;
} }
...@@ -393,10 +396,10 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc) ...@@ -393,10 +396,10 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc)
return 0; return 0;
} }
static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip) static void gpiochip_free_valid_mask(struct gpio_chip *gc)
{ {
bitmap_free(gpiochip->valid_mask); bitmap_free(gc->valid_mask);
gpiochip->valid_mask = NULL; gc->valid_mask = NULL;
} }
static int gpiochip_add_pin_ranges(struct gpio_chip *gc) static int gpiochip_add_pin_ranges(struct gpio_chip *gc)
...@@ -407,13 +410,13 @@ static int gpiochip_add_pin_ranges(struct gpio_chip *gc) ...@@ -407,13 +410,13 @@ static int gpiochip_add_pin_ranges(struct gpio_chip *gc)
return 0; return 0;
} }
bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip, bool gpiochip_line_is_valid(const struct gpio_chip *gc,
unsigned int offset) unsigned int offset)
{ {
/* No mask means all valid */ /* No mask means all valid */
if (likely(!gpiochip->valid_mask)) if (likely(!gc->valid_mask))
return true; return true;
return test_bit(offset, gpiochip->valid_mask); return test_bit(offset, gc->valid_mask);
} }
EXPORT_SYMBOL_GPL(gpiochip_line_is_valid); EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
...@@ -547,6 +550,9 @@ static long linehandle_set_config(struct linehandle_state *lh, ...@@ -547,6 +550,9 @@ static long linehandle_set_config(struct linehandle_state *lh,
if (ret) if (ret)
return ret; return ret;
} }
atomic_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_CONFIG, desc);
} }
return 0; return 0;
} }
...@@ -788,8 +794,6 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) ...@@ -788,8 +794,6 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
* @irq: the interrupt that trigger in response to events on this GPIO * @irq: the interrupt that trigger in response to events on this GPIO
* @wait: wait queue that handles blocking reads of events * @wait: wait queue that handles blocking reads of events
* @events: KFIFO for the GPIO events * @events: KFIFO for the GPIO events
* @read_lock: mutex lock to protect reads from colliding with adding
* new events to the FIFO
* @timestamp: cache for the timestamp storing it between hardirq * @timestamp: cache for the timestamp storing it between hardirq
* and IRQ thread, used to bring the timestamp close to the actual * and IRQ thread, used to bring the timestamp close to the actual
* event * event
...@@ -802,7 +806,6 @@ struct lineevent_state { ...@@ -802,7 +806,6 @@ struct lineevent_state {
int irq; int irq;
wait_queue_head_t wait; wait_queue_head_t wait;
DECLARE_KFIFO(events, struct gpioevent_data, 16); DECLARE_KFIFO(events, struct gpioevent_data, 16);
struct mutex read_lock;
u64 timestamp; u64 timestamp;
}; };
...@@ -818,7 +821,7 @@ static __poll_t lineevent_poll(struct file *filep, ...@@ -818,7 +821,7 @@ static __poll_t lineevent_poll(struct file *filep,
poll_wait(filep, &le->wait, wait); poll_wait(filep, &le->wait, wait);
if (!kfifo_is_empty(&le->events)) if (!kfifo_is_empty_spinlocked_noirqsave(&le->events, &le->wait.lock))
events = EPOLLIN | EPOLLRDNORM; events = EPOLLIN | EPOLLRDNORM;
return events; return events;
...@@ -831,43 +834,52 @@ static ssize_t lineevent_read(struct file *filep, ...@@ -831,43 +834,52 @@ static ssize_t lineevent_read(struct file *filep,
loff_t *f_ps) loff_t *f_ps)
{ {
struct lineevent_state *le = filep->private_data; struct lineevent_state *le = filep->private_data;
unsigned int copied; struct gpioevent_data ge;
ssize_t bytes_read = 0;
int ret; int ret;
if (count < sizeof(struct gpioevent_data)) if (count < sizeof(ge))
return -EINVAL; return -EINVAL;
do { do {
spin_lock(&le->wait.lock);
if (kfifo_is_empty(&le->events)) { if (kfifo_is_empty(&le->events)) {
if (filep->f_flags & O_NONBLOCK) if (bytes_read) {
spin_unlock(&le->wait.lock);
return bytes_read;
}
if (filep->f_flags & O_NONBLOCK) {
spin_unlock(&le->wait.lock);
return -EAGAIN; return -EAGAIN;
}
ret = wait_event_interruptible(le->wait, ret = wait_event_interruptible_locked(le->wait,
!kfifo_is_empty(&le->events)); !kfifo_is_empty(&le->events));
if (ret) if (ret) {
spin_unlock(&le->wait.lock);
return ret; return ret;
}
} }
if (mutex_lock_interruptible(&le->read_lock)) ret = kfifo_out(&le->events, &ge, 1);
return -ERESTARTSYS; spin_unlock(&le->wait.lock);
ret = kfifo_to_user(&le->events, buf, count, &copied); if (ret != 1) {
mutex_unlock(&le->read_lock); /*
* This should never happen - we were holding the lock
if (ret) * from the moment we learned the fifo is no longer
return ret; * empty until now.
*/
/* ret = -EIO;
* If we couldn't read anything from the fifo (a different break;
* thread might have been faster) we either return -EAGAIN if }
* the file descriptor is non-blocking, otherwise we go back to
* sleep and wait for more data to arrive.
*/
if (copied == 0 && (filep->f_flags & O_NONBLOCK))
return -EAGAIN;
} while (copied == 0); if (copy_to_user(buf + bytes_read, &ge, sizeof(ge)))
return -EFAULT;
bytes_read += sizeof(ge);
} while (count >= bytes_read + sizeof(ge));
return copied; return bytes_read;
} }
static int lineevent_release(struct inode *inode, struct file *filep) static int lineevent_release(struct inode *inode, struct file *filep)
...@@ -946,7 +958,7 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) ...@@ -946,7 +958,7 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
* we didn't get the timestamp from lineevent_irq_handler(). * we didn't get the timestamp from lineevent_irq_handler().
*/ */
if (!le->timestamp) if (!le->timestamp)
ge.timestamp = ktime_get_real_ns(); ge.timestamp = ktime_get_ns();
else else
ge.timestamp = le->timestamp; ge.timestamp = le->timestamp;
...@@ -969,9 +981,12 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p) ...@@ -969,9 +981,12 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
return IRQ_NONE; return IRQ_NONE;
} }
ret = kfifo_put(&le->events, ge); ret = kfifo_in_spinlocked_noirqsave(&le->events, &ge,
1, &le->wait.lock);
if (ret) if (ret)
wake_up_poll(&le->wait, EPOLLIN); wake_up_poll(&le->wait, EPOLLIN);
else
pr_debug_ratelimited("event FIFO is full - event dropped\n");
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -984,7 +999,7 @@ static irqreturn_t lineevent_irq_handler(int irq, void *p) ...@@ -984,7 +999,7 @@ static irqreturn_t lineevent_irq_handler(int irq, void *p)
* Just store the timestamp in hardirq context so we get it as * Just store the timestamp in hardirq context so we get it as
* close in time as possible to the actual event. * close in time as possible to the actual event.
*/ */
le->timestamp = ktime_get_real_ns(); le->timestamp = ktime_get_ns();
return IRQ_WAKE_THREAD; return IRQ_WAKE_THREAD;
} }
...@@ -1084,7 +1099,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) ...@@ -1084,7 +1099,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
INIT_KFIFO(le->events); INIT_KFIFO(le->events);
init_waitqueue_head(&le->wait); init_waitqueue_head(&le->wait);
mutex_init(&le->read_lock);
/* Request a thread to read the events */ /* Request a thread to read the events */
ret = request_threaded_irq(le->irq, ret = request_threaded_irq(le->irq,
...@@ -1140,17 +1154,82 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) ...@@ -1140,17 +1154,82 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
return ret; return ret;
} }
static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
struct gpioline_info *info)
{
struct gpio_chip *gc = desc->gdev->chip;
unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags);
if (desc->name) {
strncpy(info->name, desc->name, sizeof(info->name));
info->name[sizeof(info->name) - 1] = '\0';
} else {
info->name[0] = '\0';
}
if (desc->label) {
strncpy(info->consumer, desc->label, sizeof(info->consumer));
info->consumer[sizeof(info->consumer) - 1] = '\0';
} else {
info->consumer[0] = '\0';
}
/*
* Userspace only need to know that the kernel is using this GPIO so
* it can't use it.
*/
info->flags = 0;
if (test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_IS_HOGGED, &desc->flags) ||
test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags) ||
test_bit(FLAG_SYSFS, &desc->flags) ||
!pinctrl_gpio_can_use_line(gc->base + info->line_offset))
info->flags |= GPIOLINE_FLAG_KERNEL;
if (test_bit(FLAG_IS_OUT, &desc->flags))
info->flags |= GPIOLINE_FLAG_IS_OUT;
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
info->flags |= GPIOLINE_FLAG_ACTIVE_LOW;
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
info->flags |= (GPIOLINE_FLAG_OPEN_DRAIN |
GPIOLINE_FLAG_IS_OUT);
if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
info->flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
GPIOLINE_FLAG_IS_OUT);
if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
info->flags |= GPIOLINE_FLAG_BIAS_DISABLE;
if (test_bit(FLAG_PULL_DOWN, &desc->flags))
info->flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
if (test_bit(FLAG_PULL_UP, &desc->flags))
info->flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
spin_unlock_irqrestore(&gpio_lock, flags);
}
struct gpio_chardev_data {
struct gpio_device *gdev;
wait_queue_head_t wait;
DECLARE_KFIFO(events, struct gpioline_info_changed, 32);
struct notifier_block lineinfo_changed_nb;
unsigned long *watched_lines;
};
/* /*
* gpio_ioctl() - ioctl handler for the GPIO chardev * gpio_ioctl() - ioctl handler for the GPIO chardev
*/ */
static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{ {
struct gpio_device *gdev = filp->private_data; struct gpio_chardev_data *priv = filp->private_data;
struct gpio_chip *chip = gdev->chip; struct gpio_device *gdev = priv->gdev;
struct gpio_chip *gc = gdev->chip;
void __user *ip = (void __user *)arg; void __user *ip = (void __user *)arg;
struct gpio_desc *desc;
__u32 offset;
/* We fail any subsequent ioctl():s when the chip is gone */ /* We fail any subsequent ioctl():s when the chip is gone */
if (!chip) if (!gc)
return -ENODEV; return -ENODEV;
/* Fill in the struct and pass to userspace */ /* Fill in the struct and pass to userspace */
...@@ -1169,68 +1248,40 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -1169,68 +1248,40 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (copy_to_user(ip, &chipinfo, sizeof(chipinfo))) if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} else if (cmd == GPIO_GET_LINEINFO_IOCTL) { } else if (cmd == GPIO_GET_LINEINFO_IOCTL ||
cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
struct gpioline_info lineinfo; struct gpioline_info lineinfo;
struct gpio_desc *desc;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT; return -EFAULT;
desc = gpiochip_get_desc(chip, lineinfo.line_offset); desc = gpiochip_get_desc(gc, lineinfo.line_offset);
if (IS_ERR(desc)) if (IS_ERR(desc))
return PTR_ERR(desc); return PTR_ERR(desc);
if (desc->name) { gpio_desc_to_lineinfo(desc, &lineinfo);
strncpy(lineinfo.name, desc->name,
sizeof(lineinfo.name));
lineinfo.name[sizeof(lineinfo.name)-1] = '\0';
} else {
lineinfo.name[0] = '\0';
}
if (desc->label) {
strncpy(lineinfo.consumer, desc->label,
sizeof(lineinfo.consumer));
lineinfo.consumer[sizeof(lineinfo.consumer)-1] = '\0';
} else {
lineinfo.consumer[0] = '\0';
}
/*
* Userspace only need to know that the kernel is using
* this GPIO so it can't use it.
*/
lineinfo.flags = 0;
if (test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_IS_HOGGED, &desc->flags) ||
test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags) ||
test_bit(FLAG_SYSFS, &desc->flags) ||
!pinctrl_gpio_can_use_line(chip->base + lineinfo.line_offset))
lineinfo.flags |= GPIOLINE_FLAG_KERNEL;
if (test_bit(FLAG_IS_OUT, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_IS_OUT;
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_ACTIVE_LOW;
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
lineinfo.flags |= (GPIOLINE_FLAG_OPEN_DRAIN |
GPIOLINE_FLAG_IS_OUT);
if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
GPIOLINE_FLAG_IS_OUT);
if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_BIAS_DISABLE;
if (test_bit(FLAG_PULL_DOWN, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
if (test_bit(FLAG_PULL_UP, &desc->flags))
lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT; return -EFAULT;
if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL)
set_bit(gpio_chip_hwgpio(desc), priv->watched_lines);
return 0; return 0;
} else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
return linehandle_create(gdev, ip); return linehandle_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEEVENT_IOCTL) { } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
return lineevent_create(gdev, ip); return lineevent_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) {
if (copy_from_user(&offset, ip, sizeof(offset)))
return -EFAULT;
desc = gpiochip_get_desc(gc, offset);
if (IS_ERR(desc))
return PTR_ERR(desc);
clear_bit(gpio_chip_hwgpio(desc), priv->watched_lines);
return 0;
} }
return -EINVAL; return -EINVAL;
} }
...@@ -1243,6 +1294,101 @@ static long gpio_ioctl_compat(struct file *filp, unsigned int cmd, ...@@ -1243,6 +1294,101 @@ static long gpio_ioctl_compat(struct file *filp, unsigned int cmd,
} }
#endif #endif
static struct gpio_chardev_data *
to_gpio_chardev_data(struct notifier_block *nb)
{
return container_of(nb, struct gpio_chardev_data, lineinfo_changed_nb);
}
static int lineinfo_changed_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct gpio_chardev_data *priv = to_gpio_chardev_data(nb);
struct gpioline_info_changed chg;
struct gpio_desc *desc = data;
int ret;
if (!test_bit(gpio_chip_hwgpio(desc), priv->watched_lines))
return NOTIFY_DONE;
memset(&chg, 0, sizeof(chg));
chg.info.line_offset = gpio_chip_hwgpio(desc);
chg.event_type = action;
chg.timestamp = ktime_get_ns();
gpio_desc_to_lineinfo(desc, &chg.info);
ret = kfifo_in_spinlocked(&priv->events, &chg, 1, &priv->wait.lock);
if (ret)
wake_up_poll(&priv->wait, EPOLLIN);
else
pr_debug_ratelimited("lineinfo event FIFO is full - event dropped\n");
return NOTIFY_OK;
}
static __poll_t lineinfo_watch_poll(struct file *filep,
struct poll_table_struct *pollt)
{
struct gpio_chardev_data *priv = filep->private_data;
__poll_t events = 0;
poll_wait(filep, &priv->wait, pollt);
if (!kfifo_is_empty_spinlocked_noirqsave(&priv->events,
&priv->wait.lock))
events = EPOLLIN | EPOLLRDNORM;
return events;
}
static ssize_t lineinfo_watch_read(struct file *filep, char __user *buf,
size_t count, loff_t *off)
{
struct gpio_chardev_data *priv = filep->private_data;
struct gpioline_info_changed event;
ssize_t bytes_read = 0;
int ret;
if (count < sizeof(event))
return -EINVAL;
do {
spin_lock(&priv->wait.lock);
if (kfifo_is_empty(&priv->events)) {
if (bytes_read) {
spin_unlock(&priv->wait.lock);
return bytes_read;
}
if (filep->f_flags & O_NONBLOCK) {
spin_unlock(&priv->wait.lock);
return -EAGAIN;
}
ret = wait_event_interruptible_locked(priv->wait,
!kfifo_is_empty(&priv->events));
if (ret) {
spin_unlock(&priv->wait.lock);
return ret;
}
}
ret = kfifo_out(&priv->events, &event, 1);
spin_unlock(&priv->wait.lock);
if (ret != 1) {
ret = -EIO;
break;
/* We should never get here. See lineevent_read(). */
}
if (copy_to_user(buf + bytes_read, &event, sizeof(event)))
return -EFAULT;
bytes_read += sizeof(event);
} while (count >= bytes_read + sizeof(event));
return bytes_read;
}
/** /**
* gpio_chrdev_open() - open the chardev for ioctl operations * gpio_chrdev_open() - open the chardev for ioctl operations
* @inode: inode for this chardev * @inode: inode for this chardev
...@@ -1253,14 +1399,48 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp) ...@@ -1253,14 +1399,48 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp)
{ {
struct gpio_device *gdev = container_of(inode->i_cdev, struct gpio_device *gdev = container_of(inode->i_cdev,
struct gpio_device, chrdev); struct gpio_device, chrdev);
struct gpio_chardev_data *priv;
int ret = -ENOMEM;
/* Fail on open if the backing gpiochip is gone */ /* Fail on open if the backing gpiochip is gone */
if (!gdev->chip) if (!gdev->chip)
return -ENODEV; return -ENODEV;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL);
if (!priv->watched_lines)
goto out_free_priv;
init_waitqueue_head(&priv->wait);
INIT_KFIFO(priv->events);
priv->gdev = gdev;
priv->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify;
ret = atomic_notifier_chain_register(&gdev->notifier,
&priv->lineinfo_changed_nb);
if (ret)
goto out_free_bitmap;
get_device(&gdev->dev); get_device(&gdev->dev);
filp->private_data = gdev; filp->private_data = priv;
return nonseekable_open(inode, filp); ret = nonseekable_open(inode, filp);
if (ret)
goto out_unregister_notifier;
return ret;
out_unregister_notifier:
atomic_notifier_chain_unregister(&gdev->notifier,
&priv->lineinfo_changed_nb);
out_free_bitmap:
bitmap_free(priv->watched_lines);
out_free_priv:
kfree(priv);
return ret;
} }
/** /**
...@@ -1271,17 +1451,23 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp) ...@@ -1271,17 +1451,23 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp)
*/ */
static int gpio_chrdev_release(struct inode *inode, struct file *filp) static int gpio_chrdev_release(struct inode *inode, struct file *filp)
{ {
struct gpio_device *gdev = container_of(inode->i_cdev, struct gpio_chardev_data *priv = filp->private_data;
struct gpio_device, chrdev); struct gpio_device *gdev = priv->gdev;
bitmap_free(priv->watched_lines);
atomic_notifier_chain_unregister(&gdev->notifier,
&priv->lineinfo_changed_nb);
put_device(&gdev->dev); put_device(&gdev->dev);
kfree(priv);
return 0; return 0;
} }
static const struct file_operations gpio_fileops = { static const struct file_operations gpio_fileops = {
.release = gpio_chrdev_release, .release = gpio_chrdev_release,
.open = gpio_chrdev_open, .open = gpio_chrdev_open,
.poll = lineinfo_watch_poll,
.read = lineinfo_watch_read,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.unlocked_ioctl = gpio_ioctl, .unlocked_ioctl = gpio_ioctl,
...@@ -1333,12 +1519,12 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) ...@@ -1333,12 +1519,12 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
return ret; return ret;
} }
static void gpiochip_machine_hog(struct gpio_chip *chip, struct gpiod_hog *hog) static void gpiochip_machine_hog(struct gpio_chip *gc, struct gpiod_hog *hog)
{ {
struct gpio_desc *desc; struct gpio_desc *desc;
int rv; int rv;
desc = gpiochip_get_desc(chip, hog->chip_hwnum); desc = gpiochip_get_desc(gc, hog->chip_hwnum);
if (IS_ERR(desc)) { if (IS_ERR(desc)) {
pr_err("%s: unable to get GPIO desc: %ld\n", pr_err("%s: unable to get GPIO desc: %ld\n",
__func__, PTR_ERR(desc)); __func__, PTR_ERR(desc));
...@@ -1351,18 +1537,18 @@ static void gpiochip_machine_hog(struct gpio_chip *chip, struct gpiod_hog *hog) ...@@ -1351,18 +1537,18 @@ static void gpiochip_machine_hog(struct gpio_chip *chip, struct gpiod_hog *hog)
rv = gpiod_hog(desc, hog->line_name, hog->lflags, hog->dflags); rv = gpiod_hog(desc, hog->line_name, hog->lflags, hog->dflags);
if (rv) if (rv)
pr_err("%s: unable to hog GPIO line (%s:%u): %d\n", pr_err("%s: unable to hog GPIO line (%s:%u): %d\n",
__func__, chip->label, hog->chip_hwnum, rv); __func__, gc->label, hog->chip_hwnum, rv);
} }
static void machine_gpiochip_add(struct gpio_chip *chip) static void machine_gpiochip_add(struct gpio_chip *gc)
{ {
struct gpiod_hog *hog; struct gpiod_hog *hog;
mutex_lock(&gpio_machine_hogs_mutex); mutex_lock(&gpio_machine_hogs_mutex);
list_for_each_entry(hog, &gpio_machine_hogs, list) { list_for_each_entry(hog, &gpio_machine_hogs, list) {
if (!strcmp(chip->label, hog->chip_label)) if (!strcmp(gc->label, hog->chip_label))
gpiochip_machine_hog(chip, hog); gpiochip_machine_hog(gc, hog);
} }
mutex_unlock(&gpio_machine_hogs_mutex); mutex_unlock(&gpio_machine_hogs_mutex);
...@@ -1381,14 +1567,14 @@ static void gpiochip_setup_devs(void) ...@@ -1381,14 +1567,14 @@ static void gpiochip_setup_devs(void)
} }
} }
int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
struct lock_class_key *lock_key, struct lock_class_key *lock_key,
struct lock_class_key *request_key) struct lock_class_key *request_key)
{ {
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
unsigned i; unsigned i;
int base = chip->base; int base = gc->base;
struct gpio_device *gdev; struct gpio_device *gdev;
/* /*
...@@ -1399,19 +1585,19 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1399,19 +1585,19 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
if (!gdev) if (!gdev)
return -ENOMEM; return -ENOMEM;
gdev->dev.bus = &gpio_bus_type; gdev->dev.bus = &gpio_bus_type;
gdev->chip = chip; gdev->chip = gc;
chip->gpiodev = gdev; gc->gpiodev = gdev;
if (chip->parent) { if (gc->parent) {
gdev->dev.parent = chip->parent; gdev->dev.parent = gc->parent;
gdev->dev.of_node = chip->parent->of_node; gdev->dev.of_node = gc->parent->of_node;
} }
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
/* If the gpiochip has an assigned OF node this takes precedence */ /* If the gpiochip has an assigned OF node this takes precedence */
if (chip->of_node) if (gc->of_node)
gdev->dev.of_node = chip->of_node; gdev->dev.of_node = gc->of_node;
else else
chip->of_node = gdev->dev.of_node; gc->of_node = gdev->dev.of_node;
#endif #endif
gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL); gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL);
...@@ -1422,37 +1608,37 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1422,37 +1608,37 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id); dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id);
device_initialize(&gdev->dev); device_initialize(&gdev->dev);
dev_set_drvdata(&gdev->dev, gdev); dev_set_drvdata(&gdev->dev, gdev);
if (chip->parent && chip->parent->driver) if (gc->parent && gc->parent->driver)
gdev->owner = chip->parent->driver->owner; gdev->owner = gc->parent->driver->owner;
else if (chip->owner) else if (gc->owner)
/* TODO: remove chip->owner */ /* TODO: remove chip->owner */
gdev->owner = chip->owner; gdev->owner = gc->owner;
else else
gdev->owner = THIS_MODULE; gdev->owner = THIS_MODULE;
gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL); gdev->descs = kcalloc(gc->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);
if (!gdev->descs) { if (!gdev->descs) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_free_ida; goto err_free_ida;
} }
if (chip->ngpio == 0) { if (gc->ngpio == 0) {
chip_err(chip, "tried to insert a GPIO chip with zero lines\n"); chip_err(gc, "tried to insert a GPIO chip with zero lines\n");
ret = -EINVAL; ret = -EINVAL;
goto err_free_descs; goto err_free_descs;
} }
if (chip->ngpio > FASTPATH_NGPIO) if (gc->ngpio > FASTPATH_NGPIO)
chip_warn(chip, "line cnt %u is greater than fast path cnt %u\n", chip_warn(gc, "line cnt %u is greater than fast path cnt %u\n",
chip->ngpio, FASTPATH_NGPIO); gc->ngpio, FASTPATH_NGPIO);
gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL); gdev->label = kstrdup_const(gc->label ?: "unknown", GFP_KERNEL);
if (!gdev->label) { if (!gdev->label) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_free_descs; goto err_free_descs;
} }
gdev->ngpio = chip->ngpio; gdev->ngpio = gc->ngpio;
gdev->data = data; gdev->data = data;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
...@@ -1465,7 +1651,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1465,7 +1651,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
* of the sysfs interface anyways. * of the sysfs interface anyways.
*/ */
if (base < 0) { if (base < 0) {
base = gpiochip_find_base(chip->ngpio); base = gpiochip_find_base(gc->ngpio);
if (base < 0) { if (base < 0) {
ret = base; ret = base;
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
...@@ -1477,7 +1663,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1477,7 +1663,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
* see if anyone makes use of this, else drop this and assign * see if anyone makes use of this, else drop this and assign
* a poison instead. * a poison instead.
*/ */
chip->base = base; gc->base = base;
} }
gdev->base = base; gdev->base = base;
...@@ -1487,60 +1673,62 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1487,60 +1673,62 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
goto err_free_label; goto err_free_label;
} }
for (i = 0; i < chip->ngpio; i++) for (i = 0; i < gc->ngpio; i++)
gdev->descs[i].gdev = gdev; gdev->descs[i].gdev = gdev;
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
ATOMIC_INIT_NOTIFIER_HEAD(&gdev->notifier);
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&gdev->pin_ranges); INIT_LIST_HEAD(&gdev->pin_ranges);
#endif #endif
ret = gpiochip_set_desc_names(chip); ret = gpiochip_set_desc_names(gc);
if (ret) if (ret)
goto err_remove_from_list; goto err_remove_from_list;
ret = gpiochip_alloc_valid_mask(chip); ret = gpiochip_alloc_valid_mask(gc);
if (ret) if (ret)
goto err_remove_from_list; goto err_remove_from_list;
ret = of_gpiochip_add(chip); ret = of_gpiochip_add(gc);
if (ret) if (ret)
goto err_free_gpiochip_mask; goto err_free_gpiochip_mask;
ret = gpiochip_init_valid_mask(chip); ret = gpiochip_init_valid_mask(gc);
if (ret) if (ret)
goto err_remove_of_chip; goto err_remove_of_chip;
for (i = 0; i < chip->ngpio; i++) { for (i = 0; i < gc->ngpio; i++) {
struct gpio_desc *desc = &gdev->descs[i]; struct gpio_desc *desc = &gdev->descs[i];
if (chip->get_direction && gpiochip_line_is_valid(chip, i)) { if (gc->get_direction && gpiochip_line_is_valid(gc, i)) {
assign_bit(FLAG_IS_OUT, assign_bit(FLAG_IS_OUT,
&desc->flags, !chip->get_direction(chip, i)); &desc->flags, !gc->get_direction(gc, i));
} else { } else {
assign_bit(FLAG_IS_OUT, assign_bit(FLAG_IS_OUT,
&desc->flags, !chip->direction_input); &desc->flags, !gc->direction_input);
} }
} }
ret = gpiochip_add_pin_ranges(chip); ret = gpiochip_add_pin_ranges(gc);
if (ret) if (ret)
goto err_remove_of_chip; goto err_remove_of_chip;
acpi_gpiochip_add(chip); acpi_gpiochip_add(gc);
machine_gpiochip_add(chip); machine_gpiochip_add(gc);
ret = gpiochip_irqchip_init_valid_mask(chip); ret = gpiochip_irqchip_init_valid_mask(gc);
if (ret) if (ret)
goto err_remove_acpi_chip; goto err_remove_acpi_chip;
ret = gpiochip_irqchip_init_hw(chip); ret = gpiochip_irqchip_init_hw(gc);
if (ret) if (ret)
goto err_remove_acpi_chip; goto err_remove_acpi_chip;
ret = gpiochip_add_irqchip(chip, lock_key, request_key); ret = gpiochip_add_irqchip(gc, lock_key, request_key);
if (ret) if (ret)
goto err_remove_irqchip_mask; goto err_remove_irqchip_mask;
...@@ -1560,17 +1748,17 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1560,17 +1748,17 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
return 0; return 0;
err_remove_irqchip: err_remove_irqchip:
gpiochip_irqchip_remove(chip); gpiochip_irqchip_remove(gc);
err_remove_irqchip_mask: err_remove_irqchip_mask:
gpiochip_irqchip_free_valid_mask(chip); gpiochip_irqchip_free_valid_mask(gc);
err_remove_acpi_chip: err_remove_acpi_chip:
acpi_gpiochip_remove(chip); acpi_gpiochip_remove(gc);
err_remove_of_chip: err_remove_of_chip:
gpiochip_free_hogs(chip); gpiochip_free_hogs(gc);
of_gpiochip_remove(chip); of_gpiochip_remove(gc);
err_free_gpiochip_mask: err_free_gpiochip_mask:
gpiochip_remove_pin_ranges(chip); gpiochip_remove_pin_ranges(gc);
gpiochip_free_valid_mask(chip); gpiochip_free_valid_mask(gc);
err_remove_from_list: err_remove_from_list:
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_del(&gdev->list); list_del(&gdev->list);
...@@ -1585,7 +1773,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -1585,7 +1773,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
/* failures here can mean systems won't boot... */ /* failures here can mean systems won't boot... */
pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__, pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
gdev->base, gdev->base + gdev->ngpio - 1, gdev->base, gdev->base + gdev->ngpio - 1,
chip->label ? : "generic", ret); gc->label ? : "generic", ret);
kfree(gdev); kfree(gdev);
return ret; return ret;
} }
...@@ -1593,41 +1781,39 @@ EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key); ...@@ -1593,41 +1781,39 @@ EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key);
/** /**
* gpiochip_get_data() - get per-subdriver data for the chip * gpiochip_get_data() - get per-subdriver data for the chip
* @chip: GPIO chip * @gc: GPIO chip
* *
* Returns: * Returns:
* The per-subdriver data for the chip. * The per-subdriver data for the chip.
*/ */
void *gpiochip_get_data(struct gpio_chip *chip) void *gpiochip_get_data(struct gpio_chip *gc)
{ {
return chip->gpiodev->data; return gc->gpiodev->data;
} }
EXPORT_SYMBOL_GPL(gpiochip_get_data); EXPORT_SYMBOL_GPL(gpiochip_get_data);
/** /**
* gpiochip_remove() - unregister a gpio_chip * gpiochip_remove() - unregister a gpio_chip
* @chip: the chip to unregister * @gc: the chip to unregister
* *
* A gpio_chip with any GPIOs still requested may not be removed. * A gpio_chip with any GPIOs still requested may not be removed.
*/ */
void gpiochip_remove(struct gpio_chip *chip) void gpiochip_remove(struct gpio_chip *gc)
{ {
struct gpio_device *gdev = chip->gpiodev; struct gpio_device *gdev = gc->gpiodev;
struct gpio_desc *desc;
unsigned long flags; unsigned long flags;
unsigned i; unsigned int i;
bool requested = false;
/* FIXME: should the legacy sysfs handling be moved to gpio_device? */ /* FIXME: should the legacy sysfs handling be moved to gpio_device? */
gpiochip_sysfs_unregister(gdev); gpiochip_sysfs_unregister(gdev);
gpiochip_free_hogs(chip); gpiochip_free_hogs(gc);
/* Numb the device, cancelling all outstanding operations */ /* Numb the device, cancelling all outstanding operations */
gdev->chip = NULL; gdev->chip = NULL;
gpiochip_irqchip_remove(chip); gpiochip_irqchip_remove(gc);
acpi_gpiochip_remove(chip); acpi_gpiochip_remove(gc);
of_gpiochip_remove(chip); of_gpiochip_remove(gc);
gpiochip_remove_pin_ranges(chip); gpiochip_remove_pin_ranges(gc);
gpiochip_free_valid_mask(chip); gpiochip_free_valid_mask(gc);
/* /*
* We accept no more calls into the driver from this point, so * We accept no more calls into the driver from this point, so
* NULL the driver data pointer * NULL the driver data pointer
...@@ -1636,13 +1822,12 @@ void gpiochip_remove(struct gpio_chip *chip) ...@@ -1636,13 +1822,12 @@ void gpiochip_remove(struct gpio_chip *chip)
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
for (i = 0; i < gdev->ngpio; i++) { for (i = 0; i < gdev->ngpio; i++) {
desc = &gdev->descs[i]; if (gpiochip_is_requested(gc, i))
if (test_bit(FLAG_REQUESTED, &desc->flags)) break;
requested = true;
} }
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
if (requested) if (i != gdev->ngpio)
dev_crit(&gdev->dev, dev_crit(&gdev->dev,
"REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
...@@ -1657,52 +1842,6 @@ void gpiochip_remove(struct gpio_chip *chip) ...@@ -1657,52 +1842,6 @@ void gpiochip_remove(struct gpio_chip *chip)
} }
EXPORT_SYMBOL_GPL(gpiochip_remove); EXPORT_SYMBOL_GPL(gpiochip_remove);
static void devm_gpio_chip_release(struct device *dev, void *res)
{
struct gpio_chip *chip = *(struct gpio_chip **)res;
gpiochip_remove(chip);
}
/**
* devm_gpiochip_add_data() - Resource managed gpiochip_add_data()
* @dev: pointer to the device that gpio_chip belongs to.
* @chip: the chip to register, with chip->base initialized
* @data: driver-private data associated with this chip
*
* Context: potentially before irqs will work
*
* The gpio chip automatically be released when the device is unbound.
*
* Returns:
* A negative errno if the chip can't be registered, such as because the
* chip->base is invalid or already associated with a different chip.
* Otherwise it returns zero as a success code.
*/
int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
void *data)
{
struct gpio_chip **ptr;
int ret;
ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ret = gpiochip_add_data(chip, data);
if (ret < 0) {
devres_free(ptr);
return ret;
}
*ptr = chip;
devres_add(dev, ptr);
return 0;
}
EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
/** /**
* gpiochip_find() - iterator for locating a specific gpio_chip * gpiochip_find() - iterator for locating a specific gpio_chip
* @data: data to pass to match function * @data: data to pass to match function
...@@ -1715,31 +1854,31 @@ EXPORT_SYMBOL_GPL(devm_gpiochip_add_data); ...@@ -1715,31 +1854,31 @@ EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
* more gpio_chips. * more gpio_chips.
*/ */
struct gpio_chip *gpiochip_find(void *data, struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, int (*match)(struct gpio_chip *gc,
void *data)) void *data))
{ {
struct gpio_device *gdev; struct gpio_device *gdev;
struct gpio_chip *chip = NULL; struct gpio_chip *gc = NULL;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(gdev, &gpio_devices, list) list_for_each_entry(gdev, &gpio_devices, list)
if (gdev->chip && match(gdev->chip, data)) { if (gdev->chip && match(gdev->chip, data)) {
chip = gdev->chip; gc = gdev->chip;
break; break;
} }
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
return chip; return gc;
} }
EXPORT_SYMBOL_GPL(gpiochip_find); EXPORT_SYMBOL_GPL(gpiochip_find);
static int gpiochip_match_name(struct gpio_chip *chip, void *data) static int gpiochip_match_name(struct gpio_chip *gc, void *data)
{ {
const char *name = data; const char *name = data;
return !strcmp(chip->label, name); return !strcmp(gc->label, name);
} }
static struct gpio_chip *find_chip_by_name(const char *name) static struct gpio_chip *find_chip_by_name(const char *name)
...@@ -1779,21 +1918,21 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc) ...@@ -1779,21 +1918,21 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc)
return 0; return 0;
} }
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc)
{ {
bitmap_free(gpiochip->irq.valid_mask); bitmap_free(gc->irq.valid_mask);
gpiochip->irq.valid_mask = NULL; gc->irq.valid_mask = NULL;
} }
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
unsigned int offset) unsigned int offset)
{ {
if (!gpiochip_line_is_valid(gpiochip, offset)) if (!gpiochip_line_is_valid(gc, offset))
return false; return false;
/* No mask means all valid */ /* No mask means all valid */
if (likely(!gpiochip->irq.valid_mask)) if (likely(!gc->irq.valid_mask))
return true; return true;
return test_bit(offset, gpiochip->irq.valid_mask); return test_bit(offset, gc->irq.valid_mask);
} }
EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid); EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
...@@ -1845,16 +1984,16 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gc, ...@@ -1845,16 +1984,16 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gc,
/** /**
* gpiochip_set_nested_irqchip() - connects a nested irqchip to a gpiochip * gpiochip_set_nested_irqchip() - connects a nested irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip nested handler to * @gc: the gpiochip to set the irqchip nested handler to
* @irqchip: the irqchip to nest to the gpiochip * @irqchip: the irqchip to nest to the gpiochip
* @parent_irq: the irq number corresponding to the parent IRQ for this * @parent_irq: the irq number corresponding to the parent IRQ for this
* nested irqchip * nested irqchip
*/ */
void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip, void gpiochip_set_nested_irqchip(struct gpio_chip *gc,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int parent_irq) unsigned int parent_irq)
{ {
gpiochip_set_cascaded_irqchip(gpiochip, parent_irq, NULL); gpiochip_set_cascaded_irqchip(gc, parent_irq, NULL);
} }
EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip); EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
...@@ -2031,7 +2170,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, ...@@ -2031,7 +2170,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
return ret; return ret;
} }
static unsigned int gpiochip_child_offset_to_irq_noop(struct gpio_chip *chip, static unsigned int gpiochip_child_offset_to_irq_noop(struct gpio_chip *gc,
unsigned int offset) unsigned int offset)
{ {
return offset; return offset;
...@@ -2091,7 +2230,7 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc) ...@@ -2091,7 +2230,7 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
return !!gc->irq.parent_domain; return !!gc->irq.parent_domain;
} }
void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
unsigned int parent_hwirq, unsigned int parent_hwirq,
unsigned int parent_type) unsigned int parent_type)
{ {
...@@ -2101,7 +2240,7 @@ void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, ...@@ -2101,7 +2240,7 @@ void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
if (!fwspec) if (!fwspec)
return NULL; return NULL;
fwspec->fwnode = chip->irq.parent_domain->fwnode; fwspec->fwnode = gc->irq.parent_domain->fwnode;
fwspec->param_count = 2; fwspec->param_count = 2;
fwspec->param[0] = parent_hwirq; fwspec->param[0] = parent_hwirq;
fwspec->param[1] = parent_type; fwspec->param[1] = parent_type;
...@@ -2110,7 +2249,7 @@ void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, ...@@ -2110,7 +2249,7 @@ void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
} }
EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_twocell); EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_twocell);
void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
unsigned int parent_hwirq, unsigned int parent_hwirq,
unsigned int parent_type) unsigned int parent_type)
{ {
...@@ -2120,7 +2259,7 @@ void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, ...@@ -2120,7 +2259,7 @@ void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip,
if (!fwspec) if (!fwspec)
return NULL; return NULL;
fwspec->fwnode = chip->irq.parent_domain->fwnode; fwspec->fwnode = gc->irq.parent_domain->fwnode;
fwspec->param_count = 4; fwspec->param_count = 4;
fwspec->param[0] = 0; fwspec->param[0] = 0;
fwspec->param[1] = parent_hwirq; fwspec->param[1] = parent_hwirq;
...@@ -2158,28 +2297,28 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc) ...@@ -2158,28 +2297,28 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq) irq_hw_number_t hwirq)
{ {
struct gpio_chip *chip = d->host_data; struct gpio_chip *gc = d->host_data;
int ret = 0; int ret = 0;
if (!gpiochip_irqchip_irq_valid(chip, hwirq)) if (!gpiochip_irqchip_irq_valid(gc, hwirq))
return -ENXIO; return -ENXIO;
irq_set_chip_data(irq, chip); irq_set_chip_data(irq, gc);
/* /*
* This lock class tells lockdep that GPIO irqs are in a different * This lock class tells lockdep that GPIO irqs are in a different
* category than their parents, so it won't report false recursion. * category than their parents, so it won't report false recursion.
*/ */
irq_set_lockdep_class(irq, chip->irq.lock_key, chip->irq.request_key); irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key);
irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq.handler); irq_set_chip_and_handler(irq, gc->irq.chip, gc->irq.handler);
/* Chips that use nested thread handlers have them marked */ /* Chips that use nested thread handlers have them marked */
if (chip->irq.threaded) if (gc->irq.threaded)
irq_set_nested_thread(irq, 1); irq_set_nested_thread(irq, 1);
irq_set_noprobe(irq); irq_set_noprobe(irq);
if (chip->irq.num_parents == 1) if (gc->irq.num_parents == 1)
ret = irq_set_parent(irq, chip->irq.parents[0]); ret = irq_set_parent(irq, gc->irq.parents[0]);
else if (chip->irq.map) else if (gc->irq.map)
ret = irq_set_parent(irq, chip->irq.map[hwirq]); ret = irq_set_parent(irq, gc->irq.map[hwirq]);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -2188,8 +2327,8 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, ...@@ -2188,8 +2327,8 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
* No set-up of the hardware will happen if IRQ_TYPE_NONE * No set-up of the hardware will happen if IRQ_TYPE_NONE
* is passed as default type. * is passed as default type.
*/ */
if (chip->irq.default_type != IRQ_TYPE_NONE) if (gc->irq.default_type != IRQ_TYPE_NONE)
irq_set_irq_type(irq, chip->irq.default_type); irq_set_irq_type(irq, gc->irq.default_type);
return 0; return 0;
} }
...@@ -2197,9 +2336,9 @@ EXPORT_SYMBOL_GPL(gpiochip_irq_map); ...@@ -2197,9 +2336,9 @@ EXPORT_SYMBOL_GPL(gpiochip_irq_map);
void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
{ {
struct gpio_chip *chip = d->host_data; struct gpio_chip *gc = d->host_data;
if (chip->irq.threaded) if (gc->irq.threaded)
irq_set_nested_thread(irq, 0); irq_set_nested_thread(irq, 0);
irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(irq, NULL); irq_set_chip_data(irq, NULL);
...@@ -2231,9 +2370,9 @@ static const struct irq_domain_ops gpiochip_domain_ops = { ...@@ -2231,9 +2370,9 @@ static const struct irq_domain_ops gpiochip_domain_ops = {
int gpiochip_irq_domain_activate(struct irq_domain *domain, int gpiochip_irq_domain_activate(struct irq_domain *domain,
struct irq_data *data, bool reserve) struct irq_data *data, bool reserve)
{ {
struct gpio_chip *chip = domain->host_data; struct gpio_chip *gc = domain->host_data;
return gpiochip_lock_as_irq(chip, data->hwirq); return gpiochip_lock_as_irq(gc, data->hwirq);
} }
EXPORT_SYMBOL_GPL(gpiochip_irq_domain_activate); EXPORT_SYMBOL_GPL(gpiochip_irq_domain_activate);
...@@ -2249,17 +2388,17 @@ EXPORT_SYMBOL_GPL(gpiochip_irq_domain_activate); ...@@ -2249,17 +2388,17 @@ EXPORT_SYMBOL_GPL(gpiochip_irq_domain_activate);
void gpiochip_irq_domain_deactivate(struct irq_domain *domain, void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
struct irq_data *data) struct irq_data *data)
{ {
struct gpio_chip *chip = domain->host_data; struct gpio_chip *gc = domain->host_data;
return gpiochip_unlock_as_irq(chip, data->hwirq); return gpiochip_unlock_as_irq(gc, data->hwirq);
} }
EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate); EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) static int gpiochip_to_irq(struct gpio_chip *gc, unsigned offset)
{ {
struct irq_domain *domain = chip->irq.domain; struct irq_domain *domain = gc->irq.domain;
if (!gpiochip_irqchip_irq_valid(chip, offset)) if (!gpiochip_irqchip_irq_valid(gc, offset))
return -ENXIO; return -ENXIO;
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
...@@ -2268,7 +2407,7 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) ...@@ -2268,7 +2407,7 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
spec.fwnode = domain->fwnode; spec.fwnode = domain->fwnode;
spec.param_count = 2; spec.param_count = 2;
spec.param[0] = chip->irq.child_offset_to_irq(chip, offset); spec.param[0] = gc->irq.child_offset_to_irq(gc, offset);
spec.param[1] = IRQ_TYPE_NONE; spec.param[1] = IRQ_TYPE_NONE;
return irq_create_fwspec_mapping(&spec); return irq_create_fwspec_mapping(&spec);
...@@ -2280,32 +2419,32 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) ...@@ -2280,32 +2419,32 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
static int gpiochip_irq_reqres(struct irq_data *d) static int gpiochip_irq_reqres(struct irq_data *d)
{ {
struct gpio_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
return gpiochip_reqres_irq(chip, d->hwirq); return gpiochip_reqres_irq(gc, d->hwirq);
} }
static void gpiochip_irq_relres(struct irq_data *d) static void gpiochip_irq_relres(struct irq_data *d)
{ {
struct gpio_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
gpiochip_relres_irq(chip, d->hwirq); gpiochip_relres_irq(gc, d->hwirq);
} }
static void gpiochip_irq_enable(struct irq_data *d) static void gpiochip_irq_enable(struct irq_data *d)
{ {
struct gpio_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
gpiochip_enable_irq(chip, d->hwirq); gpiochip_enable_irq(gc, d->hwirq);
if (chip->irq.irq_enable) if (gc->irq.irq_enable)
chip->irq.irq_enable(d); gc->irq.irq_enable(d);
else else
chip->irq.chip->irq_unmask(d); gc->irq.chip->irq_unmask(d);
} }
static void gpiochip_irq_disable(struct irq_data *d) static void gpiochip_irq_disable(struct irq_data *d)
{ {
struct gpio_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
/* /*
* Since we override .irq_disable() we need to mimic the * Since we override .irq_disable() we need to mimic the
...@@ -2314,23 +2453,23 @@ static void gpiochip_irq_disable(struct irq_data *d) ...@@ -2314,23 +2453,23 @@ static void gpiochip_irq_disable(struct irq_data *d)
* behaviour of mask_irq() which calls .irq_mask() if * behaviour of mask_irq() which calls .irq_mask() if
* it exists. * it exists.
*/ */
if (chip->irq.irq_disable) if (gc->irq.irq_disable)
chip->irq.irq_disable(d); gc->irq.irq_disable(d);
else if (chip->irq.chip->irq_mask) else if (gc->irq.chip->irq_mask)
chip->irq.chip->irq_mask(d); gc->irq.chip->irq_mask(d);
gpiochip_disable_irq(chip, d->hwirq); gpiochip_disable_irq(gc, d->hwirq);
} }
static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip) static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
{ {
struct irq_chip *irqchip = gpiochip->irq.chip; struct irq_chip *irqchip = gc->irq.chip;
if (!irqchip->irq_request_resources && if (!irqchip->irq_request_resources &&
!irqchip->irq_release_resources) { !irqchip->irq_release_resources) {
irqchip->irq_request_resources = gpiochip_irq_reqres; irqchip->irq_request_resources = gpiochip_irq_reqres;
irqchip->irq_release_resources = gpiochip_irq_relres; irqchip->irq_release_resources = gpiochip_irq_relres;
} }
if (WARN_ON(gpiochip->irq.irq_enable)) if (WARN_ON(gc->irq.irq_enable))
return; return;
/* Check if the irqchip already has this hook... */ /* Check if the irqchip already has this hook... */
if (irqchip->irq_enable == gpiochip_irq_enable) { if (irqchip->irq_enable == gpiochip_irq_enable) {
...@@ -2338,27 +2477,27 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip) ...@@ -2338,27 +2477,27 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip)
* ...and if so, give a gentle warning that this is bad * ...and if so, give a gentle warning that this is bad
* practice. * practice.
*/ */
chip_info(gpiochip, chip_info(gc,
"detected irqchip that is shared with multiple gpiochips: please fix the driver.\n"); "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n");
return; return;
} }
gpiochip->irq.irq_enable = irqchip->irq_enable; gc->irq.irq_enable = irqchip->irq_enable;
gpiochip->irq.irq_disable = irqchip->irq_disable; gc->irq.irq_disable = irqchip->irq_disable;
irqchip->irq_enable = gpiochip_irq_enable; irqchip->irq_enable = gpiochip_irq_enable;
irqchip->irq_disable = gpiochip_irq_disable; irqchip->irq_disable = gpiochip_irq_disable;
} }
/** /**
* gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
* @gpiochip: the GPIO chip to add the IRQ chip to * @gc: the GPIO chip to add the IRQ chip to
* @lock_key: lockdep class for IRQ lock * @lock_key: lockdep class for IRQ lock
* @request_key: lockdep class for IRQ request * @request_key: lockdep class for IRQ request
*/ */
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, static int gpiochip_add_irqchip(struct gpio_chip *gc,
struct lock_class_key *lock_key, struct lock_class_key *lock_key,
struct lock_class_key *request_key) struct lock_class_key *request_key)
{ {
struct irq_chip *irqchip = gpiochip->irq.chip; struct irq_chip *irqchip = gc->irq.chip;
const struct irq_domain_ops *ops = NULL; const struct irq_domain_ops *ops = NULL;
struct device_node *np; struct device_node *np;
unsigned int type; unsigned int type;
...@@ -2367,13 +2506,13 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, ...@@ -2367,13 +2506,13 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
if (!irqchip) if (!irqchip)
return 0; return 0;
if (gpiochip->irq.parent_handler && gpiochip->can_sleep) { if (gc->irq.parent_handler && gc->can_sleep) {
chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n"); chip_err(gc, "you cannot have chained interrupts on a chip that may sleep\n");
return -EINVAL; return -EINVAL;
} }
np = gpiochip->gpiodev->dev.of_node; np = gc->gpiodev->dev.of_node;
type = gpiochip->irq.default_type; type = gc->irq.default_type;
/* /*
* Specifying a default trigger is a terrible idea if DT or ACPI is * Specifying a default trigger is a terrible idea if DT or ACPI is
...@@ -2384,74 +2523,74 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip, ...@@ -2384,74 +2523,74 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
"%s: Ignoring %u default trigger\n", np->full_name, type)) "%s: Ignoring %u default trigger\n", np->full_name, type))
type = IRQ_TYPE_NONE; type = IRQ_TYPE_NONE;
if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) { if (has_acpi_companion(gc->parent) && type != IRQ_TYPE_NONE) {
acpi_handle_warn(ACPI_HANDLE(gpiochip->parent), acpi_handle_warn(ACPI_HANDLE(gc->parent),
"Ignoring %u default trigger\n", type); "Ignoring %u default trigger\n", type);
type = IRQ_TYPE_NONE; type = IRQ_TYPE_NONE;
} }
gpiochip->to_irq = gpiochip_to_irq; gc->to_irq = gpiochip_to_irq;
gpiochip->irq.default_type = type; gc->irq.default_type = type;
gpiochip->irq.lock_key = lock_key; gc->irq.lock_key = lock_key;
gpiochip->irq.request_key = request_key; gc->irq.request_key = request_key;
/* If a parent irqdomain is provided, let's build a hierarchy */ /* If a parent irqdomain is provided, let's build a hierarchy */
if (gpiochip_hierarchy_is_hierarchical(gpiochip)) { if (gpiochip_hierarchy_is_hierarchical(gc)) {
int ret = gpiochip_hierarchy_add_domain(gpiochip); int ret = gpiochip_hierarchy_add_domain(gc);
if (ret) if (ret)
return ret; return ret;
} else { } else {
/* Some drivers provide custom irqdomain ops */ /* Some drivers provide custom irqdomain ops */
if (gpiochip->irq.domain_ops) if (gc->irq.domain_ops)
ops = gpiochip->irq.domain_ops; ops = gc->irq.domain_ops;
if (!ops) if (!ops)
ops = &gpiochip_domain_ops; ops = &gpiochip_domain_ops;
gpiochip->irq.domain = irq_domain_add_simple(np, gc->irq.domain = irq_domain_add_simple(np,
gpiochip->ngpio, gc->ngpio,
gpiochip->irq.first, gc->irq.first,
ops, gpiochip); ops, gc);
if (!gpiochip->irq.domain) if (!gc->irq.domain)
return -EINVAL; return -EINVAL;
} }
if (gpiochip->irq.parent_handler) { if (gc->irq.parent_handler) {
void *data = gpiochip->irq.parent_handler_data ?: gpiochip; void *data = gc->irq.parent_handler_data ?: gc;
for (i = 0; i < gpiochip->irq.num_parents; i++) { for (i = 0; i < gc->irq.num_parents; i++) {
/* /*
* The parent IRQ chip is already using the chip_data * The parent IRQ chip is already using the chip_data
* for this IRQ chip, so our callbacks simply use the * for this IRQ chip, so our callbacks simply use the
* handler_data. * handler_data.
*/ */
irq_set_chained_handler_and_data(gpiochip->irq.parents[i], irq_set_chained_handler_and_data(gc->irq.parents[i],
gpiochip->irq.parent_handler, gc->irq.parent_handler,
data); data);
} }
} }
gpiochip_set_irq_hooks(gpiochip); gpiochip_set_irq_hooks(gc);
acpi_gpiochip_request_interrupts(gpiochip); acpi_gpiochip_request_interrupts(gc);
return 0; return 0;
} }
/** /**
* gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip
* @gpiochip: the gpiochip to remove the irqchip from * @gc: the gpiochip to remove the irqchip from
* *
* This is called only from gpiochip_remove() * This is called only from gpiochip_remove()
*/ */
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) static void gpiochip_irqchip_remove(struct gpio_chip *gc)
{ {
struct irq_chip *irqchip = gpiochip->irq.chip; struct irq_chip *irqchip = gc->irq.chip;
unsigned int offset; unsigned int offset;
acpi_gpiochip_free_interrupts(gpiochip); acpi_gpiochip_free_interrupts(gc);
if (irqchip && gpiochip->irq.parent_handler) { if (irqchip && gc->irq.parent_handler) {
struct gpio_irq_chip *irq = &gpiochip->irq; struct gpio_irq_chip *irq = &gc->irq;
unsigned int i; unsigned int i;
for (i = 0; i < irq->num_parents; i++) for (i = 0; i < irq->num_parents; i++)
...@@ -2460,18 +2599,18 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) ...@@ -2460,18 +2599,18 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
} }
/* Remove all IRQ mappings and delete the domain */ /* Remove all IRQ mappings and delete the domain */
if (gpiochip->irq.domain) { if (gc->irq.domain) {
unsigned int irq; unsigned int irq;
for (offset = 0; offset < gpiochip->ngpio; offset++) { for (offset = 0; offset < gc->ngpio; offset++) {
if (!gpiochip_irqchip_irq_valid(gpiochip, offset)) if (!gpiochip_irqchip_irq_valid(gc, offset))
continue; continue;
irq = irq_find_mapping(gpiochip->irq.domain, offset); irq = irq_find_mapping(gc->irq.domain, offset);
irq_dispose_mapping(irq); irq_dispose_mapping(irq);
} }
irq_domain_remove(gpiochip->irq.domain); irq_domain_remove(gc->irq.domain);
} }
if (irqchip) { if (irqchip) {
...@@ -2480,20 +2619,20 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) ...@@ -2480,20 +2619,20 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
irqchip->irq_release_resources = NULL; irqchip->irq_release_resources = NULL;
} }
if (irqchip->irq_enable == gpiochip_irq_enable) { if (irqchip->irq_enable == gpiochip_irq_enable) {
irqchip->irq_enable = gpiochip->irq.irq_enable; irqchip->irq_enable = gc->irq.irq_enable;
irqchip->irq_disable = gpiochip->irq.irq_disable; irqchip->irq_disable = gc->irq.irq_disable;
} }
} }
gpiochip->irq.irq_enable = NULL; gc->irq.irq_enable = NULL;
gpiochip->irq.irq_disable = NULL; gc->irq.irq_disable = NULL;
gpiochip->irq.chip = NULL; gc->irq.chip = NULL;
gpiochip_irqchip_free_valid_mask(gpiochip); gpiochip_irqchip_free_valid_mask(gc);
} }
/** /**
* gpiochip_irqchip_add_key() - adds an irqchip to a gpiochip * gpiochip_irqchip_add_key() - adds an irqchip to a gpiochip
* @gpiochip: the gpiochip to add the irqchip to * @gc: the gpiochip to add the irqchip to
* @irqchip: the irqchip to add to the gpiochip * @irqchip: the irqchip to add to the gpiochip
* @first_irq: if not dynamically assigned, the base (first) IRQ to * @first_irq: if not dynamically assigned, the base (first) IRQ to
* allocate gpiochip irqs from * allocate gpiochip irqs from
...@@ -2518,7 +2657,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) ...@@ -2518,7 +2657,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
* the pins on the gpiochip can generate a unique IRQ. Everything else * the pins on the gpiochip can generate a unique IRQ. Everything else
* need to be open coded. * need to be open coded.
*/ */
int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, int gpiochip_irqchip_add_key(struct gpio_chip *gc,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int first_irq, unsigned int first_irq,
irq_flow_handler_t handler, irq_flow_handler_t handler,
...@@ -2529,23 +2668,23 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, ...@@ -2529,23 +2668,23 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
{ {
struct device_node *of_node; struct device_node *of_node;
if (!gpiochip || !irqchip) if (!gc || !irqchip)
return -EINVAL; return -EINVAL;
if (!gpiochip->parent) { if (!gc->parent) {
pr_err("missing gpiochip .dev parent pointer\n"); pr_err("missing gpiochip .dev parent pointer\n");
return -EINVAL; return -EINVAL;
} }
gpiochip->irq.threaded = threaded; gc->irq.threaded = threaded;
of_node = gpiochip->parent->of_node; of_node = gc->parent->of_node;
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
/* /*
* If the gpiochip has an assigned OF node this takes precedence * If the gpiochip has an assigned OF node this takes precedence
* FIXME: get rid of this and use gpiochip->parent->of_node * FIXME: get rid of this and use gc->parent->of_node
* everywhere * everywhere
*/ */
if (gpiochip->of_node) if (gc->of_node)
of_node = gpiochip->of_node; of_node = gc->of_node;
#endif #endif
/* /*
* Specifying a default trigger is a terrible idea if DT or ACPI is * Specifying a default trigger is a terrible idea if DT or ACPI is
...@@ -2555,29 +2694,29 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, ...@@ -2555,29 +2694,29 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
if (WARN(of_node && type != IRQ_TYPE_NONE, if (WARN(of_node && type != IRQ_TYPE_NONE,
"%pOF: Ignoring %d default trigger\n", of_node, type)) "%pOF: Ignoring %d default trigger\n", of_node, type))
type = IRQ_TYPE_NONE; type = IRQ_TYPE_NONE;
if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) { if (has_acpi_companion(gc->parent) && type != IRQ_TYPE_NONE) {
acpi_handle_warn(ACPI_HANDLE(gpiochip->parent), acpi_handle_warn(ACPI_HANDLE(gc->parent),
"Ignoring %d default trigger\n", type); "Ignoring %d default trigger\n", type);
type = IRQ_TYPE_NONE; type = IRQ_TYPE_NONE;
} }
gpiochip->irq.chip = irqchip; gc->irq.chip = irqchip;
gpiochip->irq.handler = handler; gc->irq.handler = handler;
gpiochip->irq.default_type = type; gc->irq.default_type = type;
gpiochip->to_irq = gpiochip_to_irq; gc->to_irq = gpiochip_to_irq;
gpiochip->irq.lock_key = lock_key; gc->irq.lock_key = lock_key;
gpiochip->irq.request_key = request_key; gc->irq.request_key = request_key;
gpiochip->irq.domain = irq_domain_add_simple(of_node, gc->irq.domain = irq_domain_add_simple(of_node,
gpiochip->ngpio, first_irq, gc->ngpio, first_irq,
&gpiochip_domain_ops, gpiochip); &gpiochip_domain_ops, gc);
if (!gpiochip->irq.domain) { if (!gc->irq.domain) {
gpiochip->irq.chip = NULL; gc->irq.chip = NULL;
return -EINVAL; return -EINVAL;
} }
gpiochip_set_irq_hooks(gpiochip); gpiochip_set_irq_hooks(gc);
acpi_gpiochip_request_interrupts(gpiochip); acpi_gpiochip_request_interrupts(gc);
return 0; return 0;
} }
...@@ -2585,60 +2724,65 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key); ...@@ -2585,60 +2724,65 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
#else /* CONFIG_GPIOLIB_IRQCHIP */ #else /* CONFIG_GPIOLIB_IRQCHIP */
static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip, static inline int gpiochip_add_irqchip(struct gpio_chip *gc,
struct lock_class_key *lock_key, struct lock_class_key *lock_key,
struct lock_class_key *request_key) struct lock_class_key *request_key)
{ {
return 0; return 0;
} }
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} static void gpiochip_irqchip_remove(struct gpio_chip *gc) {}
static inline int gpiochip_irqchip_init_hw(struct gpio_chip *gpiochip) static inline int gpiochip_irqchip_init_hw(struct gpio_chip *gc)
{ {
return 0; return 0;
} }
static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip) static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc)
{ {
return 0; return 0;
} }
static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip) static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc)
{ } { }
#endif /* CONFIG_GPIOLIB_IRQCHIP */ #endif /* CONFIG_GPIOLIB_IRQCHIP */
/** /**
* gpiochip_generic_request() - request the gpio function for a pin * gpiochip_generic_request() - request the gpio function for a pin
* @chip: the gpiochip owning the GPIO * @gc: the gpiochip owning the GPIO
* @offset: the offset of the GPIO to request for GPIO function * @offset: the offset of the GPIO to request for GPIO function
*/ */
int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset) int gpiochip_generic_request(struct gpio_chip *gc, unsigned offset)
{ {
return pinctrl_gpio_request(chip->gpiodev->base + offset); #ifdef CONFIG_PINCTRL
if (list_empty(&gc->gpiodev->pin_ranges))
return 0;
#endif
return pinctrl_gpio_request(gc->gpiodev->base + offset);
} }
EXPORT_SYMBOL_GPL(gpiochip_generic_request); EXPORT_SYMBOL_GPL(gpiochip_generic_request);
/** /**
* gpiochip_generic_free() - free the gpio function from a pin * gpiochip_generic_free() - free the gpio function from a pin
* @chip: the gpiochip to request the gpio function for * @gc: the gpiochip to request the gpio function for
* @offset: the offset of the GPIO to free from GPIO function * @offset: the offset of the GPIO to free from GPIO function
*/ */
void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset) void gpiochip_generic_free(struct gpio_chip *gc, unsigned offset)
{ {
pinctrl_gpio_free(chip->gpiodev->base + offset); pinctrl_gpio_free(gc->gpiodev->base + offset);
} }
EXPORT_SYMBOL_GPL(gpiochip_generic_free); EXPORT_SYMBOL_GPL(gpiochip_generic_free);
/** /**
* gpiochip_generic_config() - apply configuration for a pin * gpiochip_generic_config() - apply configuration for a pin
* @chip: the gpiochip owning the GPIO * @gc: the gpiochip owning the GPIO
* @offset: the offset of the GPIO to apply the configuration * @offset: the offset of the GPIO to apply the configuration
* @config: the configuration to be applied * @config: the configuration to be applied
*/ */
int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset, int gpiochip_generic_config(struct gpio_chip *gc, unsigned offset,
unsigned long config) unsigned long config)
{ {
return pinctrl_gpio_set_config(chip->gpiodev->base + offset, config); return pinctrl_gpio_set_config(gc->gpiodev->base + offset, config);
} }
EXPORT_SYMBOL_GPL(gpiochip_generic_config); EXPORT_SYMBOL_GPL(gpiochip_generic_config);
...@@ -2646,7 +2790,7 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_config); ...@@ -2646,7 +2790,7 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_config);
/** /**
* gpiochip_add_pingroup_range() - add a range for GPIO <-> pin mapping * gpiochip_add_pingroup_range() - add a range for GPIO <-> pin mapping
* @chip: the gpiochip to add the range for * @gc: the gpiochip to add the range for
* @pctldev: the pin controller to map to * @pctldev: the pin controller to map to
* @gpio_offset: the start offset in the current gpio_chip number space * @gpio_offset: the start offset in the current gpio_chip number space
* @pin_group: name of the pin group inside the pin controller * @pin_group: name of the pin group inside the pin controller
...@@ -2656,24 +2800,24 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_config); ...@@ -2656,24 +2800,24 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_config);
* Documentation/devicetree/bindings/gpio/gpio.txt on how to * Documentation/devicetree/bindings/gpio/gpio.txt on how to
* bind pinctrl and gpio drivers via the "gpio-ranges" property. * bind pinctrl and gpio drivers via the "gpio-ranges" property.
*/ */
int gpiochip_add_pingroup_range(struct gpio_chip *chip, int gpiochip_add_pingroup_range(struct gpio_chip *gc,
struct pinctrl_dev *pctldev, struct pinctrl_dev *pctldev,
unsigned int gpio_offset, const char *pin_group) unsigned int gpio_offset, const char *pin_group)
{ {
struct gpio_pin_range *pin_range; struct gpio_pin_range *pin_range;
struct gpio_device *gdev = chip->gpiodev; struct gpio_device *gdev = gc->gpiodev;
int ret; int ret;
pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
if (!pin_range) { if (!pin_range) {
chip_err(chip, "failed to allocate pin ranges\n"); chip_err(gc, "failed to allocate pin ranges\n");
return -ENOMEM; return -ENOMEM;
} }
/* Use local offset as range ID */ /* Use local offset as range ID */
pin_range->range.id = gpio_offset; pin_range->range.id = gpio_offset;
pin_range->range.gc = chip; pin_range->range.gc = gc;
pin_range->range.name = chip->label; pin_range->range.name = gc->label;
pin_range->range.base = gdev->base + gpio_offset; pin_range->range.base = gdev->base + gpio_offset;
pin_range->pctldev = pctldev; pin_range->pctldev = pctldev;
...@@ -2687,7 +2831,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip, ...@@ -2687,7 +2831,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip,
pinctrl_add_gpio_range(pctldev, &pin_range->range); pinctrl_add_gpio_range(pctldev, &pin_range->range);
chip_dbg(chip, "created GPIO range %d->%d ==> %s PINGRP %s\n", chip_dbg(gc, "created GPIO range %d->%d ==> %s PINGRP %s\n",
gpio_offset, gpio_offset + pin_range->range.npins - 1, gpio_offset, gpio_offset + pin_range->range.npins - 1,
pinctrl_dev_get_devname(pctldev), pin_group); pinctrl_dev_get_devname(pctldev), pin_group);
...@@ -2699,7 +2843,7 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range); ...@@ -2699,7 +2843,7 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
/** /**
* gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping
* @chip: the gpiochip to add the range for * @gc: the gpiochip to add the range for
* @pinctl_name: the dev_name() of the pin controller to map to * @pinctl_name: the dev_name() of the pin controller to map to
* @gpio_offset: the start offset in the current gpio_chip number space * @gpio_offset: the start offset in the current gpio_chip number space
* @pin_offset: the start offset in the pin controller number space * @pin_offset: the start offset in the pin controller number space
...@@ -2714,24 +2858,24 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range); ...@@ -2714,24 +2858,24 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
* Documentation/devicetree/bindings/gpio/gpio.txt on how to * Documentation/devicetree/bindings/gpio/gpio.txt on how to
* bind pinctrl and gpio drivers via the "gpio-ranges" property. * bind pinctrl and gpio drivers via the "gpio-ranges" property.
*/ */
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name,
unsigned int gpio_offset, unsigned int pin_offset, unsigned int gpio_offset, unsigned int pin_offset,
unsigned int npins) unsigned int npins)
{ {
struct gpio_pin_range *pin_range; struct gpio_pin_range *pin_range;
struct gpio_device *gdev = chip->gpiodev; struct gpio_device *gdev = gc->gpiodev;
int ret; int ret;
pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
if (!pin_range) { if (!pin_range) {
chip_err(chip, "failed to allocate pin ranges\n"); chip_err(gc, "failed to allocate pin ranges\n");
return -ENOMEM; return -ENOMEM;
} }
/* Use local offset as range ID */ /* Use local offset as range ID */
pin_range->range.id = gpio_offset; pin_range->range.id = gpio_offset;
pin_range->range.gc = chip; pin_range->range.gc = gc;
pin_range->range.name = chip->label; pin_range->range.name = gc->label;
pin_range->range.base = gdev->base + gpio_offset; pin_range->range.base = gdev->base + gpio_offset;
pin_range->range.pin_base = pin_offset; pin_range->range.pin_base = pin_offset;
pin_range->range.npins = npins; pin_range->range.npins = npins;
...@@ -2739,11 +2883,11 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, ...@@ -2739,11 +2883,11 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
&pin_range->range); &pin_range->range);
if (IS_ERR(pin_range->pctldev)) { if (IS_ERR(pin_range->pctldev)) {
ret = PTR_ERR(pin_range->pctldev); ret = PTR_ERR(pin_range->pctldev);
chip_err(chip, "could not create pin range\n"); chip_err(gc, "could not create pin range\n");
kfree(pin_range); kfree(pin_range);
return ret; return ret;
} }
chip_dbg(chip, "created GPIO range %d->%d ==> %s PIN %d->%d\n", chip_dbg(gc, "created GPIO range %d->%d ==> %s PIN %d->%d\n",
gpio_offset, gpio_offset + npins - 1, gpio_offset, gpio_offset + npins - 1,
pinctl_name, pinctl_name,
pin_offset, pin_offset + npins - 1); pin_offset, pin_offset + npins - 1);
...@@ -2756,12 +2900,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); ...@@ -2756,12 +2900,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
/** /**
* gpiochip_remove_pin_ranges() - remove all the GPIO <-> pin mappings * gpiochip_remove_pin_ranges() - remove all the GPIO <-> pin mappings
* @chip: the chip to remove all the mappings for * @gc: the chip to remove all the mappings for
*/ */
void gpiochip_remove_pin_ranges(struct gpio_chip *chip) void gpiochip_remove_pin_ranges(struct gpio_chip *gc)
{ {
struct gpio_pin_range *pin_range, *tmp; struct gpio_pin_range *pin_range, *tmp;
struct gpio_device *gdev = chip->gpiodev; struct gpio_device *gdev = gc->gpiodev;
list_for_each_entry_safe(pin_range, tmp, &gdev->pin_ranges, node) { list_for_each_entry_safe(pin_range, tmp, &gdev->pin_ranges, node) {
list_del(&pin_range->node); list_del(&pin_range->node);
...@@ -2780,7 +2924,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); ...@@ -2780,7 +2924,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
*/ */
static int gpiod_request_commit(struct gpio_desc *desc, const char *label) static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
{ {
struct gpio_chip *chip = desc->gdev->chip; struct gpio_chip *gc = desc->gdev->chip;
int ret; int ret;
unsigned long flags; unsigned long flags;
unsigned offset; unsigned offset;
...@@ -2806,12 +2950,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) ...@@ -2806,12 +2950,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
goto done; goto done;
} }
if (chip->request) { if (gc->request) {
/* chip->request may sleep */ /* gc->request may sleep */
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
offset = gpio_chip_hwgpio(desc); offset = gpio_chip_hwgpio(desc);
if (gpiochip_line_is_valid(chip, offset)) if (gpiochip_line_is_valid(gc, offset))
ret = chip->request(chip, offset); ret = gc->request(gc, offset);
else else
ret = -EINVAL; ret = -EINVAL;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
...@@ -2823,14 +2967,16 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) ...@@ -2823,14 +2967,16 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
goto done; goto done;
} }
} }
if (chip->get_direction) { if (gc->get_direction) {
/* chip->get_direction may sleep */ /* gc->get_direction may sleep */
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
gpiod_get_direction(desc); gpiod_get_direction(desc);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
} }
done: done:
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
atomic_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_REQUESTED, desc);
return ret; return ret;
} }
...@@ -2898,7 +3044,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc) ...@@ -2898,7 +3044,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
{ {
bool ret = false; bool ret = false;
unsigned long flags; unsigned long flags;
struct gpio_chip *chip; struct gpio_chip *gc;
might_sleep(); might_sleep();
...@@ -2906,12 +3052,12 @@ static bool gpiod_free_commit(struct gpio_desc *desc) ...@@ -2906,12 +3052,12 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
chip = desc->gdev->chip; gc = desc->gdev->chip;
if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) { if (gc && test_bit(FLAG_REQUESTED, &desc->flags)) {
if (chip->free) { if (gc->free) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
might_sleep_if(chip->can_sleep); might_sleep_if(gc->can_sleep);
chip->free(chip, gpio_chip_hwgpio(desc)); gc->free(gc, gpio_chip_hwgpio(desc));
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
} }
kfree_const(desc->label); kfree_const(desc->label);
...@@ -2924,10 +3070,16 @@ static bool gpiod_free_commit(struct gpio_desc *desc) ...@@ -2924,10 +3070,16 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
clear_bit(FLAG_PULL_DOWN, &desc->flags); clear_bit(FLAG_PULL_DOWN, &desc->flags);
clear_bit(FLAG_BIAS_DISABLE, &desc->flags); clear_bit(FLAG_BIAS_DISABLE, &desc->flags);
clear_bit(FLAG_IS_HOGGED, &desc->flags); clear_bit(FLAG_IS_HOGGED, &desc->flags);
#ifdef CONFIG_OF_DYNAMIC
desc->hog = NULL;
#endif
ret = true; ret = true;
} }
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
atomic_notifier_call_chain(&desc->gdev->notifier,
GPIOLINE_CHANGED_RELEASED, desc);
return ret; return ret;
} }
...@@ -2943,7 +3095,7 @@ void gpiod_free(struct gpio_desc *desc) ...@@ -2943,7 +3095,7 @@ void gpiod_free(struct gpio_desc *desc)
/** /**
* gpiochip_is_requested - return string iff signal was requested * gpiochip_is_requested - return string iff signal was requested
* @chip: controller managing the signal * @gc: controller managing the signal
* @offset: of signal within controller's 0..(ngpio - 1) range * @offset: of signal within controller's 0..(ngpio - 1) range
* *
* Returns NULL if the GPIO is not currently requested, else a string. * Returns NULL if the GPIO is not currently requested, else a string.
...@@ -2954,14 +3106,16 @@ void gpiod_free(struct gpio_desc *desc) ...@@ -2954,14 +3106,16 @@ void gpiod_free(struct gpio_desc *desc)
* help with diagnostics, and knowing that the signal is used as a GPIO * help with diagnostics, and knowing that the signal is used as a GPIO
* can help avoid accidentally multiplexing it to another controller. * can help avoid accidentally multiplexing it to another controller.
*/ */
const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned offset)
{ {
struct gpio_desc *desc; struct gpio_desc *desc;
if (offset >= chip->ngpio) if (offset >= gc->ngpio)
return NULL; return NULL;
desc = &chip->gpiodev->descs[offset]; desc = gpiochip_get_desc(gc, offset);
if (IS_ERR(desc))
return NULL;
if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) if (test_bit(FLAG_REQUESTED, &desc->flags) == 0)
return NULL; return NULL;
...@@ -2971,7 +3125,7 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); ...@@ -2971,7 +3125,7 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
/** /**
* gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor
* @chip: GPIO chip * @gc: GPIO chip
* @hwnum: hardware number of the GPIO for which to request the descriptor * @hwnum: hardware number of the GPIO for which to request the descriptor
* @label: label for the GPIO * @label: label for the GPIO
* @lflags: lookup flags for this GPIO or 0 if default, this can be used to * @lflags: lookup flags for this GPIO or 0 if default, this can be used to
...@@ -2990,17 +3144,17 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); ...@@ -2990,17 +3144,17 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* A pointer to the GPIO descriptor, or an ERR_PTR()-encoded negative error * A pointer to the GPIO descriptor, or an ERR_PTR()-encoded negative error
* code on failure. * code on failure.
*/ */
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc,
unsigned int hwnum, unsigned int hwnum,
const char *label, const char *label,
enum gpio_lookup_flags lflags, enum gpio_lookup_flags lflags,
enum gpiod_flags dflags) enum gpiod_flags dflags)
{ {
struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum); struct gpio_desc *desc = gpiochip_get_desc(gc, hwnum);
int ret; int ret;
if (IS_ERR(desc)) { if (IS_ERR(desc)) {
chip_err(chip, "failed to get GPIO descriptor\n"); chip_err(gc, "failed to get GPIO descriptor\n");
return desc; return desc;
} }
...@@ -3010,7 +3164,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, ...@@ -3010,7 +3164,7 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip,
ret = gpiod_configure_flags(desc, label, lflags, dflags); ret = gpiod_configure_flags(desc, label, lflags, dflags);
if (ret) { if (ret) {
chip_err(chip, "setup of own GPIO %s failed\n", label); chip_err(gc, "setup of own GPIO %s failed\n", label);
gpiod_free_commit(desc); gpiod_free_commit(desc);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
...@@ -3052,9 +3206,9 @@ static int gpio_do_set_config(struct gpio_chip *gc, unsigned int offset, ...@@ -3052,9 +3206,9 @@ static int gpio_do_set_config(struct gpio_chip *gc, unsigned int offset,
return gc->set_config(gc, offset, config); return gc->set_config(gc, offset, config);
} }
static int gpio_set_config(struct gpio_chip *gc, unsigned int offset, static int gpio_set_config(struct gpio_desc *desc, enum pin_config_param mode)
enum pin_config_param mode)
{ {
struct gpio_chip *gc = desc->gdev->chip;
unsigned long config; unsigned long config;
unsigned arg; unsigned arg;
...@@ -3069,10 +3223,10 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned int offset, ...@@ -3069,10 +3223,10 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned int offset,
} }
config = PIN_CONF_PACKED(mode, arg); config = PIN_CONF_PACKED(mode, arg);
return gpio_do_set_config(gc, offset, config); return gpio_do_set_config(gc, gpio_chip_hwgpio(desc), config);
} }
static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc) static int gpio_set_bias(struct gpio_desc *desc)
{ {
int bias = 0; int bias = 0;
int ret = 0; int ret = 0;
...@@ -3085,7 +3239,7 @@ static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc) ...@@ -3085,7 +3239,7 @@ static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc)
bias = PIN_CONFIG_BIAS_PULL_DOWN; bias = PIN_CONFIG_BIAS_PULL_DOWN;
if (bias) { if (bias) {
ret = gpio_set_config(chip, gpio_chip_hwgpio(desc), bias); ret = gpio_set_config(desc, bias);
if (ret != -ENOTSUPP) if (ret != -ENOTSUPP)
return ret; return ret;
} }
...@@ -3103,18 +3257,18 @@ static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc) ...@@ -3103,18 +3257,18 @@ static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc)
*/ */
int gpiod_direction_input(struct gpio_desc *desc) int gpiod_direction_input(struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *gc;
int ret = 0; int ret = 0;
VALIDATE_DESC(desc); VALIDATE_DESC(desc);
chip = desc->gdev->chip; gc = desc->gdev->chip;
/* /*
* It is legal to have no .get() and .direction_input() specified if * It is legal to have no .get() and .direction_input() specified if
* the chip is output-only, but you can't specify .direction_input() * the chip is output-only, but you can't specify .direction_input()
* and not support the .get() operation, that doesn't make sense. * and not support the .get() operation, that doesn't make sense.
*/ */
if (!chip->get && chip->direction_input) { if (!gc->get && gc->direction_input) {
gpiod_warn(desc, gpiod_warn(desc,
"%s: missing get() but have direction_input()\n", "%s: missing get() but have direction_input()\n",
__func__); __func__);
...@@ -3127,10 +3281,10 @@ int gpiod_direction_input(struct gpio_desc *desc) ...@@ -3127,10 +3281,10 @@ int gpiod_direction_input(struct gpio_desc *desc)
* direction (if .get_direction() is supported) else we silently * direction (if .get_direction() is supported) else we silently
* assume we are in input mode after this. * assume we are in input mode after this.
*/ */
if (chip->direction_input) { if (gc->direction_input) {
ret = chip->direction_input(chip, gpio_chip_hwgpio(desc)); ret = gc->direction_input(gc, gpio_chip_hwgpio(desc));
} else if (chip->get_direction && } else if (gc->get_direction &&
(chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) { (gc->get_direction(gc, gpio_chip_hwgpio(desc)) != 1)) {
gpiod_warn(desc, gpiod_warn(desc,
"%s: missing direction_input() operation and line is output\n", "%s: missing direction_input() operation and line is output\n",
__func__); __func__);
...@@ -3138,7 +3292,7 @@ int gpiod_direction_input(struct gpio_desc *desc) ...@@ -3138,7 +3292,7 @@ int gpiod_direction_input(struct gpio_desc *desc)
} }
if (ret == 0) { if (ret == 0) {
clear_bit(FLAG_IS_OUT, &desc->flags); clear_bit(FLAG_IS_OUT, &desc->flags);
ret = gpio_set_bias(chip, desc); ret = gpio_set_bias(desc);
} }
trace_gpio_direction(desc_to_gpio(desc), 1, ret); trace_gpio_direction(desc_to_gpio(desc), 1, ret);
...@@ -3222,7 +3376,6 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); ...@@ -3222,7 +3376,6 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
*/ */
int gpiod_direction_output(struct gpio_desc *desc, int value) int gpiod_direction_output(struct gpio_desc *desc, int value)
{ {
struct gpio_chip *gc;
int ret; int ret;
VALIDATE_DESC(desc); VALIDATE_DESC(desc);
...@@ -3240,11 +3393,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) ...@@ -3240,11 +3393,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
return -EIO; return -EIO;
} }
gc = desc->gdev->chip;
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
/* First see if we can enable open drain in hardware */ /* First see if we can enable open drain in hardware */
ret = gpio_set_config(gc, gpio_chip_hwgpio(desc), ret = gpio_set_config(desc, PIN_CONFIG_DRIVE_OPEN_DRAIN);
PIN_CONFIG_DRIVE_OPEN_DRAIN);
if (!ret) if (!ret)
goto set_output_value; goto set_output_value;
/* Emulate open drain by not actively driving the line high */ /* Emulate open drain by not actively driving the line high */
...@@ -3254,8 +3405,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) ...@@ -3254,8 +3405,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
} }
} }
else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) { else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
ret = gpio_set_config(gc, gpio_chip_hwgpio(desc), ret = gpio_set_config(desc, PIN_CONFIG_DRIVE_OPEN_SOURCE);
PIN_CONFIG_DRIVE_OPEN_SOURCE);
if (!ret) if (!ret)
goto set_output_value; goto set_output_value;
/* Emulate open source by not actively driving the line low */ /* Emulate open source by not actively driving the line low */
...@@ -3264,12 +3414,11 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) ...@@ -3264,12 +3414,11 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
goto set_output_flag; goto set_output_flag;
} }
} else { } else {
gpio_set_config(gc, gpio_chip_hwgpio(desc), gpio_set_config(desc, PIN_CONFIG_DRIVE_PUSH_PULL);
PIN_CONFIG_DRIVE_PUSH_PULL);
} }
set_output_value: set_output_value:
ret = gpio_set_bias(gc, desc); ret = gpio_set_bias(desc);
if (ret) if (ret)
return ret; return ret;
return gpiod_direction_output_raw_commit(desc, value); return gpiod_direction_output_raw_commit(desc, value);
...@@ -3287,6 +3436,26 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) ...@@ -3287,6 +3436,26 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
} }
EXPORT_SYMBOL_GPL(gpiod_direction_output); EXPORT_SYMBOL_GPL(gpiod_direction_output);
/**
* gpiod_set_config - sets @config for a GPIO
* @desc: descriptor of the GPIO for which to set the configuration
* @config: Same packed config format as generic pinconf
*
* Returns:
* 0 on success, %-ENOTSUPP if the controller doesn't support setting the
* configuration.
*/
int gpiod_set_config(struct gpio_desc *desc, unsigned long config)
{
struct gpio_chip *gc;
VALIDATE_DESC(desc);
gc = desc->gdev->chip;
return gpio_do_set_config(gc, gpio_chip_hwgpio(desc), config);
}
EXPORT_SYMBOL_GPL(gpiod_set_config);
/** /**
* gpiod_set_debounce - sets @debounce time for a GPIO * gpiod_set_debounce - sets @debounce time for a GPIO
* @desc: descriptor of the GPIO for which to set debounce time * @desc: descriptor of the GPIO for which to set debounce time
...@@ -3298,14 +3467,10 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output); ...@@ -3298,14 +3467,10 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output);
*/ */
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
{ {
struct gpio_chip *chip; unsigned long config;
unsigned long config;
VALIDATE_DESC(desc);
chip = desc->gdev->chip;
config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce); config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce);
return gpio_do_set_config(chip, gpio_chip_hwgpio(desc), config); return gpiod_set_config(desc, config);
} }
EXPORT_SYMBOL_GPL(gpiod_set_debounce); EXPORT_SYMBOL_GPL(gpiod_set_debounce);
...@@ -3319,7 +3484,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_debounce); ...@@ -3319,7 +3484,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_debounce);
*/ */
int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
{ {
struct gpio_chip *chip; struct gpio_chip *gc;
unsigned long packed; unsigned long packed;
int gpio; int gpio;
int rc; int rc;
...@@ -3332,14 +3497,14 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) ...@@ -3332,14 +3497,14 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
assign_bit(FLAG_TRANSITORY, &desc->flags, transitory); assign_bit(FLAG_TRANSITORY, &desc->flags, transitory);
/* If the driver supports it, set the persistence state now */ /* If the driver supports it, set the persistence state now */
chip = desc->gdev->chip; gc = desc->gdev->chip;
if (!chip->set_config) if (!gc->set_config)
return 0; return 0;
packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE,
!transitory); !transitory);
gpio = gpio_chip_hwgpio(desc); gpio = gpio_chip_hwgpio(desc);
rc = gpio_do_set_config(chip, gpio, packed); rc = gpio_do_set_config(gc, gpio, packed);
if (rc == -ENOTSUPP) { if (rc == -ENOTSUPP) {
dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n", dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n",
gpio); gpio);
...@@ -3398,28 +3563,28 @@ EXPORT_SYMBOL_GPL(gpiod_toggle_active_low); ...@@ -3398,28 +3563,28 @@ EXPORT_SYMBOL_GPL(gpiod_toggle_active_low);
static int gpiod_get_raw_value_commit(const struct gpio_desc *desc) static int gpiod_get_raw_value_commit(const struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *gc;
int offset; int offset;
int value; int value;
chip = desc->gdev->chip; gc = desc->gdev->chip;
offset = gpio_chip_hwgpio(desc); offset = gpio_chip_hwgpio(desc);
value = chip->get ? chip->get(chip, offset) : -EIO; value = gc->get ? gc->get(gc, offset) : -EIO;
value = value < 0 ? value : !!value; value = value < 0 ? value : !!value;
trace_gpio_value(desc_to_gpio(desc), 1, value); trace_gpio_value(desc_to_gpio(desc), 1, value);
return value; return value;
} }
static int gpio_chip_get_multiple(struct gpio_chip *chip, static int gpio_chip_get_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits) unsigned long *mask, unsigned long *bits)
{ {
if (chip->get_multiple) { if (gc->get_multiple) {
return chip->get_multiple(chip, mask, bits); return gc->get_multiple(gc, mask, bits);
} else if (chip->get) { } else if (gc->get) {
int i, value; int i, value;
for_each_set_bit(i, mask, chip->ngpio) { for_each_set_bit(i, mask, gc->ngpio) {
value = chip->get(chip, i); value = gc->get(gc, i);
if (value < 0) if (value < 0)
return value; return value;
__assign_bit(i, bits, value); __assign_bit(i, bits, value);
...@@ -3467,26 +3632,26 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, ...@@ -3467,26 +3632,26 @@ 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 *gc = desc_array[i]->gdev->chip;
unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)]; unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
unsigned long *mask, *bits; unsigned long *mask, *bits;
int first, j, ret; int first, j, ret;
if (likely(chip->ngpio <= FASTPATH_NGPIO)) { if (likely(gc->ngpio <= FASTPATH_NGPIO)) {
mask = fastpath; mask = fastpath;
} else { } else {
mask = kmalloc_array(2 * BITS_TO_LONGS(chip->ngpio), mask = kmalloc_array(2 * BITS_TO_LONGS(gc->ngpio),
sizeof(*mask), sizeof(*mask),
can_sleep ? GFP_KERNEL : GFP_ATOMIC); can_sleep ? GFP_KERNEL : GFP_ATOMIC);
if (!mask) if (!mask)
return -ENOMEM; return -ENOMEM;
} }
bits = mask + BITS_TO_LONGS(chip->ngpio); bits = mask + BITS_TO_LONGS(gc->ngpio);
bitmap_zero(mask, chip->ngpio); bitmap_zero(mask, gc->ngpio);
if (!can_sleep) if (!can_sleep)
WARN_ON(chip->can_sleep); WARN_ON(gc->can_sleep);
/* collect all inputs belonging to the same chip */ /* collect all inputs belonging to the same chip */
first = i; first = i;
...@@ -3501,9 +3666,9 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, ...@@ -3501,9 +3666,9 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
i = find_next_zero_bit(array_info->get_mask, i = find_next_zero_bit(array_info->get_mask,
array_size, i); array_size, i);
} while ((i < array_size) && } while ((i < array_size) &&
(desc_array[i]->gdev->chip == chip)); (desc_array[i]->gdev->chip == gc));
ret = gpio_chip_get_multiple(chip, mask, bits); ret = gpio_chip_get_multiple(gc, mask, bits);
if (ret) { if (ret) {
if (mask != fastpath) if (mask != fastpath)
kfree(mask); kfree(mask);
...@@ -3641,13 +3806,13 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value); ...@@ -3641,13 +3806,13 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value);
static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
{ {
int ret = 0; int ret = 0;
struct gpio_chip *chip = desc->gdev->chip; struct gpio_chip *gc = desc->gdev->chip;
int offset = gpio_chip_hwgpio(desc); int offset = gpio_chip_hwgpio(desc);
if (value) { if (value) {
ret = chip->direction_input(chip, offset); ret = gc->direction_input(gc, offset);
} else { } else {
ret = chip->direction_output(chip, offset, 0); ret = gc->direction_output(gc, offset, 0);
if (!ret) if (!ret)
set_bit(FLAG_IS_OUT, &desc->flags); set_bit(FLAG_IS_OUT, &desc->flags);
} }
...@@ -3666,15 +3831,15 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) ...@@ -3666,15 +3831,15 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value) static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value)
{ {
int ret = 0; int ret = 0;
struct gpio_chip *chip = desc->gdev->chip; struct gpio_chip *gc = desc->gdev->chip;
int offset = gpio_chip_hwgpio(desc); int offset = gpio_chip_hwgpio(desc);
if (value) { if (value) {
ret = chip->direction_output(chip, offset, 1); ret = gc->direction_output(gc, offset, 1);
if (!ret) if (!ret)
set_bit(FLAG_IS_OUT, &desc->flags); set_bit(FLAG_IS_OUT, &desc->flags);
} else { } else {
ret = chip->direction_input(chip, offset); ret = gc->direction_input(gc, offset);
} }
trace_gpio_direction(desc_to_gpio(desc), !value, ret); trace_gpio_direction(desc_to_gpio(desc), !value, ret);
if (ret < 0) if (ret < 0)
...@@ -3685,33 +3850,34 @@ static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value ...@@ -3685,33 +3850,34 @@ static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value
static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
{ {
struct gpio_chip *chip; struct gpio_chip *gc;
chip = desc->gdev->chip; gc = desc->gdev->chip;
trace_gpio_value(desc_to_gpio(desc), 0, value); trace_gpio_value(desc_to_gpio(desc), 0, value);
chip->set(chip, gpio_chip_hwgpio(desc), value); gc->set(gc, gpio_chip_hwgpio(desc), value);
} }
/* /*
* set multiple outputs on the same chip; * set multiple outputs on the same chip;
* use the chip's set_multiple function if available; * use the chip's set_multiple function if available;
* otherwise set the outputs sequentially; * otherwise set the outputs sequentially;
* @chip: the GPIO chip we operate on
* @mask: bit mask array; one bit per output; BITS_PER_LONG bits per word * @mask: bit mask array; one bit per output; BITS_PER_LONG bits per word
* defines which outputs are to be changed * defines which outputs are to be changed
* @bits: bit value array; one bit per output; BITS_PER_LONG bits per word * @bits: bit value array; one bit per output; BITS_PER_LONG bits per word
* defines the values the outputs specified by mask are to be set to * defines the values the outputs specified by mask are to be set to
*/ */
static void gpio_chip_set_multiple(struct gpio_chip *chip, static void gpio_chip_set_multiple(struct gpio_chip *gc,
unsigned long *mask, unsigned long *bits) unsigned long *mask, unsigned long *bits)
{ {
if (chip->set_multiple) { if (gc->set_multiple) {
chip->set_multiple(chip, mask, bits); gc->set_multiple(gc, mask, bits);
} else { } else {
unsigned int i; unsigned int i;
/* set outputs if the corresponding mask bit is set */ /* set outputs if the corresponding mask bit is set */
for_each_set_bit(i, mask, chip->ngpio) for_each_set_bit(i, mask, gc->ngpio)
chip->set(chip, i, test_bit(i, bits)); gc->set(gc, i, test_bit(i, bits));
} }
} }
...@@ -3750,26 +3916,26 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, ...@@ -3750,26 +3916,26 @@ int 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 *gc = desc_array[i]->gdev->chip;
unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)]; unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
unsigned long *mask, *bits; unsigned long *mask, *bits;
int count = 0; int count = 0;
if (likely(chip->ngpio <= FASTPATH_NGPIO)) { if (likely(gc->ngpio <= FASTPATH_NGPIO)) {
mask = fastpath; mask = fastpath;
} else { } else {
mask = kmalloc_array(2 * BITS_TO_LONGS(chip->ngpio), mask = kmalloc_array(2 * BITS_TO_LONGS(gc->ngpio),
sizeof(*mask), sizeof(*mask),
can_sleep ? GFP_KERNEL : GFP_ATOMIC); can_sleep ? GFP_KERNEL : GFP_ATOMIC);
if (!mask) if (!mask)
return -ENOMEM; return -ENOMEM;
} }
bits = mask + BITS_TO_LONGS(chip->ngpio); bits = mask + BITS_TO_LONGS(gc->ngpio);
bitmap_zero(mask, chip->ngpio); bitmap_zero(mask, gc->ngpio);
if (!can_sleep) if (!can_sleep)
WARN_ON(chip->can_sleep); WARN_ON(gc->can_sleep);
do { do {
struct gpio_desc *desc = desc_array[i]; struct gpio_desc *desc = desc_array[i];
...@@ -3805,10 +3971,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, ...@@ -3805,10 +3971,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
i = find_next_zero_bit(array_info->set_mask, i = find_next_zero_bit(array_info->set_mask,
array_size, i); array_size, i);
} while ((i < array_size) && } while ((i < array_size) &&
(desc_array[i]->gdev->chip == chip)); (desc_array[i]->gdev->chip == gc));
/* 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(gc, mask, bits);
if (mask != fastpath) if (mask != fastpath)
kfree(mask); kfree(mask);
...@@ -3970,7 +4136,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_consumer_name); ...@@ -3970,7 +4136,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_consumer_name);
*/ */
int gpiod_to_irq(const struct gpio_desc *desc) int gpiod_to_irq(const struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *gc;
int offset; int offset;
/* /*
...@@ -3981,10 +4147,10 @@ int gpiod_to_irq(const struct gpio_desc *desc) ...@@ -3981,10 +4147,10 @@ int gpiod_to_irq(const struct gpio_desc *desc)
if (!desc || IS_ERR(desc) || !desc->gdev || !desc->gdev->chip) if (!desc || IS_ERR(desc) || !desc->gdev || !desc->gdev->chip)
return -EINVAL; return -EINVAL;
chip = desc->gdev->chip; gc = desc->gdev->chip;
offset = gpio_chip_hwgpio(desc); offset = gpio_chip_hwgpio(desc);
if (chip->to_irq) { if (gc->to_irq) {
int retirq = chip->to_irq(chip, offset); int retirq = gc->to_irq(gc, offset);
/* Zero means NO_IRQ */ /* Zero means NO_IRQ */
if (!retirq) if (!retirq)
...@@ -3998,17 +4164,17 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq); ...@@ -3998,17 +4164,17 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq);
/** /**
* gpiochip_lock_as_irq() - lock a GPIO to be used as IRQ * gpiochip_lock_as_irq() - lock a GPIO to be used as IRQ
* @chip: the chip the GPIO to lock belongs to * @gc: the chip the GPIO to lock belongs to
* @offset: the offset of the GPIO to lock as IRQ * @offset: the offset of the GPIO to lock as IRQ
* *
* This is used directly by GPIO drivers that want to lock down * This is used directly by GPIO drivers that want to lock down
* a certain GPIO line to be used for IRQs. * a certain GPIO line to be used for IRQs.
*/ */
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset)
{ {
struct gpio_desc *desc; struct gpio_desc *desc;
desc = gpiochip_get_desc(chip, offset); desc = gpiochip_get_desc(gc, offset);
if (IS_ERR(desc)) if (IS_ERR(desc))
return PTR_ERR(desc); return PTR_ERR(desc);
...@@ -4016,18 +4182,18 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -4016,18 +4182,18 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
* If it's fast: flush the direction setting if something changed * If it's fast: flush the direction setting if something changed
* behind our back * behind our back
*/ */
if (!chip->can_sleep && chip->get_direction) { if (!gc->can_sleep && gc->get_direction) {
int dir = gpiod_get_direction(desc); int dir = gpiod_get_direction(desc);
if (dir < 0) { if (dir < 0) {
chip_err(chip, "%s: cannot get GPIO direction\n", chip_err(gc, "%s: cannot get GPIO direction\n",
__func__); __func__);
return dir; return dir;
} }
} }
if (test_bit(FLAG_IS_OUT, &desc->flags)) { if (test_bit(FLAG_IS_OUT, &desc->flags)) {
chip_err(chip, chip_err(gc,
"%s: tried to flag a GPIO set as output for IRQ\n", "%s: tried to flag a GPIO set as output for IRQ\n",
__func__); __func__);
return -EIO; return -EIO;
...@@ -4050,17 +4216,17 @@ EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); ...@@ -4050,17 +4216,17 @@ EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);
/** /**
* gpiochip_unlock_as_irq() - unlock a GPIO used as IRQ * gpiochip_unlock_as_irq() - unlock a GPIO used as IRQ
* @chip: the chip the GPIO to lock belongs to * @gc: the chip the GPIO to lock belongs to
* @offset: the offset of the GPIO to lock as IRQ * @offset: the offset of the GPIO to lock as IRQ
* *
* This is used directly by GPIO drivers that want to indicate * This is used directly by GPIO drivers that want to indicate
* that a certain GPIO is no longer used exclusively for IRQ. * that a certain GPIO is no longer used exclusively for IRQ.
*/ */
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) void gpiochip_unlock_as_irq(struct gpio_chip *gc, unsigned int offset)
{ {
struct gpio_desc *desc; struct gpio_desc *desc;
desc = gpiochip_get_desc(chip, offset); desc = gpiochip_get_desc(gc, offset);
if (IS_ERR(desc)) if (IS_ERR(desc))
return; return;
...@@ -4073,9 +4239,9 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -4073,9 +4239,9 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
} }
EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq); EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset) void gpiochip_disable_irq(struct gpio_chip *gc, unsigned int offset)
{ {
struct gpio_desc *desc = gpiochip_get_desc(chip, offset); struct gpio_desc *desc = gpiochip_get_desc(gc, offset);
if (!IS_ERR(desc) && if (!IS_ERR(desc) &&
!WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags))) !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags)))
...@@ -4083,9 +4249,9 @@ void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -4083,9 +4249,9 @@ void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset)
} }
EXPORT_SYMBOL_GPL(gpiochip_disable_irq); EXPORT_SYMBOL_GPL(gpiochip_disable_irq);
void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset) void gpiochip_enable_irq(struct gpio_chip *gc, unsigned int offset)
{ {
struct gpio_desc *desc = gpiochip_get_desc(chip, offset); struct gpio_desc *desc = gpiochip_get_desc(gc, offset);
if (!IS_ERR(desc) && if (!IS_ERR(desc) &&
!WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags))) { !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags))) {
...@@ -4095,63 +4261,63 @@ void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset) ...@@ -4095,63 +4261,63 @@ void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset)
} }
EXPORT_SYMBOL_GPL(gpiochip_enable_irq); EXPORT_SYMBOL_GPL(gpiochip_enable_irq);
bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset) bool gpiochip_line_is_irq(struct gpio_chip *gc, unsigned int offset)
{ {
if (offset >= chip->ngpio) if (offset >= gc->ngpio)
return false; return false;
return test_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags); return test_bit(FLAG_USED_AS_IRQ, &gc->gpiodev->descs[offset].flags);
} }
EXPORT_SYMBOL_GPL(gpiochip_line_is_irq); EXPORT_SYMBOL_GPL(gpiochip_line_is_irq);
int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset) int gpiochip_reqres_irq(struct gpio_chip *gc, unsigned int offset)
{ {
int ret; int ret;
if (!try_module_get(chip->gpiodev->owner)) if (!try_module_get(gc->gpiodev->owner))
return -ENODEV; return -ENODEV;
ret = gpiochip_lock_as_irq(chip, offset); ret = gpiochip_lock_as_irq(gc, offset);
if (ret) { if (ret) {
chip_err(chip, "unable to lock HW IRQ %u for IRQ\n", offset); chip_err(gc, "unable to lock HW IRQ %u for IRQ\n", offset);
module_put(chip->gpiodev->owner); module_put(gc->gpiodev->owner);
return ret; return ret;
} }
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(gpiochip_reqres_irq); EXPORT_SYMBOL_GPL(gpiochip_reqres_irq);
void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset) void gpiochip_relres_irq(struct gpio_chip *gc, unsigned int offset)
{ {
gpiochip_unlock_as_irq(chip, offset); gpiochip_unlock_as_irq(gc, offset);
module_put(chip->gpiodev->owner); module_put(gc->gpiodev->owner);
} }
EXPORT_SYMBOL_GPL(gpiochip_relres_irq); EXPORT_SYMBOL_GPL(gpiochip_relres_irq);
bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset) bool gpiochip_line_is_open_drain(struct gpio_chip *gc, unsigned int offset)
{ {
if (offset >= chip->ngpio) if (offset >= gc->ngpio)
return false; return false;
return test_bit(FLAG_OPEN_DRAIN, &chip->gpiodev->descs[offset].flags); return test_bit(FLAG_OPEN_DRAIN, &gc->gpiodev->descs[offset].flags);
} }
EXPORT_SYMBOL_GPL(gpiochip_line_is_open_drain); EXPORT_SYMBOL_GPL(gpiochip_line_is_open_drain);
bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset) bool gpiochip_line_is_open_source(struct gpio_chip *gc, unsigned int offset)
{ {
if (offset >= chip->ngpio) if (offset >= gc->ngpio)
return false; return false;
return test_bit(FLAG_OPEN_SOURCE, &chip->gpiodev->descs[offset].flags); return test_bit(FLAG_OPEN_SOURCE, &gc->gpiodev->descs[offset].flags);
} }
EXPORT_SYMBOL_GPL(gpiochip_line_is_open_source); EXPORT_SYMBOL_GPL(gpiochip_line_is_open_source);
bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset) bool gpiochip_line_is_persistent(struct gpio_chip *gc, unsigned int offset)
{ {
if (offset >= chip->ngpio) if (offset >= gc->ngpio)
return false; return false;
return !test_bit(FLAG_TRANSITORY, &chip->gpiodev->descs[offset].flags); return !test_bit(FLAG_TRANSITORY, &gc->gpiodev->descs[offset].flags);
} }
EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent); EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent);
...@@ -4389,7 +4555,7 @@ EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table); ...@@ -4389,7 +4555,7 @@ EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table);
*/ */
void gpiod_add_hogs(struct gpiod_hog *hogs) void gpiod_add_hogs(struct gpiod_hog *hogs)
{ {
struct gpio_chip *chip; struct gpio_chip *gc;
struct gpiod_hog *hog; struct gpiod_hog *hog;
mutex_lock(&gpio_machine_hogs_mutex); mutex_lock(&gpio_machine_hogs_mutex);
...@@ -4401,9 +4567,9 @@ void gpiod_add_hogs(struct gpiod_hog *hogs) ...@@ -4401,9 +4567,9 @@ void gpiod_add_hogs(struct gpiod_hog *hogs)
* The chip may have been registered earlier, so check if it * The chip may have been registered earlier, so check if it
* exists and, if so, try to hog the line now. * exists and, if so, try to hog the line now.
*/ */
chip = find_chip_by_name(hog->chip_label); gc = find_chip_by_name(hog->chip_label);
if (chip) if (gc)
gpiochip_machine_hog(chip, hog); gpiochip_machine_hog(gc, hog);
} }
mutex_unlock(&gpio_machine_hogs_mutex); mutex_unlock(&gpio_machine_hogs_mutex);
...@@ -4453,7 +4619,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, ...@@ -4453,7 +4619,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
return desc; return desc;
for (p = &table->table[0]; p->chip_label; p++) { for (p = &table->table[0]; p->chip_label; p++) {
struct gpio_chip *chip; struct gpio_chip *gc;
/* idx must always match exactly */ /* idx must always match exactly */
if (p->idx != idx) if (p->idx != idx)
...@@ -4463,9 +4629,9 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, ...@@ -4463,9 +4629,9 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) if (p->con_id && (!con_id || strcmp(p->con_id, con_id)))
continue; continue;
chip = find_chip_by_name(p->chip_label); gc = find_chip_by_name(p->chip_label);
if (!chip) { if (!gc) {
/* /*
* As the lookup table indicates a chip with * As the lookup table indicates a chip with
* p->chip_label should exist, assume it may * p->chip_label should exist, assume it may
...@@ -4478,15 +4644,15 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, ...@@ -4478,15 +4644,15 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
} }
if (chip->ngpio <= p->chip_hwnum) { if (gc->ngpio <= p->chip_hwnum) {
dev_err(dev, dev_err(dev,
"requested GPIO %u (%u) is out of range [0..%u] for chip %s\n", "requested GPIO %u (%u) is out of range [0..%u] for chip %s\n",
idx, p->chip_hwnum, chip->ngpio - 1, idx, p->chip_hwnum, gc->ngpio - 1,
chip->label); gc->label);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
desc = gpiochip_get_desc(chip, p->chip_hwnum); desc = gpiochip_get_desc(gc, p->chip_hwnum);
*flags = p->flags; *flags = p->flags;
return desc; return desc;
...@@ -4881,20 +5047,20 @@ EXPORT_SYMBOL_GPL(gpiod_get_index_optional); ...@@ -4881,20 +5047,20 @@ EXPORT_SYMBOL_GPL(gpiod_get_index_optional);
int gpiod_hog(struct gpio_desc *desc, const char *name, int gpiod_hog(struct gpio_desc *desc, const char *name,
unsigned long lflags, enum gpiod_flags dflags) unsigned long lflags, enum gpiod_flags dflags)
{ {
struct gpio_chip *chip; struct gpio_chip *gc;
struct gpio_desc *local_desc; struct gpio_desc *local_desc;
int hwnum; int hwnum;
int ret; int ret;
chip = gpiod_to_chip(desc); gc = gpiod_to_chip(desc);
hwnum = gpio_chip_hwgpio(desc); hwnum = gpio_chip_hwgpio(desc);
local_desc = gpiochip_request_own_desc(chip, hwnum, name, local_desc = gpiochip_request_own_desc(gc, hwnum, name,
lflags, dflags); lflags, dflags);
if (IS_ERR(local_desc)) { if (IS_ERR(local_desc)) {
ret = PTR_ERR(local_desc); ret = PTR_ERR(local_desc);
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n", pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
name, chip->label, hwnum, ret); name, gc->label, hwnum, ret);
return ret; return ret;
} }
...@@ -4912,15 +5078,15 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, ...@@ -4912,15 +5078,15 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
/** /**
* gpiochip_free_hogs - Scan gpio-controller chip and release GPIO hog * gpiochip_free_hogs - Scan gpio-controller chip and release GPIO hog
* @chip: gpio chip to act on * @gc: gpio chip to act on
*/ */
static void gpiochip_free_hogs(struct gpio_chip *chip) static void gpiochip_free_hogs(struct gpio_chip *gc)
{ {
int id; int id;
for (id = 0; id < chip->ngpio; id++) { for (id = 0; id < gc->ngpio; id++) {
if (test_bit(FLAG_IS_HOGGED, &chip->gpiodev->descs[id].flags)) if (test_bit(FLAG_IS_HOGGED, &gc->gpiodev->descs[id].flags))
gpiochip_free_own_desc(&chip->gpiodev->descs[id]); gpiochip_free_own_desc(&gc->gpiodev->descs[id]);
} }
} }
...@@ -4943,7 +5109,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, ...@@ -4943,7 +5109,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
struct gpio_desc *desc; struct gpio_desc *desc;
struct gpio_descs *descs; struct gpio_descs *descs;
struct gpio_array *array_info = NULL; struct gpio_array *array_info = NULL;
struct gpio_chip *chip; struct gpio_chip *gc;
int count, bitmap_size; int count, bitmap_size;
count = gpiod_count(dev, con_id); count = gpiod_count(dev, con_id);
...@@ -4963,7 +5129,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, ...@@ -4963,7 +5129,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
descs->desc[descs->ndescs] = desc; descs->desc[descs->ndescs] = desc;
chip = gpiod_to_chip(desc); gc = gpiod_to_chip(desc);
/* /*
* If pin hardware number of array member 0 is also 0, select * If pin hardware number of array member 0 is also 0, select
* its chip as a candidate for fast bitmap processing path. * its chip as a candidate for fast bitmap processing path.
...@@ -4971,8 +5137,8 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, ...@@ -4971,8 +5137,8 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) { if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) {
struct gpio_descs *array; struct gpio_descs *array;
bitmap_size = BITS_TO_LONGS(chip->ngpio > count ? bitmap_size = BITS_TO_LONGS(gc->ngpio > count ?
chip->ngpio : count); gc->ngpio : count);
array = kzalloc(struct_size(descs, desc, count) + array = kzalloc(struct_size(descs, desc, count) +
struct_size(array_info, invert_mask, struct_size(array_info, invert_mask,
...@@ -4995,7 +5161,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, ...@@ -4995,7 +5161,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
array_info->desc = descs->desc; array_info->desc = descs->desc;
array_info->size = count; array_info->size = count;
array_info->chip = chip; array_info->chip = gc;
bitmap_set(array_info->get_mask, descs->ndescs, bitmap_set(array_info->get_mask, descs->ndescs,
count - descs->ndescs); count - descs->ndescs);
bitmap_set(array_info->set_mask, descs->ndescs, bitmap_set(array_info->set_mask, descs->ndescs,
...@@ -5003,7 +5169,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, ...@@ -5003,7 +5169,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
descs->info = array_info; descs->info = array_info;
} }
/* Unmark array members which don't belong to the 'fast' chip */ /* Unmark array members which don't belong to the 'fast' chip */
if (array_info && array_info->chip != chip) { if (array_info && array_info->chip != gc) {
__clear_bit(descs->ndescs, array_info->get_mask); __clear_bit(descs->ndescs, array_info->get_mask);
__clear_bit(descs->ndescs, array_info->set_mask); __clear_bit(descs->ndescs, array_info->set_mask);
} }
...@@ -5028,8 +5194,8 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, ...@@ -5028,8 +5194,8 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
} }
} else if (array_info) { } else if (array_info) {
/* Exclude open drain or open source from fast output */ /* Exclude open drain or open source from fast output */
if (gpiochip_line_is_open_drain(chip, descs->ndescs) || if (gpiochip_line_is_open_drain(gc, descs->ndescs) ||
gpiochip_line_is_open_source(chip, descs->ndescs)) gpiochip_line_is_open_source(gc, descs->ndescs))
__clear_bit(descs->ndescs, __clear_bit(descs->ndescs,
array_info->set_mask); array_info->set_mask);
/* Identify 'fast' pins which require invertion */ /* Identify 'fast' pins which require invertion */
...@@ -5117,10 +5283,15 @@ static int __init gpiolib_dev_init(void) ...@@ -5117,10 +5283,15 @@ static int __init gpiolib_dev_init(void)
if (ret < 0) { if (ret < 0) {
pr_err("gpiolib: failed to allocate char dev region\n"); pr_err("gpiolib: failed to allocate char dev region\n");
bus_unregister(&gpio_bus_type); bus_unregister(&gpio_bus_type);
} else { return ret;
gpiolib_initialized = true;
gpiochip_setup_devs();
} }
gpiolib_initialized = true;
gpiochip_setup_devs();
if (IS_ENABLED(CONFIG_OF_DYNAMIC))
WARN_ON(of_reconfig_notifier_register(&gpio_of_notifier));
return ret; return ret;
} }
core_initcall(gpiolib_dev_init); core_initcall(gpiolib_dev_init);
...@@ -5130,7 +5301,7 @@ core_initcall(gpiolib_dev_init); ...@@ -5130,7 +5301,7 @@ core_initcall(gpiolib_dev_init);
static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
{ {
unsigned i; unsigned i;
struct gpio_chip *chip = gdev->chip; struct gpio_chip *gc = gdev->chip;
unsigned gpio = gdev->base; unsigned gpio = gdev->base;
struct gpio_desc *gdesc = &gdev->descs[0]; struct gpio_desc *gdesc = &gdev->descs[0];
bool is_out; bool is_out;
...@@ -5153,7 +5324,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) ...@@ -5153,7 +5324,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s", seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s",
gpio, gdesc->name ? gdesc->name : "", gdesc->label, gpio, gdesc->name ? gdesc->name : "", gdesc->label,
is_out ? "out" : "in ", is_out ? "out" : "in ",
chip->get ? (chip->get(chip, i) ? "hi" : "lo") : "? ", gc->get ? (gc->get(gc, i) ? "hi" : "lo") : "? ",
is_irq ? "IRQ " : "", is_irq ? "IRQ " : "",
active_low ? "ACTIVE LOW" : ""); active_low ? "ACTIVE LOW" : "");
seq_printf(s, "\n"); seq_printf(s, "\n");
...@@ -5205,10 +5376,10 @@ static void gpiolib_seq_stop(struct seq_file *s, void *v) ...@@ -5205,10 +5376,10 @@ static void gpiolib_seq_stop(struct seq_file *s, void *v)
static int gpiolib_seq_show(struct seq_file *s, void *v) static int gpiolib_seq_show(struct seq_file *s, void *v)
{ {
struct gpio_device *gdev = v; struct gpio_device *gdev = v;
struct gpio_chip *chip = gdev->chip; struct gpio_chip *gc = gdev->chip;
struct device *parent; struct device *parent;
if (!chip) { if (!gc) {
seq_printf(s, "%s%s: (dangling chip)", (char *)s->private, seq_printf(s, "%s%s: (dangling chip)", (char *)s->private,
dev_name(&gdev->dev)); dev_name(&gdev->dev));
return 0; return 0;
...@@ -5217,19 +5388,19 @@ static int gpiolib_seq_show(struct seq_file *s, void *v) ...@@ -5217,19 +5388,19 @@ static int gpiolib_seq_show(struct seq_file *s, void *v)
seq_printf(s, "%s%s: GPIOs %d-%d", (char *)s->private, seq_printf(s, "%s%s: GPIOs %d-%d", (char *)s->private,
dev_name(&gdev->dev), dev_name(&gdev->dev),
gdev->base, gdev->base + gdev->ngpio - 1); gdev->base, gdev->base + gdev->ngpio - 1);
parent = chip->parent; parent = gc->parent;
if (parent) if (parent)
seq_printf(s, ", parent: %s/%s", seq_printf(s, ", parent: %s/%s",
parent->bus ? parent->bus->name : "no-bus", parent->bus ? parent->bus->name : "no-bus",
dev_name(parent)); dev_name(parent));
if (chip->label) if (gc->label)
seq_printf(s, ", %s", chip->label); seq_printf(s, ", %s", gc->label);
if (chip->can_sleep) if (gc->can_sleep)
seq_printf(s, ", can sleep"); seq_printf(s, ", can sleep");
seq_printf(s, ":\n"); seq_printf(s, ":\n");
if (chip->dbg_show) if (gc->dbg_show)
chip->dbg_show(s, chip); gc->dbg_show(s, gc);
else else
gpiolib_dbg_show(s, gdev); gpiolib_dbg_show(s, gdev);
......
...@@ -56,6 +56,7 @@ struct gpio_device { ...@@ -56,6 +56,7 @@ struct gpio_device {
const char *label; const char *label;
void *data; void *data;
struct list_head list; struct list_head list;
struct atomic_notifier_head notifier;
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
/* /*
...@@ -119,6 +120,9 @@ struct gpio_desc { ...@@ -119,6 +120,9 @@ struct gpio_desc {
const char *label; const char *label;
/* Name of the GPIO */ /* Name of the GPIO */
const char *name; const char *name;
#ifdef CONFIG_OF_DYNAMIC
struct device_node *hog;
#endif
}; };
int gpiod_request(struct gpio_desc *desc, const char *label); int gpiod_request(struct gpio_desc *desc, const char *label);
......
...@@ -103,6 +103,7 @@ struct pinctrl_dev *of_pinctrl_get(struct device_node *np) ...@@ -103,6 +103,7 @@ struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
{ {
return get_pinctrl_dev_from_of_node(np); return get_pinctrl_dev_from_of_node(np);
} }
EXPORT_SYMBOL_GPL(of_pinctrl_get);
static int dt_to_map_one_config(struct pinctrl *p, static int dt_to_map_one_config(struct pinctrl *p,
struct pinctrl_dev *hog_pctldev, struct pinctrl_dev *hog_pctldev,
......
...@@ -2323,11 +2323,8 @@ static int __init ingenic_gpio_probe(struct ingenic_pinctrl *jzpc, ...@@ -2323,11 +2323,8 @@ static int __init ingenic_gpio_probe(struct ingenic_pinctrl *jzpc,
jzgc->gc.direction_input = ingenic_gpio_direction_input; jzgc->gc.direction_input = ingenic_gpio_direction_input;
jzgc->gc.direction_output = ingenic_gpio_direction_output; jzgc->gc.direction_output = ingenic_gpio_direction_output;
jzgc->gc.get_direction = ingenic_gpio_get_direction; jzgc->gc.get_direction = ingenic_gpio_get_direction;
jzgc->gc.request = gpiochip_generic_request;
if (of_property_read_bool(node, "gpio-ranges")) { jzgc->gc.free = gpiochip_generic_free;
jzgc->gc.request = gpiochip_generic_request;
jzgc->gc.free = gpiochip_generic_free;
}
jzgc->irq = irq_of_parse_and_map(node, 0); jzgc->irq = irq_of_parse_and_map(node, 0);
if (!jzgc->irq) if (!jzgc->irq)
......
...@@ -2,10 +2,8 @@ ...@@ -2,10 +2,8 @@
#ifndef _ASM_GENERIC_GPIO_H #ifndef _ASM_GENERIC_GPIO_H
#define _ASM_GENERIC_GPIO_H #define _ASM_GENERIC_GPIO_H
#include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/of.h>
#ifdef CONFIG_GPIOLIB #ifdef CONFIG_GPIOLIB
...@@ -140,6 +138,8 @@ static inline void gpio_unexport(unsigned gpio) ...@@ -140,6 +138,8 @@ static inline void gpio_unexport(unsigned gpio)
#else /* !CONFIG_GPIOLIB */ #else /* !CONFIG_GPIOLIB */
#include <linux/kernel.h>
static inline bool gpio_is_valid(int number) static inline bool gpio_is_valid(int number)
{ {
/* only non-negative numbers are valid */ /* only non-negative numbers are valid */
......
...@@ -102,11 +102,9 @@ void devm_gpio_free(struct device *dev, unsigned int gpio); ...@@ -102,11 +102,9 @@ void devm_gpio_free(struct device *dev, unsigned int gpio);
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/pinctrl/pinctrl.h>
struct device; struct device;
struct gpio_chip; struct gpio_chip;
struct pinctrl_dev;
static inline bool gpio_is_valid(int number) static inline bool gpio_is_valid(int number)
{ {
......
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
#ifndef __LINUX_GPIO_CONSUMER_H #ifndef __LINUX_GPIO_CONSUMER_H
#define __LINUX_GPIO_CONSUMER_H #define __LINUX_GPIO_CONSUMER_H
#include <linux/bits.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/compiler_types.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/kernel.h>
struct device; struct device;
...@@ -156,6 +157,7 @@ int gpiod_set_raw_array_value_cansleep(unsigned int array_size, ...@@ -156,6 +157,7 @@ int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_array *array_info, struct gpio_array *array_info,
unsigned long *value_bitmap); unsigned long *value_bitmap);
int gpiod_set_config(struct gpio_desc *desc, unsigned long config);
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
int gpiod_set_transitory(struct gpio_desc *desc, bool transitory); int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
void gpiod_toggle_active_low(struct gpio_desc *desc); void gpiod_toggle_active_low(struct gpio_desc *desc);
...@@ -189,6 +191,8 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev, ...@@ -189,6 +191,8 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev,
#else /* CONFIG_GPIOLIB */ #else /* CONFIG_GPIOLIB */
#include <linux/kernel.h>
static inline int gpiod_count(struct device *dev, const char *con_id) static inline int gpiod_count(struct device *dev, const char *con_id)
{ {
return 0; return 0;
...@@ -470,6 +474,13 @@ static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size, ...@@ -470,6 +474,13 @@ static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
return 0; return 0;
} }
static inline int gpiod_set_config(struct gpio_desc *desc, unsigned long config)
{
/* GPIO can never have been requested */
WARN_ON(desc);
return -ENOSYS;
}
static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
......
...@@ -87,7 +87,7 @@ struct gpio_irq_chip { ...@@ -87,7 +87,7 @@ struct gpio_irq_chip {
* @need_valid_mask to make these GPIO lines unavailable for * @need_valid_mask to make these GPIO lines unavailable for
* translation. * translation.
*/ */
int (*child_to_parent_hwirq)(struct gpio_chip *chip, int (*child_to_parent_hwirq)(struct gpio_chip *gc,
unsigned int child_hwirq, unsigned int child_hwirq,
unsigned int child_type, unsigned int child_type,
unsigned int *parent_hwirq, unsigned int *parent_hwirq,
...@@ -102,7 +102,7 @@ struct gpio_irq_chip { ...@@ -102,7 +102,7 @@ struct gpio_irq_chip {
* variant named &gpiochip_populate_parent_fwspec_fourcell is also * variant named &gpiochip_populate_parent_fwspec_fourcell is also
* available. * available.
*/ */
void *(*populate_parent_alloc_arg)(struct gpio_chip *chip, void *(*populate_parent_alloc_arg)(struct gpio_chip *gc,
unsigned int parent_hwirq, unsigned int parent_hwirq,
unsigned int parent_type); unsigned int parent_type);
...@@ -114,7 +114,7 @@ struct gpio_irq_chip { ...@@ -114,7 +114,7 @@ struct gpio_irq_chip {
* callback. If this is not specified, then a default callback will be * callback. If this is not specified, then a default callback will be
* provided that returns the line offset. * provided that returns the line offset.
*/ */
unsigned int (*child_offset_to_irq)(struct gpio_chip *chip, unsigned int (*child_offset_to_irq)(struct gpio_chip *gc,
unsigned int pin); unsigned int pin);
/** /**
...@@ -209,7 +209,7 @@ struct gpio_irq_chip { ...@@ -209,7 +209,7 @@ struct gpio_irq_chip {
* a particular driver wants to clear IRQ related registers * a particular driver wants to clear IRQ related registers
* in order to avoid undesired events. * in order to avoid undesired events.
*/ */
int (*init_hw)(struct gpio_chip *chip); int (*init_hw)(struct gpio_chip *gc);
/** /**
* @init_valid_mask: optional routine to initialize @valid_mask, to be * @init_valid_mask: optional routine to initialize @valid_mask, to be
...@@ -220,7 +220,7 @@ struct gpio_irq_chip { ...@@ -220,7 +220,7 @@ struct gpio_irq_chip {
* then directly set some bits to "0" if they cannot be used for * then directly set some bits to "0" if they cannot be used for
* interrupts. * interrupts.
*/ */
void (*init_valid_mask)(struct gpio_chip *chip, void (*init_valid_mask)(struct gpio_chip *gc,
unsigned long *valid_mask, unsigned long *valid_mask,
unsigned int ngpios); unsigned int ngpios);
...@@ -348,40 +348,40 @@ struct gpio_chip { ...@@ -348,40 +348,40 @@ struct gpio_chip {
struct device *parent; struct device *parent;
struct module *owner; struct module *owner;
int (*request)(struct gpio_chip *chip, int (*request)(struct gpio_chip *gc,
unsigned offset); unsigned offset);
void (*free)(struct gpio_chip *chip, void (*free)(struct gpio_chip *gc,
unsigned offset); unsigned offset);
int (*get_direction)(struct gpio_chip *chip, int (*get_direction)(struct gpio_chip *gc,
unsigned offset); unsigned offset);
int (*direction_input)(struct gpio_chip *chip, int (*direction_input)(struct gpio_chip *gc,
unsigned offset); unsigned offset);
int (*direction_output)(struct gpio_chip *chip, int (*direction_output)(struct gpio_chip *gc,
unsigned offset, int value); unsigned offset, int value);
int (*get)(struct gpio_chip *chip, int (*get)(struct gpio_chip *gc,
unsigned offset); unsigned offset);
int (*get_multiple)(struct gpio_chip *chip, int (*get_multiple)(struct gpio_chip *gc,
unsigned long *mask, unsigned long *mask,
unsigned long *bits); unsigned long *bits);
void (*set)(struct gpio_chip *chip, void (*set)(struct gpio_chip *gc,
unsigned offset, int value); unsigned offset, int value);
void (*set_multiple)(struct gpio_chip *chip, void (*set_multiple)(struct gpio_chip *gc,
unsigned long *mask, unsigned long *mask,
unsigned long *bits); unsigned long *bits);
int (*set_config)(struct gpio_chip *chip, int (*set_config)(struct gpio_chip *gc,
unsigned offset, unsigned offset,
unsigned long config); unsigned long config);
int (*to_irq)(struct gpio_chip *chip, int (*to_irq)(struct gpio_chip *gc,
unsigned offset); unsigned offset);
void (*dbg_show)(struct seq_file *s, void (*dbg_show)(struct seq_file *s,
struct gpio_chip *chip); struct gpio_chip *gc);
int (*init_valid_mask)(struct gpio_chip *chip, int (*init_valid_mask)(struct gpio_chip *gc,
unsigned long *valid_mask, unsigned long *valid_mask,
unsigned int ngpios); unsigned int ngpios);
int (*add_pin_ranges)(struct gpio_chip *chip); int (*add_pin_ranges)(struct gpio_chip *gc);
int base; int base;
u16 ngpio; u16 ngpio;
...@@ -458,11 +458,11 @@ struct gpio_chip { ...@@ -458,11 +458,11 @@ struct gpio_chip {
#endif /* CONFIG_OF_GPIO */ #endif /* CONFIG_OF_GPIO */
}; };
extern const char *gpiochip_is_requested(struct gpio_chip *chip, extern const char *gpiochip_is_requested(struct gpio_chip *gc,
unsigned offset); unsigned offset);
/* add/remove chips */ /* add/remove chips */
extern int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, extern int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
struct lock_class_key *lock_key, struct lock_class_key *lock_key,
struct lock_class_key *request_key); struct lock_class_key *request_key);
...@@ -490,43 +490,43 @@ extern int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ...@@ -490,43 +490,43 @@ extern int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
* Otherwise it returns zero as a success code. * Otherwise it returns zero as a success code.
*/ */
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
#define gpiochip_add_data(chip, data) ({ \ #define gpiochip_add_data(gc, data) ({ \
static struct lock_class_key lock_key; \ static struct lock_class_key lock_key; \
static struct lock_class_key request_key; \ static struct lock_class_key request_key; \
gpiochip_add_data_with_key(chip, data, &lock_key, \ gpiochip_add_data_with_key(gc, data, &lock_key, \
&request_key); \ &request_key); \
}) })
#else #else
#define gpiochip_add_data(chip, data) gpiochip_add_data_with_key(chip, data, NULL, NULL) #define gpiochip_add_data(gc, data) gpiochip_add_data_with_key(gc, data, NULL, NULL)
#endif /* CONFIG_LOCKDEP */ #endif /* CONFIG_LOCKDEP */
static inline int gpiochip_add(struct gpio_chip *chip) static inline int gpiochip_add(struct gpio_chip *gc)
{ {
return gpiochip_add_data(chip, NULL); return gpiochip_add_data(gc, NULL);
} }
extern void gpiochip_remove(struct gpio_chip *chip); extern void gpiochip_remove(struct gpio_chip *gc);
extern int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip, extern int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *gc,
void *data); void *data);
extern struct gpio_chip *gpiochip_find(void *data, extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, void *data)); int (*match)(struct gpio_chip *gc, void *data));
bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset); bool gpiochip_line_is_irq(struct gpio_chip *gc, unsigned int offset);
int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset); int gpiochip_reqres_irq(struct gpio_chip *gc, unsigned int offset);
void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset); void gpiochip_relres_irq(struct gpio_chip *gc, unsigned int offset);
void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset); void gpiochip_disable_irq(struct gpio_chip *gc, unsigned int offset);
void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset); void gpiochip_enable_irq(struct gpio_chip *gc, unsigned int offset);
/* Line status inquiry for drivers */ /* Line status inquiry for drivers */
bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset); bool gpiochip_line_is_open_drain(struct gpio_chip *gc, unsigned int offset);
bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset); bool gpiochip_line_is_open_source(struct gpio_chip *gc, unsigned int offset);
/* Sleep persistence inquiry for drivers */ /* Sleep persistence inquiry for drivers */
bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset); bool gpiochip_line_is_persistent(struct gpio_chip *gc, unsigned int offset);
bool gpiochip_line_is_valid(const struct gpio_chip *chip, unsigned int offset); bool gpiochip_line_is_valid(const struct gpio_chip *gc, unsigned int offset);
/* get driver data */ /* get driver data */
void *gpiochip_get_data(struct gpio_chip *chip); void *gpiochip_get_data(struct gpio_chip *gc);
struct bgpio_pdata { struct bgpio_pdata {
const char *label; const char *label;
...@@ -536,23 +536,23 @@ struct bgpio_pdata { ...@@ -536,23 +536,23 @@ struct bgpio_pdata {
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
unsigned int parent_hwirq, unsigned int parent_hwirq,
unsigned int parent_type); unsigned int parent_type);
void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
unsigned int parent_hwirq, unsigned int parent_hwirq,
unsigned int parent_type); unsigned int parent_type);
#else #else
static inline void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, static inline void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *gc,
unsigned int parent_hwirq, unsigned int parent_hwirq,
unsigned int parent_type) unsigned int parent_type)
{ {
return NULL; return NULL;
} }
static inline void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, static inline void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *gc,
unsigned int parent_hwirq, unsigned int parent_hwirq,
unsigned int parent_type) unsigned int parent_type)
{ {
...@@ -572,6 +572,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev, ...@@ -572,6 +572,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
#define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3) #define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3)
#define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */ #define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */
#define BGPIOF_NO_OUTPUT BIT(5) /* only input */ #define BGPIOF_NO_OUTPUT BIT(5) /* only input */
#define BGPIOF_NO_SET_ON_INPUT BIT(6)
int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq); irq_hw_number_t hwirq);
...@@ -582,11 +583,11 @@ int gpiochip_irq_domain_activate(struct irq_domain *domain, ...@@ -582,11 +583,11 @@ int gpiochip_irq_domain_activate(struct irq_domain *domain,
void gpiochip_irq_domain_deactivate(struct irq_domain *domain, void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
struct irq_data *data); struct irq_data *data);
void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip, void gpiochip_set_nested_irqchip(struct gpio_chip *gc,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int parent_irq); unsigned int parent_irq);
int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, int gpiochip_irqchip_add_key(struct gpio_chip *gc,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int first_irq, unsigned int first_irq,
irq_flow_handler_t handler, irq_flow_handler_t handler,
...@@ -595,7 +596,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, ...@@ -595,7 +596,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
struct lock_class_key *lock_key, struct lock_class_key *lock_key,
struct lock_class_key *request_key); struct lock_class_key *request_key);
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
unsigned int offset); unsigned int offset);
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
...@@ -606,7 +607,7 @@ bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, ...@@ -606,7 +607,7 @@ bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
* boilerplate static inlines provides such a key for each * boilerplate static inlines provides such a key for each
* unique instance. * unique instance.
*/ */
static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip, static inline int gpiochip_irqchip_add(struct gpio_chip *gc,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int first_irq, unsigned int first_irq,
irq_flow_handler_t handler, irq_flow_handler_t handler,
...@@ -615,12 +616,12 @@ static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip, ...@@ -615,12 +616,12 @@ static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
static struct lock_class_key lock_key; static struct lock_class_key lock_key;
static struct lock_class_key request_key; static struct lock_class_key request_key;
return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq, return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
handler, type, false, handler, type, false,
&lock_key, &request_key); &lock_key, &request_key);
} }
static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip, static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gc,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int first_irq, unsigned int first_irq,
irq_flow_handler_t handler, irq_flow_handler_t handler,
...@@ -630,35 +631,35 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip, ...@@ -630,35 +631,35 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
static struct lock_class_key lock_key; static struct lock_class_key lock_key;
static struct lock_class_key request_key; static struct lock_class_key request_key;
return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq, return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
handler, type, true, handler, type, true,
&lock_key, &request_key); &lock_key, &request_key);
} }
#else /* ! CONFIG_LOCKDEP */ #else /* ! CONFIG_LOCKDEP */
static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip, static inline int gpiochip_irqchip_add(struct gpio_chip *gc,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int first_irq, unsigned int first_irq,
irq_flow_handler_t handler, irq_flow_handler_t handler,
unsigned int type) unsigned int type)
{ {
return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq, return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
handler, type, false, NULL, NULL); handler, type, false, NULL, NULL);
} }
static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip, static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gc,
struct irq_chip *irqchip, struct irq_chip *irqchip,
unsigned int first_irq, unsigned int first_irq,
irq_flow_handler_t handler, irq_flow_handler_t handler,
unsigned int type) unsigned int type)
{ {
return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq, return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
handler, type, true, NULL, NULL); handler, type, true, NULL, NULL);
} }
#endif /* CONFIG_LOCKDEP */ #endif /* CONFIG_LOCKDEP */
int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset); int gpiochip_generic_request(struct gpio_chip *gc, unsigned offset);
void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset); void gpiochip_generic_free(struct gpio_chip *gc, unsigned offset);
int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset, int gpiochip_generic_config(struct gpio_chip *gc, unsigned offset,
unsigned long config); unsigned long config);
/** /**
...@@ -675,25 +676,25 @@ struct gpio_pin_range { ...@@ -675,25 +676,25 @@ struct gpio_pin_range {
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, int gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name,
unsigned int gpio_offset, unsigned int pin_offset, unsigned int gpio_offset, unsigned int pin_offset,
unsigned int npins); unsigned int npins);
int gpiochip_add_pingroup_range(struct gpio_chip *chip, int gpiochip_add_pingroup_range(struct gpio_chip *gc,
struct pinctrl_dev *pctldev, struct pinctrl_dev *pctldev,
unsigned int gpio_offset, const char *pin_group); unsigned int gpio_offset, const char *pin_group);
void gpiochip_remove_pin_ranges(struct gpio_chip *chip); void gpiochip_remove_pin_ranges(struct gpio_chip *gc);
#else /* ! CONFIG_PINCTRL */ #else /* ! CONFIG_PINCTRL */
static inline int static inline int
gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, gpiochip_add_pin_range(struct gpio_chip *gc, const char *pinctl_name,
unsigned int gpio_offset, unsigned int pin_offset, unsigned int gpio_offset, unsigned int pin_offset,
unsigned int npins) unsigned int npins)
{ {
return 0; return 0;
} }
static inline int static inline int
gpiochip_add_pingroup_range(struct gpio_chip *chip, gpiochip_add_pingroup_range(struct gpio_chip *gc,
struct pinctrl_dev *pctldev, struct pinctrl_dev *pctldev,
unsigned int gpio_offset, const char *pin_group) unsigned int gpio_offset, const char *pin_group)
{ {
...@@ -701,27 +702,27 @@ gpiochip_add_pingroup_range(struct gpio_chip *chip, ...@@ -701,27 +702,27 @@ gpiochip_add_pingroup_range(struct gpio_chip *chip,
} }
static inline void static inline void
gpiochip_remove_pin_ranges(struct gpio_chip *chip) gpiochip_remove_pin_ranges(struct gpio_chip *gc)
{ {
} }
#endif /* CONFIG_PINCTRL */ #endif /* CONFIG_PINCTRL */
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc,
unsigned int hwnum, unsigned int hwnum,
const char *label, const char *label,
enum gpio_lookup_flags lflags, enum gpio_lookup_flags lflags,
enum gpiod_flags dflags); enum gpiod_flags dflags);
void gpiochip_free_own_desc(struct gpio_desc *desc); void gpiochip_free_own_desc(struct gpio_desc *desc);
void devprop_gpiochip_set_names(struct gpio_chip *chip, void devprop_gpiochip_set_names(struct gpio_chip *gc,
const struct fwnode_handle *fwnode); const struct fwnode_handle *fwnode);
#ifdef CONFIG_GPIOLIB #ifdef CONFIG_GPIOLIB
/* lock/unlock as IRQ */ /* lock/unlock as IRQ */
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset); int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset);
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset); void gpiochip_unlock_as_irq(struct gpio_chip *gc, unsigned int offset);
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc); struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
...@@ -735,14 +736,14 @@ static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) ...@@ -735,14 +736,14 @@ static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
static inline int gpiochip_lock_as_irq(struct gpio_chip *chip, static inline int gpiochip_lock_as_irq(struct gpio_chip *gc,
unsigned int offset) unsigned int offset)
{ {
WARN_ON(1); WARN_ON(1);
return -EINVAL; return -EINVAL;
} }
static inline void gpiochip_unlock_as_irq(struct gpio_chip *chip, static inline void gpiochip_unlock_as_irq(struct gpio_chip *gc,
unsigned int offset) unsigned int offset)
{ {
WARN_ON(1); WARN_ON(1);
......
...@@ -246,6 +246,37 @@ __kfifo_int_must_check_helper(int val) ...@@ -246,6 +246,37 @@ __kfifo_int_must_check_helper(int val)
__tmpq->kfifo.in == __tmpq->kfifo.out; \ __tmpq->kfifo.in == __tmpq->kfifo.out; \
}) })
/**
* kfifo_is_empty_spinlocked - returns true if the fifo is empty using
* a spinlock for locking
* @fifo: address of the fifo to be used
* @lock: spinlock to be used for locking
*/
#define kfifo_is_empty_spinlocked(fifo, lock) \
({ \
unsigned long __flags; \
bool __ret; \
spin_lock_irqsave(lock, __flags); \
__ret = kfifo_is_empty(fifo); \
spin_unlock_irqrestore(lock, __flags); \
__ret; \
})
/**
* kfifo_is_empty_spinlocked_noirqsave - returns true if the fifo is empty
* using a spinlock for locking, doesn't disable interrupts
* @fifo: address of the fifo to be used
* @lock: spinlock to be used for locking
*/
#define kfifo_is_empty_spinlocked_noirqsave(fifo, lock) \
({ \
bool __ret; \
spin_lock(lock); \
__ret = kfifo_is_empty(fifo); \
spin_unlock(lock); \
__ret; \
})
/** /**
* kfifo_is_full - returns true if the fifo is full * kfifo_is_full - returns true if the fifo is full
* @fifo: address of the fifo to be used * @fifo: address of the fifo to be used
...@@ -517,6 +548,26 @@ __kfifo_uint_must_check_helper( \ ...@@ -517,6 +548,26 @@ __kfifo_uint_must_check_helper( \
__ret; \ __ret; \
}) })
/**
* kfifo_in_spinlocked_noirqsave - put data into fifo using a spinlock for
* locking, don't disable interrupts
* @fifo: address of the fifo to be used
* @buf: the data to be added
* @n: number of elements to be added
* @lock: pointer to the spinlock to use for locking
*
* This is a variant of kfifo_in_spinlocked() but uses spin_lock/unlock()
* for locking and doesn't disable interrupts.
*/
#define kfifo_in_spinlocked_noirqsave(fifo, buf, n, lock) \
({ \
unsigned int __ret; \
spin_lock(lock); \
__ret = kfifo_in(fifo, buf, n); \
spin_unlock(lock); \
__ret; \
})
/* alias for kfifo_in_spinlocked, will be removed in a future release */ /* alias for kfifo_in_spinlocked, will be removed in a future release */
#define kfifo_in_locked(fifo, buf, n, lock) \ #define kfifo_in_locked(fifo, buf, n, lock) \
kfifo_in_spinlocked(fifo, buf, n, lock) kfifo_in_spinlocked(fifo, buf, n, lock)
...@@ -569,6 +620,28 @@ __kfifo_uint_must_check_helper( \ ...@@ -569,6 +620,28 @@ __kfifo_uint_must_check_helper( \
}) \ }) \
) )
/**
* kfifo_out_spinlocked_noirqsave - get data from the fifo using a spinlock
* for locking, don't disable interrupts
* @fifo: address of the fifo to be used
* @buf: pointer to the storage buffer
* @n: max. number of elements to get
* @lock: pointer to the spinlock to use for locking
*
* This is a variant of kfifo_out_spinlocked() which uses spin_lock/unlock()
* for locking and doesn't disable interrupts.
*/
#define kfifo_out_spinlocked_noirqsave(fifo, buf, n, lock) \
__kfifo_uint_must_check_helper( \
({ \
unsigned int __ret; \
spin_lock(lock); \
__ret = kfifo_out(fifo, buf, n); \
spin_unlock(lock); \
__ret; \
}) \
)
/* alias for kfifo_out_spinlocked, will be removed in a future release */ /* alias for kfifo_out_spinlocked, will be removed in a future release */
#define kfifo_out_locked(fifo, buf, n, lock) \ #define kfifo_out_locked(fifo, buf, n, lock) \
kfifo_out_spinlocked(fifo, buf, n, lock) kfifo_out_spinlocked(fifo, buf, n, lock)
......
...@@ -11,9 +11,8 @@ ...@@ -11,9 +11,8 @@
#define __LINUX_OF_GPIO_H #define __LINUX_OF_GPIO_H
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/kernel.h> #include <linux/gpio/driver.h>
#include <linux/errno.h> #include <linux/gpio.h> /* FIXME: Shouldn't be here */
#include <linux/gpio.h>
#include <linux/of.h> #include <linux/of.h>
struct device_node; struct device_node;
...@@ -34,6 +33,8 @@ enum of_gpio_flags { ...@@ -34,6 +33,8 @@ enum of_gpio_flags {
#ifdef CONFIG_OF_GPIO #ifdef CONFIG_OF_GPIO
#include <linux/kernel.h>
/* /*
* OF GPIO chip for memory mapped banks * OF GPIO chip for memory mapped banks
*/ */
...@@ -63,6 +64,8 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc); ...@@ -63,6 +64,8 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
#else /* CONFIG_OF_GPIO */ #else /* CONFIG_OF_GPIO */
#include <linux/errno.h>
/* Drivers may not strictly depend on the GPIO support, so let them link. */ /* Drivers may not strictly depend on the GPIO support, so let them link. */
static inline int of_get_named_gpio_flags(struct device_node *np, static inline int of_get_named_gpio_flags(struct device_node *np,
const char *list_name, int index, enum of_gpio_flags *flags) const char *list_name, int index, enum of_gpio_flags *flags)
......
...@@ -186,7 +186,7 @@ extern int pinctrl_get_group_pins(struct pinctrl_dev *pctldev, ...@@ -186,7 +186,7 @@ extern int pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
const char *pin_group, const unsigned **pins, const char *pin_group, const unsigned **pins,
unsigned *num_pins); unsigned *num_pins);
#ifdef CONFIG_OF #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_PINCTRL)
extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np); extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np);
#else #else
static inline static inline
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* struct gpiochip_info - Information about a certain GPIO chip * struct gpiochip_info - Information about a certain GPIO chip
* @name: the Linux kernel name of this GPIO chip * @name: the Linux kernel name of this GPIO chip
* @label: a functional name for this GPIO chip, such as a product * @label: a functional name for this GPIO chip, such as a product
* number, may be NULL * number, may be empty
* @lines: number of GPIO lines on this chip * @lines: number of GPIO lines on this chip
*/ */
struct gpiochip_info { struct gpiochip_info {
...@@ -44,10 +44,10 @@ struct gpiochip_info { ...@@ -44,10 +44,10 @@ struct gpiochip_info {
* @flags: various flags for this line * @flags: various flags for this line
* @name: the name of this GPIO line, such as the output pin of the line on the * @name: the name of this GPIO line, such as the output pin of the line on the
* chip, a rail or a pin header name on a board, as specified by the gpio * chip, a rail or a pin header name on a board, as specified by the gpio
* chip, may be NULL * chip, may be empty
* @consumer: a functional name for the consumer of this GPIO line as set by * @consumer: a functional name for the consumer of this GPIO line as set by
* whatever is using it, will be NULL if there is no current user but may * whatever is using it, will be empty if there is no current user but may
* also be NULL if the consumer doesn't set this up * also be empty if the consumer doesn't set this up
*/ */
struct gpioline_info { struct gpioline_info {
__u32 line_offset; __u32 line_offset;
...@@ -59,6 +59,34 @@ struct gpioline_info { ...@@ -59,6 +59,34 @@ struct gpioline_info {
/* Maximum number of requested handles */ /* Maximum number of requested handles */
#define GPIOHANDLES_MAX 64 #define GPIOHANDLES_MAX 64
/* Possible line status change events */
enum {
GPIOLINE_CHANGED_REQUESTED = 1,
GPIOLINE_CHANGED_RELEASED,
GPIOLINE_CHANGED_CONFIG,
};
/**
* struct gpioline_info_changed - Information about a change in status
* of a GPIO line
* @info: updated line information
* @timestamp: estimate of time of status change occurrence, in nanoseconds
* and GPIOLINE_CHANGED_CONFIG
* @event_type: one of GPIOLINE_CHANGED_REQUESTED, GPIOLINE_CHANGED_RELEASED
*
* Note: struct gpioline_info embedded here has 32-bit alignment on its own,
* but it works fine with 64-bit alignment too. With its 72 byte size, we can
* guarantee there are no implicit holes between it and subsequent members.
* The 20-byte padding at the end makes sure we don't add any implicit padding
* at the end of the structure on 64-bit architectures.
*/
struct gpioline_info_changed {
struct gpioline_info info;
__u64 timestamp;
__u32 event_type;
__u32 padding[5]; /* for future use */
};
/* Linerequest flags */ /* Linerequest flags */
#define GPIOHANDLE_REQUEST_INPUT (1UL << 0) #define GPIOHANDLE_REQUEST_INPUT (1UL << 0)
#define GPIOHANDLE_REQUEST_OUTPUT (1UL << 1) #define GPIOHANDLE_REQUEST_OUTPUT (1UL << 1)
...@@ -176,6 +204,8 @@ struct gpioevent_data { ...@@ -176,6 +204,8 @@ struct gpioevent_data {
#define GPIO_GET_CHIPINFO_IOCTL _IOR(0xB4, 0x01, struct gpiochip_info) #define GPIO_GET_CHIPINFO_IOCTL _IOR(0xB4, 0x01, struct gpiochip_info)
#define GPIO_GET_LINEINFO_IOCTL _IOWR(0xB4, 0x02, struct gpioline_info) #define GPIO_GET_LINEINFO_IOCTL _IOWR(0xB4, 0x02, struct gpioline_info)
#define GPIO_GET_LINEINFO_WATCH_IOCTL _IOWR(0xB4, 0x0b, struct gpioline_info)
#define GPIO_GET_LINEINFO_UNWATCH_IOCTL _IOWR(0xB4, 0x0c, __u32)
#define GPIO_GET_LINEHANDLE_IOCTL _IOWR(0xB4, 0x03, struct gpiohandle_request) #define GPIO_GET_LINEHANDLE_IOCTL _IOWR(0xB4, 0x03, struct gpiohandle_request)
#define GPIO_GET_LINEEVENT_IOCTL _IOWR(0xB4, 0x04, struct gpioevent_request) #define GPIO_GET_LINEEVENT_IOCTL _IOWR(0xB4, 0x04, struct gpioevent_request)
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
gpio-event-mon gpio-event-mon
gpio-hammer gpio-hammer
gpio-watch
lsgpio lsgpio
include/linux/gpio.h include/linux/gpio.h
...@@ -2,3 +2,4 @@ gpio-utils-y += gpio-utils.o ...@@ -2,3 +2,4 @@ gpio-utils-y += gpio-utils.o
lsgpio-y += lsgpio.o gpio-utils.o lsgpio-y += lsgpio.o gpio-utils.o
gpio-hammer-y += gpio-hammer.o gpio-utils.o gpio-hammer-y += gpio-hammer.o gpio-utils.o
gpio-event-mon-y += gpio-event-mon.o gpio-utils.o gpio-event-mon-y += gpio-event-mon.o gpio-utils.o
gpio-watch-y += gpio-watch.o
...@@ -18,7 +18,7 @@ MAKEFLAGS += -r ...@@ -18,7 +18,7 @@ MAKEFLAGS += -r
override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon gpio-watch
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
all: $(ALL_PROGRAMS) all: $(ALL_PROGRAMS)
...@@ -35,7 +35,7 @@ $(OUTPUT)include/linux/gpio.h: ../../include/uapi/linux/gpio.h ...@@ -35,7 +35,7 @@ $(OUTPUT)include/linux/gpio.h: ../../include/uapi/linux/gpio.h
prepare: $(OUTPUT)include/linux/gpio.h prepare: $(OUTPUT)include/linux/gpio.h
GPIO_UTILS_IN := $(output)gpio-utils-in.o GPIO_UTILS_IN := $(OUTPUT)gpio-utils-in.o
$(GPIO_UTILS_IN): prepare FORCE $(GPIO_UTILS_IN): prepare FORCE
$(Q)$(MAKE) $(build)=gpio-utils $(Q)$(MAKE) $(build)=gpio-utils
...@@ -66,6 +66,15 @@ $(GPIO_EVENT_MON_IN): prepare FORCE $(OUTPUT)gpio-utils-in.o ...@@ -66,6 +66,15 @@ $(GPIO_EVENT_MON_IN): prepare FORCE $(OUTPUT)gpio-utils-in.o
$(OUTPUT)gpio-event-mon: $(GPIO_EVENT_MON_IN) $(OUTPUT)gpio-event-mon: $(GPIO_EVENT_MON_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
#
# gpio-watch
#
GPIO_WATCH_IN := $(OUTPUT)gpio-watch-in.o
$(GPIO_WATCH_IN): prepare FORCE
$(Q)$(MAKE) $(build)=gpio-watch
$(OUTPUT)gpio-watch: $(GPIO_WATCH_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
clean: clean:
rm -f $(ALL_PROGRAMS) rm -f $(ALL_PROGRAMS)
rm -f $(OUTPUT)include/linux/gpio.h rm -f $(OUTPUT)include/linux/gpio.h
......
...@@ -77,7 +77,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines, ...@@ -77,7 +77,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines,
fprintf(stdout, "[%c] ", swirr[j]); fprintf(stdout, "[%c] ", swirr[j]);
j++; j++;
if (j == sizeof(swirr)-1) if (j == sizeof(swirr) - 1)
j = 0; j = 0;
fprintf(stdout, "["); fprintf(stdout, "[");
...@@ -135,7 +135,14 @@ int main(int argc, char **argv) ...@@ -135,7 +135,14 @@ int main(int argc, char **argv)
device_name = optarg; device_name = optarg;
break; break;
case 'o': case 'o':
lines[i] = strtoul(optarg, NULL, 10); /*
* Avoid overflow. Do not immediately error, we want to
* be able to accurately report on the amount of times
* '-o' was given to give an accurate error message
*/
if (i < GPIOHANDLES_MAX)
lines[i] = strtoul(optarg, NULL, 10);
i++; i++;
break; break;
case '?': case '?':
...@@ -143,6 +150,14 @@ int main(int argc, char **argv) ...@@ -143,6 +150,14 @@ int main(int argc, char **argv)
return -1; return -1;
} }
} }
if (i >= GPIOHANDLES_MAX) {
fprintf(stderr,
"Only %d occurrences of '-o' are allowed, %d were found\n",
GPIOHANDLES_MAX, i + 1);
return -1;
}
nlines = i; nlines = i;
if (!device_name || !nlines) { if (!device_name || !nlines) {
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include "gpio-utils.h" #include "gpio-utils.h"
#define COMSUMER "gpio-utils" #define CONSUMER "gpio-utils"
/** /**
* doc: Operation of gpio * doc: Operation of gpio
...@@ -209,7 +209,7 @@ int gpiotools_gets(const char *device_name, unsigned int *lines, ...@@ -209,7 +209,7 @@ int gpiotools_gets(const char *device_name, unsigned int *lines,
ret = gpiotools_request_linehandle(device_name, lines, nlines, ret = gpiotools_request_linehandle(device_name, lines, nlines,
GPIOHANDLE_REQUEST_INPUT, data, GPIOHANDLE_REQUEST_INPUT, data,
COMSUMER); CONSUMER);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -259,7 +259,7 @@ int gpiotools_sets(const char *device_name, unsigned int *lines, ...@@ -259,7 +259,7 @@ int gpiotools_sets(const char *device_name, unsigned int *lines,
ret = gpiotools_request_linehandle(device_name, lines, nlines, ret = gpiotools_request_linehandle(device_name, lines, nlines,
GPIOHANDLE_REQUEST_OUTPUT, data, GPIOHANDLE_REQUEST_OUTPUT, data,
COMSUMER); CONSUMER);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* gpio-watch - monitor unrequested lines for property changes using the
* character device
*
* Copyright (C) 2019 BayLibre SAS
* Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
*/
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/gpio.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
int main(int argc, char **argv)
{
struct gpioline_info_changed chg;
struct gpioline_info req;
struct pollfd pfd;
int fd, i, j, ret;
char *event, *end;
ssize_t rd;
if (argc < 3)
goto err_usage;
fd = open(argv[1], O_RDWR | O_CLOEXEC);
if (fd < 0) {
perror("unable to open gpiochip");
return EXIT_FAILURE;
}
for (i = 0, j = 2; i < argc - 2; i++, j++) {
memset(&req, 0, sizeof(req));
req.line_offset = strtoul(argv[j], &end, 0);
if (*end != '\0')
goto err_usage;
ret = ioctl(fd, GPIO_GET_LINEINFO_WATCH_IOCTL, &req);
if (ret) {
perror("unable to set up line watch");
return EXIT_FAILURE;
}
}
pfd.fd = fd;
pfd.events = POLLIN | POLLPRI;
for (;;) {
ret = poll(&pfd, 1, 5000);
if (ret < 0) {
perror("error polling the linechanged fd");
return EXIT_FAILURE;
} else if (ret > 0) {
memset(&chg, 0, sizeof(chg));
rd = read(pfd.fd, &chg, sizeof(chg));
if (rd < 0 || rd != sizeof(chg)) {
if (rd != sizeof(chg))
errno = EIO;
perror("error reading line change event");
return EXIT_FAILURE;
}
switch (chg.event_type) {
case GPIOLINE_CHANGED_REQUESTED:
event = "requested";
break;
case GPIOLINE_CHANGED_RELEASED:
event = "released";
break;
case GPIOLINE_CHANGED_CONFIG:
event = "config changed";
break;
default:
fprintf(stderr,
"invalid event type received from the kernel\n");
return EXIT_FAILURE;
}
printf("line %u: %s at %llu\n",
chg.info.line_offset, event, chg.timestamp);
}
}
return 0;
err_usage:
printf("%s: <gpiochip> <line0> <line1> ...\n", argv[0]);
return EXIT_FAILURE;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment