gpio updates for v5.11-rc1
- several refactoring patches of the core gpiolib code - add support for NXP PCAL9554B/C to gpio-pca953x - allow probing mockup devices from device tree - refactoring and improvements to gpio-rcar - improvements to locking in gpio-tegra - code shrink in gpiolib devres - get the irq offset from device tree in gpio-sifive - major refactoring of gpio-exar - convert gpio-mvebu pwm access to regmap - create a new submenu for virtual GPIO drivers - fix clang fall-through warnings treewide - minor driver refactoring and tweaks sprinkled all over -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAl/QnM8ACgkQEacuoBRx 13LkDw/+NKHc32hKgMJmSsLLFHgZ8XB+7Y775G5Ejxj+4Z0hVY9LdqL0zSYwrzCg D2dKwrKMtM83T8vf0bVbPdZ/9uuqrljvocGYt2CFmDqQa3sSlJkyDiSak2HAqjK/ p9cgDQaUIlDrg2xh/1kSqELQoONmp4m82i++bItIwxIqAwPWfjSHVD7EQznDu0QD MJ7eYSuVlpeBhMwfyGCYSuUFhd4wN+nTkLTYw3nNlU4PHCKpdgYd7SBCJjSsLAhM 8FOQ+PBspS6t8lPIEa4Mt+TOWUbbboGUBy40GPNU8QcUjbzj3TwPIBJu/0SIdSOy fBrk+GRjWtJ9shSlz0WQ19mG+qMjIiw4xLY1Jh3Tr4b75bQ3a4pk50aPWNE6bbHV NP1wZer/s06f1TQFKjfuDVFsOoRLyrTuOzlW0COAHoqFOdgimZi36xtjaS3AL3lE POBiBxFo9VaQ0enD99QMBt3940IP3ekRmlqRxeR1t8C0gE5np8IMZ5Dti8Fh4eCN hUQTDDuWQadluOdhMdLCBh5cA3VfZY8xksAMBzAYnSUHzM2D8TcKVjfJeegCEuZd kapAV3nLUv1/ZU36okFpMaHaKBL+xGDv8gtV2ro7rptkm6khNPQ3hxKvRbCRCG+S fO6IKThwozZEL/uVvsZLRKvN47g89oAGYYfasqq49932WChVKf8= =RmnM -----END PGP SIGNATURE----- Merge tag 'gpio-updates-for-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux into devel gpio updates for v5.11-rc1 - several refactoring patches of the core gpiolib code - add support for NXP PCAL9554B/C to gpio-pca953x - allow probing mockup devices from device tree - refactoring and improvements to gpio-rcar - improvements to locking in gpio-tegra - code shrink in gpiolib devres - get the irq offset from device tree in gpio-sifive - major refactoring of gpio-exar - convert gpio-mvebu pwm access to regmap - create a new submenu for virtual GPIO drivers - fix clang fall-through warnings treewide - minor driver refactoring and tweaks sprinkled all over
This commit is contained in:
commit
40b37008eb
|
@ -48,6 +48,7 @@ properties:
|
|||
- nxp,pcal6416
|
||||
- nxp,pcal6524
|
||||
- nxp,pcal9535
|
||||
- nxp,pcal9554b
|
||||
- nxp,pcal9555a
|
||||
- onnn,cat9554
|
||||
- onnn,pca9654
|
||||
|
|
|
@ -256,6 +256,7 @@ config GPIO_EP93XX
|
|||
config GPIO_EXAR
|
||||
tristate "Support for GPIO pins on XR17V352/354/358"
|
||||
depends on SERIAL_8250_EXAR
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Selecting this option will enable handling of GPIO pins present
|
||||
on Exar XR17V352/354/358 chips.
|
||||
|
@ -1602,6 +1603,8 @@ config GPIO_VIPERBOARD
|
|||
|
||||
endmenu
|
||||
|
||||
menu "Virtual GPIO drivers"
|
||||
|
||||
config GPIO_AGGREGATOR
|
||||
tristate "GPIO Aggregator"
|
||||
help
|
||||
|
@ -1625,4 +1628,6 @@ config GPIO_MOCKUP
|
|||
tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
|
||||
it.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
|
|
@ -123,6 +123,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
|
|||
switch (flow_type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
polarity |= mask;
|
||||
fallthrough;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
break;
|
||||
|
|
|
@ -616,10 +616,9 @@ static int dwapb_get_reset(struct dwapb_gpio *gpio)
|
|||
int err;
|
||||
|
||||
gpio->rst = devm_reset_control_get_optional_shared(gpio->dev, NULL);
|
||||
if (IS_ERR(gpio->rst)) {
|
||||
dev_err(gpio->dev, "Cannot get reset descriptor\n");
|
||||
return PTR_ERR(gpio->rst);
|
||||
}
|
||||
if (IS_ERR(gpio->rst))
|
||||
return dev_err_probe(gpio->dev, PTR_ERR(gpio->rst),
|
||||
"Cannot get reset descriptor\n");
|
||||
|
||||
err = reset_control_deassert(gpio->rst);
|
||||
if (err) {
|
||||
|
|
|
@ -4,14 +4,17 @@
|
|||
*
|
||||
* Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define EXAR_OFFSET_MPIOLVL_LO 0x90
|
||||
#define EXAR_OFFSET_MPIOSEL_LO 0x93
|
||||
|
@ -24,60 +27,39 @@ static DEFINE_IDA(ida_index);
|
|||
|
||||
struct exar_gpio_chip {
|
||||
struct gpio_chip gpio_chip;
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
int index;
|
||||
void __iomem *regs;
|
||||
char name[20];
|
||||
unsigned int first_pin;
|
||||
};
|
||||
|
||||
static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
|
||||
unsigned int offset)
|
||||
static unsigned int
|
||||
exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
int temp;
|
||||
|
||||
mutex_lock(&exar_gpio->lock);
|
||||
temp = readb(exar_gpio->regs + reg);
|
||||
temp &= ~BIT(offset);
|
||||
if (val)
|
||||
temp |= BIT(offset);
|
||||
writeb(temp, exar_gpio->regs + reg);
|
||||
mutex_unlock(&exar_gpio->lock);
|
||||
return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOSEL_HI
|
||||
: EXAR_OFFSET_MPIOSEL_LO;
|
||||
}
|
||||
|
||||
static int exar_set_direction(struct gpio_chip *chip, int direction,
|
||||
unsigned int offset)
|
||||
static unsigned int
|
||||
exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
|
||||
EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
|
||||
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
|
||||
|
||||
exar_update(chip, addr, direction, bit);
|
||||
return 0;
|
||||
return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOLVL_HI
|
||||
: EXAR_OFFSET_MPIOLVL_LO;
|
||||
}
|
||||
|
||||
static int exar_get(struct gpio_chip *chip, unsigned int reg)
|
||||
static unsigned int
|
||||
exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
int value;
|
||||
|
||||
mutex_lock(&exar_gpio->lock);
|
||||
value = readb(exar_gpio->regs + reg);
|
||||
mutex_unlock(&exar_gpio->lock);
|
||||
|
||||
return value;
|
||||
return (offset + exar_gpio->first_pin) % 8;
|
||||
}
|
||||
|
||||
static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
|
||||
EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
|
||||
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
|
||||
unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
if (exar_get(chip, addr) & BIT(bit))
|
||||
if (regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
@ -86,39 +68,66 @@ static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
|
|||
static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
|
||||
EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
|
||||
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
|
||||
unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
return !!(exar_get(chip, addr) & BIT(bit));
|
||||
return !!(regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)));
|
||||
}
|
||||
|
||||
static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
|
||||
EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
|
||||
unsigned int bit = (offset + exar_gpio->first_pin) % 8;
|
||||
unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
exar_update(chip, addr, value, bit);
|
||||
if (value)
|
||||
regmap_set_bits(exar_gpio->regmap, addr, BIT(bit));
|
||||
else
|
||||
regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit));
|
||||
}
|
||||
|
||||
static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
exar_set_value(chip, offset, value);
|
||||
return exar_set_direction(chip, 0, offset);
|
||||
regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return exar_set_direction(chip, 1, offset);
|
||||
struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
|
||||
unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
|
||||
unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
|
||||
|
||||
regmap_set_bits(exar_gpio->regmap, addr, BIT(bit));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exar_devm_ida_free(void *data)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = data;
|
||||
|
||||
ida_free(&ida_index, exar_gpio->index);
|
||||
}
|
||||
|
||||
static const struct regmap_config exar_regmap_config = {
|
||||
.name = "exar-gpio",
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int gpio_exar_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pci_dev *pcidev = to_pci_dev(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pci_dev *pcidev = to_pci_dev(dev->parent);
|
||||
struct exar_gpio_chip *exar_gpio;
|
||||
u32 first_pin, ngpios;
|
||||
void __iomem *p;
|
||||
|
@ -132,30 +141,37 @@ static int gpio_exar_probe(struct platform_device *pdev)
|
|||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev, "exar,first-pin",
|
||||
&first_pin);
|
||||
ret = device_property_read_u32(dev, "exar,first-pin", &first_pin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = device_property_read_u32(&pdev->dev, "ngpios", &ngpios);
|
||||
ret = device_property_read_u32(dev, "ngpios", &ngpios);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
exar_gpio = devm_kzalloc(&pdev->dev, sizeof(*exar_gpio), GFP_KERNEL);
|
||||
exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL);
|
||||
if (!exar_gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&exar_gpio->lock);
|
||||
/*
|
||||
* We don't need to check the return values of mmio regmap operations (unless
|
||||
* the regmap has a clock attached which is not the case here).
|
||||
*/
|
||||
exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config);
|
||||
if (IS_ERR(exar_gpio->regmap))
|
||||
return PTR_ERR(exar_gpio->regmap);
|
||||
|
||||
index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
|
||||
if (index < 0) {
|
||||
ret = index;
|
||||
goto err_mutex_destroy;
|
||||
}
|
||||
index = ida_alloc(&ida_index, GFP_KERNEL);
|
||||
if (index < 0)
|
||||
return index;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sprintf(exar_gpio->name, "exar_gpio%d", index);
|
||||
exar_gpio->gpio_chip.label = exar_gpio->name;
|
||||
exar_gpio->gpio_chip.parent = &pdev->dev;
|
||||
exar_gpio->gpio_chip.parent = dev;
|
||||
exar_gpio->gpio_chip.direction_output = exar_direction_output;
|
||||
exar_gpio->gpio_chip.direction_input = exar_direction_input;
|
||||
exar_gpio->gpio_chip.get_direction = exar_get_direction;
|
||||
|
@ -163,39 +179,20 @@ static int gpio_exar_probe(struct platform_device *pdev)
|
|||
exar_gpio->gpio_chip.set = exar_set_value;
|
||||
exar_gpio->gpio_chip.base = -1;
|
||||
exar_gpio->gpio_chip.ngpio = ngpios;
|
||||
exar_gpio->regs = p;
|
||||
exar_gpio->index = index;
|
||||
exar_gpio->first_pin = first_pin;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev,
|
||||
&exar_gpio->gpio_chip, exar_gpio);
|
||||
ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio);
|
||||
if (ret)
|
||||
goto err_destroy;
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, exar_gpio);
|
||||
|
||||
return 0;
|
||||
|
||||
err_destroy:
|
||||
ida_simple_remove(&ida_index, index);
|
||||
err_mutex_destroy:
|
||||
mutex_destroy(&exar_gpio->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gpio_exar_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
ida_simple_remove(&ida_index, exar_gpio->index);
|
||||
mutex_destroy(&exar_gpio->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_exar_driver = {
|
||||
.probe = gpio_exar_probe,
|
||||
.remove = gpio_exar_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/irq_sim.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
@ -460,9 +461,16 @@ static int gpio_mockup_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id gpio_mockup_of_match[] = {
|
||||
{ .compatible = "gpio-mockup", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpio_mockup_of_match);
|
||||
|
||||
static struct platform_driver gpio_mockup_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-mockup",
|
||||
.of_match_table = gpio_mockup_of_match,
|
||||
},
|
||||
.probe = gpio_mockup_probe,
|
||||
};
|
||||
|
@ -556,8 +564,7 @@ static int __init gpio_mockup_init(void)
|
|||
{
|
||||
int i, num_chips, err;
|
||||
|
||||
if ((gpio_mockup_num_ranges < 2) ||
|
||||
(gpio_mockup_num_ranges % 2) ||
|
||||
if ((gpio_mockup_num_ranges % 2) ||
|
||||
(gpio_mockup_num_ranges > GPIO_MOCKUP_MAX_RANGES))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -78,8 +78,7 @@
|
|||
|
||||
/*
|
||||
* The Armada XP has per-CPU registers for interrupt cause, interrupt
|
||||
* mask and interrupt level mask. Those are relative to the
|
||||
* percpu_membase.
|
||||
* mask and interrupt level mask. Those are in percpu_regs range.
|
||||
*/
|
||||
#define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4)
|
||||
#define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4)
|
||||
|
@ -93,7 +92,7 @@
|
|||
#define MVEBU_MAX_GPIO_PER_BANK 32
|
||||
|
||||
struct mvebu_pwm {
|
||||
void __iomem *membase;
|
||||
struct regmap *regs;
|
||||
unsigned long clk_rate;
|
||||
struct gpio_desc *gpiod;
|
||||
struct pwm_chip chip;
|
||||
|
@ -279,17 +278,17 @@ mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val)
|
|||
}
|
||||
|
||||
/*
|
||||
* Functions returning addresses of individual registers for a given
|
||||
* Functions returning offsets of individual registers for a given
|
||||
* PWM controller.
|
||||
*/
|
||||
static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
|
||||
static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
|
||||
{
|
||||
return mvpwm->membase + PWM_BLINK_ON_DURATION_OFF;
|
||||
return PWM_BLINK_ON_DURATION_OFF;
|
||||
}
|
||||
|
||||
static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
|
||||
static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
|
||||
{
|
||||
return mvpwm->membase + PWM_BLINK_OFF_DURATION_OFF;
|
||||
return PWM_BLINK_OFF_DURATION_OFF;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -600,6 +599,13 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static const struct regmap_config mvebu_gpio_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions implementing the pwm_chip methods
|
||||
*/
|
||||
|
@ -660,9 +666,8 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
|||
|
||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
|
||||
val = (unsigned long long)
|
||||
readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
val *= NSEC_PER_SEC;
|
||||
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u);
|
||||
val = (unsigned long long) u * NSEC_PER_SEC;
|
||||
do_div(val, mvpwm->clk_rate);
|
||||
if (val > UINT_MAX)
|
||||
state->duty_cycle = UINT_MAX;
|
||||
|
@ -671,9 +676,8 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
|||
else
|
||||
state->duty_cycle = 1;
|
||||
|
||||
val = (unsigned long long)
|
||||
readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
val *= NSEC_PER_SEC;
|
||||
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
|
||||
val = (unsigned long long) u * NSEC_PER_SEC;
|
||||
do_div(val, mvpwm->clk_rate);
|
||||
if (val < state->duty_cycle) {
|
||||
state->period = 1;
|
||||
|
@ -726,8 +730,8 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
|
||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
|
||||
writel_relaxed(on, mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
writel_relaxed(off, mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), on);
|
||||
regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), off);
|
||||
if (state->enabled)
|
||||
mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1);
|
||||
else
|
||||
|
@ -752,10 +756,10 @@ static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
|
|||
|
||||
regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
&mvpwm->blink_select);
|
||||
mvpwm->blink_on_duration =
|
||||
readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
mvpwm->blink_off_duration =
|
||||
readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
|
||||
&mvpwm->blink_on_duration);
|
||||
regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
|
||||
&mvpwm->blink_off_duration);
|
||||
}
|
||||
|
||||
static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
|
||||
|
@ -764,10 +768,10 @@ static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
|
|||
|
||||
regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
mvpwm->blink_select);
|
||||
writel_relaxed(mvpwm->blink_on_duration,
|
||||
mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
writel_relaxed(mvpwm->blink_off_duration,
|
||||
mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
|
||||
mvpwm->blink_on_duration);
|
||||
regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
|
||||
mvpwm->blink_off_duration);
|
||||
}
|
||||
|
||||
static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
|
@ -776,6 +780,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mvebu_pwm *mvpwm;
|
||||
void __iomem *base;
|
||||
u32 set;
|
||||
|
||||
if (!of_device_is_compatible(mvchip->chip.of_node,
|
||||
|
@ -813,9 +818,14 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
|||
mvchip->mvpwm = mvpwm;
|
||||
mvpwm->mvchip = mvchip;
|
||||
|
||||
mvpwm->membase = devm_platform_ioremap_resource_byname(pdev, "pwm");
|
||||
if (IS_ERR(mvpwm->membase))
|
||||
return PTR_ERR(mvpwm->membase);
|
||||
base = devm_platform_ioremap_resource_byname(pdev, "pwm");
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
&mvebu_gpio_regmap_config);
|
||||
if (IS_ERR(mvpwm->regs))
|
||||
return PTR_ERR(mvpwm->regs);
|
||||
|
||||
mvpwm->clk_rate = clk_get_rate(mvchip->clk);
|
||||
if (!mvpwm->clk_rate) {
|
||||
|
@ -1022,13 +1032,6 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config mvebu_gpio_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static int mvebu_gpio_probe_raw(struct platform_device *pdev,
|
||||
struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
|
|
|
@ -1049,11 +1049,8 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
|
|||
irq->first = irq_base;
|
||||
|
||||
ret = gpiochip_add_data(&bank->chip, bank);
|
||||
if (ret) {
|
||||
dev_err(bank->chip.parent,
|
||||
"Could not register gpio chip %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(bank->chip.parent, ret, "Could not register gpio chip\n");
|
||||
|
||||
ret = devm_request_irq(bank->chip.parent, bank->irq,
|
||||
omap_gpio_irq_handler,
|
||||
|
|
|
@ -32,6 +32,11 @@ struct gpio_rcar_bank_info {
|
|||
u32 intmsk;
|
||||
};
|
||||
|
||||
struct gpio_rcar_info {
|
||||
bool has_outdtsel;
|
||||
bool has_both_edge_trigger;
|
||||
};
|
||||
|
||||
struct gpio_rcar_priv {
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
|
@ -40,24 +45,23 @@ struct gpio_rcar_priv {
|
|||
struct irq_chip irq_chip;
|
||||
unsigned int irq_parent;
|
||||
atomic_t wakeup_path;
|
||||
bool has_outdtsel;
|
||||
bool has_both_edge_trigger;
|
||||
struct gpio_rcar_info info;
|
||||
struct gpio_rcar_bank_info bank_info;
|
||||
};
|
||||
|
||||
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
|
||||
#define INOUTSEL 0x04 /* General Input/Output Switching Register */
|
||||
#define OUTDT 0x08 /* General Output Register */
|
||||
#define INDT 0x0c /* General Input Register */
|
||||
#define INTDT 0x10 /* Interrupt Display Register */
|
||||
#define INTCLR 0x14 /* Interrupt Clear Register */
|
||||
#define INTMSK 0x18 /* Interrupt Mask Register */
|
||||
#define MSKCLR 0x1c /* Interrupt Mask Clear Register */
|
||||
#define POSNEG 0x20 /* Positive/Negative Logic Select Register */
|
||||
#define EDGLEVEL 0x24 /* Edge/level Select Register */
|
||||
#define FILONOFF 0x28 /* Chattering Prevention On/Off Register */
|
||||
#define OUTDTSEL 0x40 /* Output Data Select Register */
|
||||
#define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */
|
||||
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
|
||||
#define INOUTSEL 0x04 /* General Input/Output Switching Register */
|
||||
#define OUTDT 0x08 /* General Output Register */
|
||||
#define INDT 0x0c /* General Input Register */
|
||||
#define INTDT 0x10 /* Interrupt Display Register */
|
||||
#define INTCLR 0x14 /* Interrupt Clear Register */
|
||||
#define INTMSK 0x18 /* Interrupt Mask Register */
|
||||
#define MSKCLR 0x1c /* Interrupt Mask Clear Register */
|
||||
#define POSNEG 0x20 /* Positive/Negative Logic Select Register */
|
||||
#define EDGLEVEL 0x24 /* Edge/level Select Register */
|
||||
#define FILONOFF 0x28 /* Chattering Prevention On/Off Register */
|
||||
#define OUTDTSEL 0x40 /* Output Data Select Register */
|
||||
#define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */
|
||||
|
||||
#define RCAR_MAX_GPIO_PER_BANK 32
|
||||
|
||||
|
@ -123,7 +127,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
|
|||
gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
|
||||
|
||||
/* Select one edge or both edges in BOTHEDGE */
|
||||
if (p->has_both_edge_trigger)
|
||||
if (p->info.has_both_edge_trigger)
|
||||
gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
|
||||
|
||||
/* Select "Interrupt Input Mode" in IOINTSEL */
|
||||
|
@ -162,7 +166,7 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
false);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
if (!p->has_both_edge_trigger)
|
||||
if (!p->info.has_both_edge_trigger)
|
||||
return -EINVAL;
|
||||
gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
|
||||
true);
|
||||
|
@ -238,7 +242,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
|
|||
gpio_rcar_modify_bit(p, INOUTSEL, gpio, output);
|
||||
|
||||
/* Select General Output Register to output data in OUTDTSEL */
|
||||
if (p->has_outdtsel && output)
|
||||
if (p->info.has_outdtsel && output)
|
||||
gpio_rcar_modify_bit(p, OUTDTSEL, gpio, false);
|
||||
|
||||
spin_unlock_irqrestore(&p->lock, flags);
|
||||
|
@ -295,14 +299,44 @@ static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
|
|||
|
||||
static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
|
||||
u32 bit = BIT(offset);
|
||||
|
||||
/* testing on r8a7790 shows that INDT does not show correct pin state
|
||||
* when configured as output, so use OUTDT in case of output pins */
|
||||
if (gpio_rcar_read(gpiochip_get_data(chip), INOUTSEL) & bit)
|
||||
return !!(gpio_rcar_read(gpiochip_get_data(chip), OUTDT) & bit);
|
||||
if (gpio_rcar_read(p, INOUTSEL) & bit)
|
||||
return !!(gpio_rcar_read(p, OUTDT) & bit);
|
||||
else
|
||||
return !!(gpio_rcar_read(gpiochip_get_data(chip), INDT) & bit);
|
||||
return !!(gpio_rcar_read(p, INDT) & bit);
|
||||
}
|
||||
|
||||
static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpio_rcar_priv *p = gpiochip_get_data(chip);
|
||||
u32 bankmask, outputs, m, val = 0;
|
||||
unsigned long flags;
|
||||
|
||||
bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0);
|
||||
if (chip->valid_mask)
|
||||
bankmask &= chip->valid_mask[0];
|
||||
|
||||
if (!bankmask)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&p->lock, flags);
|
||||
outputs = gpio_rcar_read(p, INOUTSEL);
|
||||
m = outputs & bankmask;
|
||||
if (m)
|
||||
val |= gpio_rcar_read(p, OUTDT) & m;
|
||||
|
||||
m = ~outputs & bankmask;
|
||||
if (m)
|
||||
val |= gpio_rcar_read(p, INDT) & m;
|
||||
spin_unlock_irqrestore(&p->lock, flags);
|
||||
|
||||
bits[0] = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
|
@ -346,11 +380,6 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct gpio_rcar_info {
|
||||
bool has_outdtsel;
|
||||
bool has_both_edge_trigger;
|
||||
};
|
||||
|
||||
static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
|
||||
.has_outdtsel = false,
|
||||
.has_both_edge_trigger = false,
|
||||
|
@ -417,8 +446,7 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
|
|||
int ret;
|
||||
|
||||
info = of_device_get_match_data(p->dev);
|
||||
p->has_outdtsel = info->has_outdtsel;
|
||||
p->has_both_edge_trigger = info->has_both_edge_trigger;
|
||||
p->info = *info;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
|
||||
*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
|
||||
|
@ -479,6 +507,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
|||
gpio_chip->get_direction = gpio_rcar_get_direction;
|
||||
gpio_chip->direction_input = gpio_rcar_direction_input;
|
||||
gpio_chip->get = gpio_rcar_get;
|
||||
gpio_chip->get_multiple = gpio_rcar_get_multiple;
|
||||
gpio_chip->direction_output = gpio_rcar_direction_output;
|
||||
gpio_chip->set = gpio_rcar_set;
|
||||
gpio_chip->set_multiple = gpio_rcar_set_multiple;
|
||||
|
@ -552,7 +581,7 @@ static int gpio_rcar_suspend(struct device *dev)
|
|||
p->bank_info.intmsk = gpio_rcar_read(p, INTMSK);
|
||||
p->bank_info.posneg = gpio_rcar_read(p, POSNEG);
|
||||
p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL);
|
||||
if (p->has_both_edge_trigger)
|
||||
if (p->info.has_both_edge_trigger)
|
||||
p->bank_info.bothedge = gpio_rcar_read(p, BOTHEDGE);
|
||||
|
||||
if (atomic_read(&p->wakeup_path))
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#define SIFIVE_GPIO_OUTPUT_XOR 0x40
|
||||
|
||||
#define SIFIVE_GPIO_MAX 32
|
||||
#define SIFIVE_GPIO_IRQ_OFFSET 7
|
||||
|
||||
struct sifive_gpio {
|
||||
void __iomem *base;
|
||||
|
@ -37,7 +36,7 @@ struct sifive_gpio {
|
|||
struct regmap *regs;
|
||||
unsigned long irq_state;
|
||||
unsigned int trigger[SIFIVE_GPIO_MAX];
|
||||
unsigned int irq_parent[SIFIVE_GPIO_MAX];
|
||||
unsigned int irq_number[SIFIVE_GPIO_MAX];
|
||||
};
|
||||
|
||||
static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset)
|
||||
|
@ -155,8 +154,12 @@ static int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
|
|||
unsigned int *parent,
|
||||
unsigned int *parent_type)
|
||||
{
|
||||
struct sifive_gpio *chip = gpiochip_get_data(gc);
|
||||
struct irq_data *d = irq_get_irq_data(chip->irq_number[child]);
|
||||
|
||||
*parent_type = IRQ_TYPE_NONE;
|
||||
*parent = child + SIFIVE_GPIO_IRQ_OFFSET;
|
||||
*parent = irqd_to_hwirq(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -176,7 +179,7 @@ static int sifive_gpio_probe(struct platform_device *pdev)
|
|||
struct irq_domain *parent;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct sifive_gpio *chip;
|
||||
int ret, ngpio;
|
||||
int ret, ngpio, i;
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
|
@ -211,6 +214,9 @@ static int sifive_gpio_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
for (i = 0; i < ngpio; i++)
|
||||
chip->irq_number[i] = platform_get_irq(pdev, i);
|
||||
|
||||
ret = bgpio_init(&chip->gc, dev, 4,
|
||||
chip->base + SIFIVE_GPIO_INPUT_VAL,
|
||||
chip->base + SIFIVE_GPIO_OUTPUT_VAL,
|
||||
|
|
|
@ -61,8 +61,16 @@ struct tegra_gpio_info;
|
|||
struct tegra_gpio_bank {
|
||||
unsigned int bank;
|
||||
unsigned int irq;
|
||||
spinlock_t lvl_lock[4];
|
||||
spinlock_t dbc_lock[4]; /* Lock for updating debounce count register */
|
||||
|
||||
/*
|
||||
* IRQ-core code uses raw locking, and thus, nested locking also
|
||||
* should be raw in order not to trip spinlock debug warnings.
|
||||
*/
|
||||
raw_spinlock_t lvl_lock[4];
|
||||
|
||||
/* Lock for updating debounce count register */
|
||||
spinlock_t dbc_lock[4];
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
u32 cnf[4];
|
||||
u32 out[4];
|
||||
|
@ -334,14 +342,14 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&bank->lvl_lock[port], flags);
|
||||
raw_spin_lock_irqsave(&bank->lvl_lock[port], flags);
|
||||
|
||||
val = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio));
|
||||
val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio));
|
||||
val |= lvl_type << GPIO_BIT(gpio);
|
||||
tegra_gpio_writel(tgi, val, GPIO_INT_LVL(tgi, gpio));
|
||||
|
||||
spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
|
||||
raw_spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
|
||||
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, gpio), gpio, 0);
|
||||
tegra_gpio_enable(tgi, gpio);
|
||||
|
@ -560,6 +568,9 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {
|
|||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
|
||||
};
|
||||
|
||||
static struct lock_class_key gpio_lock_class;
|
||||
static struct lock_class_key gpio_request_class;
|
||||
|
||||
static int tegra_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_gpio_info *tgi;
|
||||
|
@ -661,6 +672,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
|||
bank = &tgi->bank_info[GPIO_BANK(gpio)];
|
||||
|
||||
irq_set_chip_data(irq, bank);
|
||||
irq_set_lockdep_class(irq, &gpio_lock_class, &gpio_request_class);
|
||||
irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);
|
||||
}
|
||||
|
||||
|
@ -671,7 +683,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
|||
tegra_gpio_irq_handler, bank);
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
spin_lock_init(&bank->lvl_lock[j]);
|
||||
raw_spin_lock_init(&bank->lvl_lock[j]);
|
||||
spin_lock_init(&bank->dbc_lock[j]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,15 +186,7 @@ static int xra1403_probe(struct spi_device *spi)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_gpiochip_add_data(&spi->dev, &xra->chip, xra);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Unable to register gpiochip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, xra);
|
||||
|
||||
return 0;
|
||||
return devm_gpiochip_add_data(&spi->dev, &xra->chip, xra);
|
||||
}
|
||||
|
||||
static const struct spi_device_id xra1403_ids[] = {
|
||||
|
|
|
@ -233,6 +233,7 @@ acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio, int polarity)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -428,6 +428,12 @@ struct line {
|
|||
*/
|
||||
struct linereq *req;
|
||||
unsigned int irq;
|
||||
/*
|
||||
* eflags is set by edge_detector_setup(), edge_detector_stop() and
|
||||
* edge_detector_update(), which are themselves mutually exclusive,
|
||||
* and is accessed by edge_irq_thread() and debounce_work_func(),
|
||||
* which can both live with a slightly stale value.
|
||||
*/
|
||||
u64 eflags;
|
||||
/*
|
||||
* timestamp_ns and req_seqno are accessed only by
|
||||
|
@ -504,6 +510,8 @@ struct linereq {
|
|||
(GPIO_V2_LINE_FLAG_EDGE_RISING | \
|
||||
GPIO_V2_LINE_FLAG_EDGE_FALLING)
|
||||
|
||||
#define GPIO_V2_LINE_FLAG_EDGE_BOTH GPIO_V2_LINE_EDGE_FLAGS
|
||||
|
||||
#define GPIO_V2_LINE_VALID_FLAGS \
|
||||
(GPIO_V2_LINE_FLAG_ACTIVE_LOW | \
|
||||
GPIO_V2_LINE_DIRECTION_FLAGS | \
|
||||
|
@ -543,6 +551,7 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
|
|||
struct line *line = p;
|
||||
struct linereq *lr = line->req;
|
||||
struct gpio_v2_line_event le;
|
||||
u64 eflags;
|
||||
|
||||
/* Do not leak kernel stack to userspace */
|
||||
memset(&le, 0, sizeof(le));
|
||||
|
@ -561,8 +570,8 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
|
|||
}
|
||||
line->timestamp_ns = 0;
|
||||
|
||||
if (line->eflags == (GPIO_V2_LINE_FLAG_EDGE_RISING |
|
||||
GPIO_V2_LINE_FLAG_EDGE_FALLING)) {
|
||||
eflags = READ_ONCE(line->eflags);
|
||||
if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) {
|
||||
int level = gpiod_get_value_cansleep(line->desc);
|
||||
|
||||
if (level)
|
||||
|
@ -571,10 +580,10 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
|
|||
else
|
||||
/* Emit high-to-low event */
|
||||
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
|
||||
} else if (line->eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
|
||||
} else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
|
||||
/* Emit low-to-high event */
|
||||
le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
|
||||
} else if (line->eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
|
||||
} else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
|
||||
/* Emit high-to-low event */
|
||||
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
|
||||
} else {
|
||||
|
@ -643,6 +652,7 @@ static void debounce_work_func(struct work_struct *work)
|
|||
struct line *line = container_of(work, struct line, work.work);
|
||||
struct linereq *lr;
|
||||
int level;
|
||||
u64 eflags;
|
||||
|
||||
level = gpiod_get_raw_value_cansleep(line->desc);
|
||||
if (level < 0) {
|
||||
|
@ -656,7 +666,8 @@ static void debounce_work_func(struct work_struct *work)
|
|||
WRITE_ONCE(line->level, level);
|
||||
|
||||
/* -- edge detection -- */
|
||||
if (!line->eflags)
|
||||
eflags = READ_ONCE(line->eflags);
|
||||
if (!eflags)
|
||||
return;
|
||||
|
||||
/* switch from physical level to logical - if they differ */
|
||||
|
@ -664,8 +675,8 @@ static void debounce_work_func(struct work_struct *work)
|
|||
level = !level;
|
||||
|
||||
/* ignore edges that are not being monitored */
|
||||
if (((line->eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) && !level) ||
|
||||
((line->eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) && level))
|
||||
if (((eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) && !level) ||
|
||||
((eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) && level))
|
||||
return;
|
||||
|
||||
/* Do not leak kernel stack to userspace */
|
||||
|
@ -764,7 +775,7 @@ static void edge_detector_stop(struct line *line)
|
|||
|
||||
cancel_delayed_work_sync(&line->work);
|
||||
WRITE_ONCE(line->sw_debounced, 0);
|
||||
line->eflags = 0;
|
||||
WRITE_ONCE(line->eflags, 0);
|
||||
/* do not change line->level - see comment in debounced_value() */
|
||||
}
|
||||
|
||||
|
@ -783,7 +794,7 @@ static int edge_detector_setup(struct line *line,
|
|||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
line->eflags = eflags;
|
||||
WRITE_ONCE(line->eflags, eflags);
|
||||
if (gpio_v2_line_config_debounced(lc, line_idx)) {
|
||||
debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx);
|
||||
ret = debounce_setup(line, debounce_period_us);
|
||||
|
@ -826,13 +837,13 @@ static int edge_detector_update(struct line *line,
|
|||
unsigned int debounce_period_us =
|
||||
gpio_v2_line_config_debounce_period(lc, line_idx);
|
||||
|
||||
if ((line->eflags == eflags) && !polarity_change &&
|
||||
if ((READ_ONCE(line->eflags) == eflags) && !polarity_change &&
|
||||
(READ_ONCE(line->desc->debounce_period_us) == debounce_period_us))
|
||||
return 0;
|
||||
|
||||
/* sw debounced and still will be...*/
|
||||
if (debounce_period_us && READ_ONCE(line->sw_debounced)) {
|
||||
line->eflags = eflags;
|
||||
WRITE_ONCE(line->eflags, eflags);
|
||||
WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -246,10 +246,8 @@ struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
|
|||
struct gpio_desc *desc;
|
||||
|
||||
desc = devm_gpiod_get_index(dev, con_id, index, flags);
|
||||
if (IS_ERR(desc)) {
|
||||
if (PTR_ERR(desc) == -ENOENT)
|
||||
return NULL;
|
||||
}
|
||||
if (gpiod_not_found(desc))
|
||||
return NULL;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
@ -308,7 +306,7 @@ devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
|
|||
struct gpio_descs *descs;
|
||||
|
||||
descs = devm_gpiod_get_array(dev, con_id, flags);
|
||||
if (PTR_ERR(descs) == -ENOENT)
|
||||
if (gpiod_not_found(descs))
|
||||
return NULL;
|
||||
|
||||
return descs;
|
||||
|
@ -479,9 +477,9 @@ void devm_gpio_free(struct device *dev, unsigned int gpio)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(devm_gpio_free);
|
||||
|
||||
static void devm_gpio_chip_release(struct device *dev, void *res)
|
||||
static void devm_gpio_chip_release(void *data)
|
||||
{
|
||||
struct gpio_chip *gc = *(struct gpio_chip **)res;
|
||||
struct gpio_chip *gc = data;
|
||||
|
||||
gpiochip_remove(gc);
|
||||
}
|
||||
|
@ -507,23 +505,12 @@ int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, vo
|
|||
struct lock_class_key *lock_key,
|
||||
struct lock_class_key *request_key)
|
||||
{
|
||||
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_with_key(gc, data, lock_key, request_key);
|
||||
if (ret < 0) {
|
||||
devres_free(ptr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
*ptr = gc;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return 0;
|
||||
return devm_add_action_or_reset(dev, devm_gpio_chip_release, gc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_gpiochip_add_data_with_key);
|
||||
|
|
|
@ -509,31 +509,31 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
|
|||
desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
|
||||
&of_flags);
|
||||
|
||||
if (!IS_ERR(desc) || PTR_ERR(desc) != -ENOENT)
|
||||
if (!gpiod_not_found(desc))
|
||||
break;
|
||||
}
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT) {
|
||||
if (gpiod_not_found(desc)) {
|
||||
/* Special handling for SPI GPIOs if used */
|
||||
desc = of_find_spi_gpio(dev, con_id, &of_flags);
|
||||
}
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT) {
|
||||
if (gpiod_not_found(desc)) {
|
||||
/* This quirk looks up flags and all */
|
||||
desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
|
||||
if (!IS_ERR(desc))
|
||||
return desc;
|
||||
}
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT) {
|
||||
if (gpiod_not_found(desc)) {
|
||||
/* Special handling for regulator GPIOs if used */
|
||||
desc = of_find_regulator_gpio(dev, con_id, &of_flags);
|
||||
}
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT)
|
||||
if (gpiod_not_found(desc))
|
||||
desc = of_find_arizona_gpio(dev, con_id, &of_flags);
|
||||
|
||||
if (PTR_ERR(desc) == -ENOENT)
|
||||
if (gpiod_not_found(desc))
|
||||
desc = of_find_usb_gpio(dev, con_id, &of_flags);
|
||||
|
||||
if (IS_ERR(desc))
|
||||
|
@ -593,7 +593,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
|
|||
|
||||
xlate_flags = 0;
|
||||
*lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
|
||||
*dflags = 0;
|
||||
*dflags = GPIOD_ASIS;
|
||||
|
||||
ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
|
||||
if (ret)
|
||||
|
|
|
@ -476,7 +476,7 @@ static ssize_t export_store(struct class *class,
|
|||
*/
|
||||
|
||||
status = gpiod_request(desc, "sysfs");
|
||||
if (status < 0) {
|
||||
if (status) {
|
||||
if (status == -EPROBE_DEFER)
|
||||
status = -ENODEV;
|
||||
goto done;
|
||||
|
|
|
@ -772,9 +772,11 @@ err_free_ida:
|
|||
ida_free(&gpio_ida, gdev->id);
|
||||
err_free_gdev:
|
||||
/* failures here can mean systems won't boot... */
|
||||
pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
|
||||
gdev->base, gdev->base + gdev->ngpio - 1,
|
||||
gc->label ? : "generic", ret);
|
||||
if (ret != -EPROBE_DEFER) {
|
||||
pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
|
||||
gdev->base, gdev->base + gdev->ngpio - 1,
|
||||
gc->label ? : "generic", ret);
|
||||
}
|
||||
kfree(gdev);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1828,11 +1830,9 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
|||
|
||||
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
|
||||
desc_set_label(desc, label ? : "?");
|
||||
ret = 0;
|
||||
} else {
|
||||
kfree_const(label);
|
||||
ret = -EBUSY;
|
||||
goto done;
|
||||
goto out_free_unlock;
|
||||
}
|
||||
|
||||
if (gc->request) {
|
||||
|
@ -1845,11 +1845,10 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
|||
ret = -EINVAL;
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
if (ret < 0) {
|
||||
if (ret) {
|
||||
desc_set_label(desc, NULL);
|
||||
kfree_const(label);
|
||||
clear_bit(FLAG_REQUESTED, &desc->flags);
|
||||
goto done;
|
||||
goto out_free_unlock;
|
||||
}
|
||||
}
|
||||
if (gc->get_direction) {
|
||||
|
@ -1858,8 +1857,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
|
|||
gpiod_get_direction(desc);
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
}
|
||||
done:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return 0;
|
||||
|
||||
out_free_unlock:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
kfree_const(label);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1911,7 +1914,7 @@ int gpiod_request(struct gpio_desc *desc, const char *label)
|
|||
|
||||
if (try_module_get(gdev->owner)) {
|
||||
ret = gpiod_request_commit(desc, label);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
module_put(gdev->owner);
|
||||
else
|
||||
get_device(&gdev->dev);
|
||||
|
@ -3644,7 +3647,7 @@ struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
|
|||
|
||||
desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags,
|
||||
label);
|
||||
if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
|
||||
if (!gpiod_not_found(desc))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3820,7 +3823,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
|||
* Either we are not using DT or ACPI, or their lookup did not return
|
||||
* a result. In that case, use platform lookup as a fallback.
|
||||
*/
|
||||
if (!desc || desc == ERR_PTR(-ENOENT)) {
|
||||
if (!desc || gpiod_not_found(desc)) {
|
||||
dev_dbg(dev, "using lookup tables for GPIO lookup\n");
|
||||
desc = gpiod_find(dev, con_id, idx, &lookupflags);
|
||||
}
|
||||
|
@ -3835,7 +3838,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
|||
* the device name as label
|
||||
*/
|
||||
ret = gpiod_request(desc, con_id ? con_id : devname);
|
||||
if (ret < 0) {
|
||||
if (ret) {
|
||||
if (ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
|
||||
/*
|
||||
* This happens when there are several consumers for
|
||||
|
@ -3955,10 +3958,8 @@ struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev,
|
|||
struct gpio_desc *desc;
|
||||
|
||||
desc = gpiod_get_index(dev, con_id, index, flags);
|
||||
if (IS_ERR(desc)) {
|
||||
if (PTR_ERR(desc) == -ENOENT)
|
||||
return NULL;
|
||||
}
|
||||
if (gpiod_not_found(desc))
|
||||
return NULL;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
@ -4160,7 +4161,7 @@ struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev,
|
|||
struct gpio_descs *descs;
|
||||
|
||||
descs = gpiod_get_array(dev, con_id, flags);
|
||||
if (PTR_ERR(descs) == -ENOENT)
|
||||
if (gpiod_not_found(descs))
|
||||
return NULL;
|
||||
|
||||
return descs;
|
||||
|
|
|
@ -131,6 +131,8 @@ struct gpio_desc {
|
|||
#endif
|
||||
};
|
||||
|
||||
#define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
|
||||
|
||||
int gpiod_request(struct gpio_desc *desc, const char *label);
|
||||
void gpiod_free(struct gpio_desc *desc);
|
||||
int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
|
||||
|
|
Loading…
Reference in New Issue