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;
if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
chips->chip.request = gpiochip_generic_request; chips->chip.request = gpiochip_generic_request;
chips->chip.free = gpiochip_generic_free; 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 {
......
...@@ -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;
if (pxa_gpio_has_pinctrl()) {
pchip->chip.request = gpiochip_generic_request; pchip->chip.request = gpiochip_generic_request;
pchip->chip.free = gpiochip_generic_free; 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);
id = of_alias_get_id(dev->of_node, "gpio");
raw_spin_lock_init(&chip->lock); raw_spin_lock_init(&chip->lock);
if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
chip->gc.request = gpiochip_generic_request; chip->gc.request = gpiochip_generic_request;
chip->gc.free = gpiochip_generic_free; chip->gc.free = gpiochip_generic_free;
}
id = of_alias_get_id(dev->of_node, "gpio");
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,
&dflags);
if (IS_ERR(desc))
break;
ret = gpiod_hog(desc, name, lflags, dflags);
if (ret < 0) { if (ret < 0) {
of_node_put(np); of_node_put(np);
return ret; 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 */
This diff is collapsed.
...@@ -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;
if (of_property_read_bool(node, "gpio-ranges")) {
jzgc->gc.request = gpiochip_generic_request; jzgc->gc.request = gpiochip_generic_request;
jzgc->gc.free = gpiochip_generic_free; 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 */
......
This diff is collapsed.
...@@ -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':
/*
* 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); 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