mirror of
https://github.com/torvalds/linux.git
synced 2026-05-29 17:43:52 +02:00
gpio updates for v6.14-rc1
Driver improvements:
- support a new model in gpio-mpc8xxx
- refactor gpio-tqmx86 and add support for direction setting
- allow building gpio-omap with COMPILE_TEST=y
- use gpiochip_get_data() instead of dev_get_drvdata() in gpio-twl6040
- drop unued field from driver data in gpio-altera
- use generic request/free callbacks in gpio-regmap for better integration
with pinctrl
- use dev_err_probe() where applicable in gpio-pca953x
- use existing dedicated GPIO defines in gpio-tps65219 instead of custom
ones
DT bindings:
- document a new model in fsl,qoriq-gpio
- explain the chip's latch clock pin and how it works like chip-select
in fairchild,74hc595
- enable the gpio-line-names property for gpio-brcmstb
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmeOV4QACgkQEacuoBRx
13KgVhAAyDU80gfEydvhtgtnCf70zD/SiqQ6Jj+4/zexkLi8N8oKAKCcdD8bL00+
sY/fJQbLqhms9ctQ2HAoZXo7ftXlDdCZpMP5LKY9SeYHj/YSLW2HYHtTJ/viuq/w
xdF+kWMDXV56zkXcSDruK8zhRPEtM77QLALjGwLsePh0qtKFYyESd0Xmi5p92dt5
I7KczMZpUclBBa1VsNTDzEVzoJmaI/G9HC/4yZZQ0ULfGvnSNg91UjS2Kph8h4/8
DBnTtqZ9xM/bLAZmPqyrHYHGcUoDtXeDAO0pQpAW/pSjlQxQGNs4yMXXkrISu0Lg
nZHpIWPstUzeMQG9dele1MZsH4fDdwzfzacDQTNdNRqUwXVUlNWF19QhA1qGsjH+
Mg1ROmSIeUFIUsMv2t7BnomcXcSL/BjhS62BNpX54prJ36dvF/N80hMP4dlkI5uI
plktRGpEXt/LHrzFyakEB06rRMCQKmSGo8SelhfH8/FPWFPude6/AKQy2+favIwW
ZmKGp3agCERuM2fBYisVKm5iIAgRmO4s7eNhlQhd25uX2pBzkRFPk91yO2FS8H/9
3UcOjkmGaQPlDLSpTcZt4WdS8VABt26E5DNXUYnvPKalb4LgNF/hA8KkYBkAY1v4
U46xbRjnLESU+1jCz5iz5wn8D+N/ThHDTWeUPDdme/9mnsO2ZA4=
=iXkF
-----END PGP SIGNATURE-----
Merge tag 'gpio-updates-for-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
"Thanks to little activity in December, this is really tiny. Just a few
updates to drivers and device-tree bindings.
Driver improvements:
- support a new model in gpio-mpc8xxx
- refactor gpio-tqmx86 and add support for direction setting
- allow building gpio-omap with COMPILE_TEST=y
- use gpiochip_get_data() instead of dev_get_drvdata() in
gpio-twl6040
- drop unued field from driver data in gpio-altera
- use generic request/free callbacks in gpio-regmap for better
integration with pinctrl
- use dev_err_probe() where applicable in gpio-pca953x
- use existing dedicated GPIO defines in gpio-tps65219 instead of
custom ones
DT bindings:
- document a new model in fsl,qoriq-gpio
- explain the chip's latch clock pin and how it works like
chip-select in fairchild,74hc595
- enable the gpio-line-names property for gpio-brcmstb"
* tag 'gpio-updates-for-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
gpio: regmap: Use generic request/free ops
gpio: altera: Drop .mapped_irq from driver data
gpio: mpc8xxx: Add MPC8314 support
dt-bindings: gpio: fsl,qoriq-gpio: Add compatible string fsl,mpc8314-gpio
dt-bindings: gpio: fairchild,74hc595: Document chip select vs. latch clock
gpio: tps65219: Use existing kernel gpio macros
gpio: pca953x: log an error when failing to get the reset GPIO
dt-bindings: gpio: brcmstb: permit gpio-line-names property
gpio: tqmx86: add support for changing GPIO directions
gpio: tqmx86: introduce tqmx86_gpio_clrsetbits() helper
gpio: tqmx86: use cleanup guards for spinlock
gpio: tqmx86: consistently refer to IRQs by hwirq numbers
gpio: tqmx86: add macros for interrupt configuration
gpio: omap: allow building the module with COMPILE_TEST=y
gpio: twl4030: use gpiochip_get_data
This commit is contained in:
commit
4abae5b6af
|
|
@ -64,6 +64,10 @@ properties:
|
|||
|
||||
gpio-ranges: true
|
||||
|
||||
gpio-line-names:
|
||||
minItems: 1
|
||||
maxItems: 128
|
||||
|
||||
wakeup-source:
|
||||
type: boolean
|
||||
description: >
|
||||
|
|
|
|||
|
|
@ -6,6 +6,23 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
|||
|
||||
title: Generic 8-bit shift register
|
||||
|
||||
description: |
|
||||
NOTE: These chips nominally don't have a chip select pin. They do however
|
||||
have a rising-edge triggered latch clock (or storage register clock) pin,
|
||||
which behaves like an active-low chip select.
|
||||
|
||||
After the bits are shifted into the shift register, CS# is driven high, which
|
||||
the 74HC595 sees as a rising edge on the latch clock that results in a
|
||||
transfer of the bits from the shift register to the storage register and thus
|
||||
to the output pins.
|
||||
_ _ _ _
|
||||
shift clock ____| |_| |_..._| |_| |_________
|
||||
|
||||
latch clock * trigger
|
||||
___ ________
|
||||
chip select# |___________________|
|
||||
|
||||
|
||||
maintainers:
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ properties:
|
|||
- enum:
|
||||
- fsl,mpc5121-gpio
|
||||
- fsl,mpc5125-gpio
|
||||
- fsl,mpc8314-gpio
|
||||
- fsl,mpc8349-gpio
|
||||
- fsl,mpc8572-gpio
|
||||
- fsl,mpc8610-gpio
|
||||
|
|
|
|||
|
|
@ -529,9 +529,9 @@ config GPIO_OCTEON
|
|||
family of SOCs.
|
||||
|
||||
config GPIO_OMAP
|
||||
tristate "TI OMAP GPIO support" if ARCH_OMAP2PLUS || COMPILE_TEST
|
||||
tristate "TI OMAP GPIO support"
|
||||
depends on ARCH_OMAP || COMPILE_TEST
|
||||
default y if ARCH_OMAP
|
||||
depends on ARM
|
||||
select GENERIC_IRQ_CHIP
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
|
|
|
|||
|
|
@ -32,14 +32,12 @@
|
|||
* will be blocked until the current one completes.
|
||||
* @interrupt_trigger : specifies the hardware configured IRQ trigger type
|
||||
* (rising, falling, both, high)
|
||||
* @mapped_irq : kernel mapped irq number.
|
||||
*/
|
||||
struct altera_gpio_chip {
|
||||
struct gpio_chip gc;
|
||||
void __iomem *regs;
|
||||
raw_spinlock_t gpio_lock;
|
||||
int interrupt_trigger;
|
||||
int mapped_irq;
|
||||
};
|
||||
|
||||
static void altera_gpio_irq_unmask(struct irq_data *d)
|
||||
|
|
@ -235,6 +233,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
|||
int reg, ret;
|
||||
struct altera_gpio_chip *altera_gc;
|
||||
struct gpio_irq_chip *girq;
|
||||
int mapped_irq;
|
||||
|
||||
altera_gc = devm_kzalloc(&pdev->dev, sizeof(*altera_gc), GFP_KERNEL);
|
||||
if (!altera_gc)
|
||||
|
|
@ -271,8 +270,8 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(altera_gc->regs))
|
||||
return dev_err_probe(dev, PTR_ERR(altera_gc->regs), "failed to ioremap memory resource\n");
|
||||
|
||||
altera_gc->mapped_irq = platform_get_irq_optional(pdev, 0);
|
||||
if (altera_gc->mapped_irq < 0)
|
||||
mapped_irq = platform_get_irq_optional(pdev, 0);
|
||||
if (mapped_irq < 0)
|
||||
goto skip_irq;
|
||||
|
||||
if (device_property_read_u32(dev, "altr,interrupt-type", ®)) {
|
||||
|
|
@ -296,7 +295,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->parents[0] = altera_gc->mapped_irq;
|
||||
girq->parents[0] = mapped_irq;
|
||||
|
||||
skip_irq:
|
||||
ret = devm_gpiochip_add_data(dev, &altera_gc->gc, altera_gc);
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@ static const struct mpc8xxx_gpio_devtype mpc8xxx_gpio_devtype_default = {
|
|||
};
|
||||
|
||||
static const struct of_device_id mpc8xxx_gpio_ids[] = {
|
||||
{ .compatible = "fsl,mpc8314-gpio", },
|
||||
{ .compatible = "fsl,mpc8349-gpio", },
|
||||
{ .compatible = "fsl,mpc8572-gpio", .data = &mpc8572_gpio_devtype, },
|
||||
{ .compatible = "fsl,mpc8610-gpio", },
|
||||
|
|
|
|||
|
|
@ -1088,7 +1088,8 @@ static int pca953x_probe(struct i2c_client *client)
|
|||
*/
|
||||
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(reset_gpio))
|
||||
return PTR_ERR(reset_gpio);
|
||||
return dev_err_probe(dev, PTR_ERR(reset_gpio),
|
||||
"Failed to get reset gpio\n");
|
||||
}
|
||||
|
||||
chip->client = client;
|
||||
|
|
|
|||
|
|
@ -262,6 +262,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config
|
|||
chip->label = config->label ?: dev_name(config->parent);
|
||||
chip->can_sleep = regmap_might_sleep(config->regmap);
|
||||
|
||||
chip->request = gpiochip_generic_request;
|
||||
chip->free = gpiochip_generic_free;
|
||||
chip->get = gpio_regmap_get;
|
||||
if (gpio->reg_set_base && gpio->reg_clr_base)
|
||||
chip->set = gpio_regmap_set_with_clear;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
#define TPS65219_GPIO0_DIR_MASK BIT(3)
|
||||
#define TPS65219_GPIO0_OFFSET 2
|
||||
#define TPS65219_GPIO0_IDX 0
|
||||
#define TPS65219_GPIO_DIR_IN 1
|
||||
#define TPS65219_GPIO_DIR_OUT 0
|
||||
|
||||
struct tps65219_gpio {
|
||||
struct gpio_chip gpio_chip;
|
||||
|
|
@ -61,7 +59,7 @@ static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
|||
* status bit.
|
||||
*/
|
||||
|
||||
if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_OUT)
|
||||
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT)
|
||||
return -ENOTSUPP;
|
||||
|
||||
return ret;
|
||||
|
|
@ -124,10 +122,10 @@ static int tps65219_gpio_direction_input(struct gpio_chip *gc, unsigned int offs
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_IN)
|
||||
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_IN)
|
||||
return 0;
|
||||
|
||||
return tps65219_gpio_change_direction(gc, offset, TPS65219_GPIO_DIR_IN);
|
||||
return tps65219_gpio_change_direction(gc, offset, GPIO_LINE_DIRECTION_IN);
|
||||
}
|
||||
|
||||
static int tps65219_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
|
|
@ -136,10 +134,10 @@ static int tps65219_gpio_direction_output(struct gpio_chip *gc, unsigned int off
|
|||
if (offset != TPS65219_GPIO0_IDX)
|
||||
return 0;
|
||||
|
||||
if (tps65219_gpio_get_direction(gc, offset) == TPS65219_GPIO_DIR_OUT)
|
||||
if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT)
|
||||
return 0;
|
||||
|
||||
return tps65219_gpio_change_direction(gc, offset, TPS65219_GPIO_DIR_OUT);
|
||||
return tps65219_gpio_change_direction(gc, offset, GPIO_LINE_DIRECTION_OUT);
|
||||
}
|
||||
|
||||
static const struct gpio_chip tps65219_template_chip = {
|
||||
|
|
|
|||
|
|
@ -29,18 +29,22 @@
|
|||
#define TQMX86_GPIIC 3 /* GPI Interrupt Configuration Register */
|
||||
#define TQMX86_GPIIS 4 /* GPI Interrupt Status Register */
|
||||
|
||||
#define TQMX86_GPII_NONE 0
|
||||
#define TQMX86_GPII_FALLING BIT(0)
|
||||
#define TQMX86_GPII_RISING BIT(1)
|
||||
/* Stored in irq_type as a trigger type, but not actually valid as a register
|
||||
* value, so the name doesn't use "GPII"
|
||||
/*
|
||||
* NONE, FALLING and RISING use the same bit patterns that can be programmed to
|
||||
* the GPII register (after passing them to the TQMX86_GPII_ macros to shift
|
||||
* them to the right position)
|
||||
*/
|
||||
#define TQMX86_INT_BOTH (BIT(0) | BIT(1))
|
||||
#define TQMX86_GPII_MASK (BIT(0) | BIT(1))
|
||||
#define TQMX86_GPII_BITS 2
|
||||
#define TQMX86_INT_TRIG_NONE 0
|
||||
#define TQMX86_INT_TRIG_FALLING BIT(0)
|
||||
#define TQMX86_INT_TRIG_RISING BIT(1)
|
||||
#define TQMX86_INT_TRIG_BOTH (BIT(0) | BIT(1))
|
||||
#define TQMX86_INT_TRIG_MASK (BIT(0) | BIT(1))
|
||||
/* Stored in irq_type with GPII bits */
|
||||
#define TQMX86_INT_UNMASKED BIT(2)
|
||||
|
||||
#define TQMX86_GPIIC_CONFIG(i, v) ((v) << (2 * (i)))
|
||||
#define TQMX86_GPIIC_MASK(i) TQMX86_GPIIC_CONFIG(i, TQMX86_INT_TRIG_MASK)
|
||||
|
||||
struct tqmx86_gpio_data {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *io_base;
|
||||
|
|
@ -48,7 +52,7 @@ struct tqmx86_gpio_data {
|
|||
/* Lock must be held for accessing output and irq_type fields */
|
||||
raw_spinlock_t spinlock;
|
||||
DECLARE_BITMAP(output, TQMX86_NGPIO);
|
||||
u8 irq_type[TQMX86_NGPI];
|
||||
u8 irq_type[TQMX86_NGPIO];
|
||||
};
|
||||
|
||||
static u8 tqmx86_gpio_read(struct tqmx86_gpio_data *gd, unsigned int reg)
|
||||
|
|
@ -62,6 +66,18 @@ static void tqmx86_gpio_write(struct tqmx86_gpio_data *gd, u8 val,
|
|||
iowrite8(val, gd->io_base + reg);
|
||||
}
|
||||
|
||||
static void tqmx86_gpio_clrsetbits(struct tqmx86_gpio_data *gpio,
|
||||
u8 clr, u8 set, unsigned int reg)
|
||||
__must_hold(&gpio->spinlock)
|
||||
{
|
||||
u8 val = tqmx86_gpio_read(gpio, reg);
|
||||
|
||||
val &= ~clr;
|
||||
val |= set;
|
||||
|
||||
tqmx86_gpio_write(gpio, val, reg);
|
||||
}
|
||||
|
||||
static int tqmx86_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
|
||||
|
|
@ -69,127 +85,137 @@ static int tqmx86_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
|||
return !!(tqmx86_gpio_read(gpio, TQMX86_GPIOD) & BIT(offset));
|
||||
}
|
||||
|
||||
static void _tqmx86_gpio_set(struct tqmx86_gpio_data *gpio, unsigned int offset,
|
||||
int value)
|
||||
__must_hold(&gpio->spinlock)
|
||||
{
|
||||
__assign_bit(offset, gpio->output, value);
|
||||
tqmx86_gpio_write(gpio, bitmap_get_value8(gpio->output, 0), TQMX86_GPIOD);
|
||||
}
|
||||
|
||||
static void tqmx86_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&gpio->spinlock, flags);
|
||||
__assign_bit(offset, gpio->output, value);
|
||||
tqmx86_gpio_write(gpio, bitmap_get_value8(gpio->output, 0), TQMX86_GPIOD);
|
||||
raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
|
||||
guard(raw_spinlock_irqsave)(&gpio->spinlock);
|
||||
|
||||
_tqmx86_gpio_set(gpio, offset, value);
|
||||
}
|
||||
|
||||
static int tqmx86_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
/* Direction cannot be changed. Validate is an input. */
|
||||
if (BIT(offset) & TQMX86_DIR_INPUT_MASK)
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
|
||||
|
||||
guard(raw_spinlock_irqsave)(&gpio->spinlock);
|
||||
|
||||
tqmx86_gpio_clrsetbits(gpio, BIT(offset), 0, TQMX86_GPIODD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tqmx86_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
/* Direction cannot be changed, validate is an output */
|
||||
if (BIT(offset) & TQMX86_DIR_INPUT_MASK)
|
||||
return -EINVAL;
|
||||
struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
|
||||
|
||||
guard(raw_spinlock_irqsave)(&gpio->spinlock);
|
||||
|
||||
_tqmx86_gpio_set(gpio, offset, value);
|
||||
tqmx86_gpio_clrsetbits(gpio, 0, BIT(offset), TQMX86_GPIODD);
|
||||
|
||||
tqmx86_gpio_set(chip, offset, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tqmx86_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (TQMX86_DIR_INPUT_MASK & BIT(offset))
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
|
||||
u8 val;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
val = tqmx86_gpio_read(gpio, TQMX86_GPIODD);
|
||||
|
||||
if (val & BIT(offset))
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static void tqmx86_gpio_irq_config(struct tqmx86_gpio_data *gpio, int offset)
|
||||
static void tqmx86_gpio_irq_config(struct tqmx86_gpio_data *gpio, int hwirq)
|
||||
__must_hold(&gpio->spinlock)
|
||||
{
|
||||
u8 type = TQMX86_GPII_NONE, gpiic;
|
||||
u8 type = TQMX86_INT_TRIG_NONE;
|
||||
int gpiic_irq = hwirq - TQMX86_NGPO;
|
||||
|
||||
if (gpio->irq_type[offset] & TQMX86_INT_UNMASKED) {
|
||||
type = gpio->irq_type[offset] & TQMX86_GPII_MASK;
|
||||
if (gpio->irq_type[hwirq] & TQMX86_INT_UNMASKED) {
|
||||
type = gpio->irq_type[hwirq] & TQMX86_INT_TRIG_MASK;
|
||||
|
||||
if (type == TQMX86_INT_BOTH)
|
||||
type = tqmx86_gpio_get(&gpio->chip, offset + TQMX86_NGPO)
|
||||
? TQMX86_GPII_FALLING
|
||||
: TQMX86_GPII_RISING;
|
||||
if (type == TQMX86_INT_TRIG_BOTH)
|
||||
type = tqmx86_gpio_get(&gpio->chip, hwirq)
|
||||
? TQMX86_INT_TRIG_FALLING
|
||||
: TQMX86_INT_TRIG_RISING;
|
||||
}
|
||||
|
||||
gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);
|
||||
gpiic &= ~(TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS));
|
||||
gpiic |= type << (offset * TQMX86_GPII_BITS);
|
||||
tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC);
|
||||
tqmx86_gpio_clrsetbits(gpio,
|
||||
TQMX86_GPIIC_MASK(gpiic_irq),
|
||||
TQMX86_GPIIC_CONFIG(gpiic_irq, type),
|
||||
TQMX86_GPIIC);
|
||||
}
|
||||
|
||||
static void tqmx86_gpio_irq_mask(struct irq_data *data)
|
||||
{
|
||||
unsigned int offset = (data->hwirq - TQMX86_NGPO);
|
||||
struct tqmx86_gpio_data *gpio = gpiochip_get_data(
|
||||
irq_data_get_irq_chip_data(data));
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&gpio->spinlock, flags);
|
||||
gpio->irq_type[offset] &= ~TQMX86_INT_UNMASKED;
|
||||
tqmx86_gpio_irq_config(gpio, offset);
|
||||
raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
|
||||
scoped_guard(raw_spinlock_irqsave, &gpio->spinlock) {
|
||||
gpio->irq_type[data->hwirq] &= ~TQMX86_INT_UNMASKED;
|
||||
tqmx86_gpio_irq_config(gpio, data->hwirq);
|
||||
}
|
||||
|
||||
gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(data));
|
||||
}
|
||||
|
||||
static void tqmx86_gpio_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
unsigned int offset = (data->hwirq - TQMX86_NGPO);
|
||||
struct tqmx86_gpio_data *gpio = gpiochip_get_data(
|
||||
irq_data_get_irq_chip_data(data));
|
||||
unsigned long flags;
|
||||
|
||||
gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(data));
|
||||
|
||||
raw_spin_lock_irqsave(&gpio->spinlock, flags);
|
||||
gpio->irq_type[offset] |= TQMX86_INT_UNMASKED;
|
||||
tqmx86_gpio_irq_config(gpio, offset);
|
||||
raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
|
||||
guard(raw_spinlock_irqsave)(&gpio->spinlock);
|
||||
|
||||
gpio->irq_type[data->hwirq] |= TQMX86_INT_UNMASKED;
|
||||
tqmx86_gpio_irq_config(gpio, data->hwirq);
|
||||
}
|
||||
|
||||
static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
struct tqmx86_gpio_data *gpio = gpiochip_get_data(
|
||||
irq_data_get_irq_chip_data(data));
|
||||
unsigned int offset = (data->hwirq - TQMX86_NGPO);
|
||||
unsigned int edge_type = type & IRQF_TRIGGER_MASK;
|
||||
unsigned long flags;
|
||||
u8 new_type;
|
||||
|
||||
switch (edge_type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
new_type = TQMX86_GPII_RISING;
|
||||
new_type = TQMX86_INT_TRIG_RISING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
new_type = TQMX86_GPII_FALLING;
|
||||
new_type = TQMX86_INT_TRIG_FALLING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
new_type = TQMX86_INT_BOTH;
|
||||
new_type = TQMX86_INT_TRIG_BOTH;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL; /* not supported */
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&gpio->spinlock, flags);
|
||||
gpio->irq_type[offset] &= ~TQMX86_GPII_MASK;
|
||||
gpio->irq_type[offset] |= new_type;
|
||||
tqmx86_gpio_irq_config(gpio, offset);
|
||||
raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
|
||||
guard(raw_spinlock_irqsave)(&gpio->spinlock);
|
||||
|
||||
gpio->irq_type[data->hwirq] &= ~TQMX86_INT_TRIG_MASK;
|
||||
gpio->irq_type[data->hwirq] |= new_type;
|
||||
tqmx86_gpio_irq_config(gpio, data->hwirq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -199,8 +225,8 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc)
|
|||
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
|
||||
struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
|
||||
struct irq_chip *irq_chip = irq_desc_get_chip(desc);
|
||||
unsigned long irq_bits, flags;
|
||||
int i;
|
||||
unsigned long irq_bits;
|
||||
int i, hwirq;
|
||||
u8 irq_status;
|
||||
|
||||
chained_irq_enter(irq_chip, desc);
|
||||
|
|
@ -210,32 +236,38 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc)
|
|||
|
||||
irq_bits = irq_status;
|
||||
|
||||
raw_spin_lock_irqsave(&gpio->spinlock, flags);
|
||||
for_each_set_bit(i, &irq_bits, TQMX86_NGPI) {
|
||||
/*
|
||||
* Edge-both triggers are implemented by flipping the edge
|
||||
* trigger after each interrupt, as the controller only supports
|
||||
* either rising or falling edge triggers, but not both.
|
||||
*
|
||||
* Internally, the TQMx86 GPIO controller has separate status
|
||||
* registers for rising and falling edge interrupts. GPIIC
|
||||
* configures which bits from which register are visible in the
|
||||
* interrupt status register GPIIS and defines what triggers the
|
||||
* parent IRQ line. Writing to GPIIS always clears both rising
|
||||
* and falling interrupt flags internally, regardless of the
|
||||
* currently configured trigger.
|
||||
*
|
||||
* In consequence, we can cleanly implement the edge-both
|
||||
* trigger in software by first clearing the interrupt and then
|
||||
* setting the new trigger based on the current GPIO input in
|
||||
* tqmx86_gpio_irq_config() - even if an edge arrives between
|
||||
* reading the input and setting the trigger, we will have a new
|
||||
* interrupt pending.
|
||||
*/
|
||||
if ((gpio->irq_type[i] & TQMX86_GPII_MASK) == TQMX86_INT_BOTH)
|
||||
tqmx86_gpio_irq_config(gpio, i);
|
||||
scoped_guard(raw_spinlock_irqsave, &gpio->spinlock) {
|
||||
for_each_set_bit(i, &irq_bits, TQMX86_NGPI) {
|
||||
hwirq = i + TQMX86_NGPO;
|
||||
|
||||
/*
|
||||
* Edge-both triggers are implemented by flipping the
|
||||
* edge trigger after each interrupt, as the controller
|
||||
* only supports either rising or falling edge triggers,
|
||||
* but not both.
|
||||
*
|
||||
* Internally, the TQMx86 GPIO controller has separate
|
||||
* status registers for rising and falling edge
|
||||
* interrupts. GPIIC configures which bits from which
|
||||
* register are visible in the interrupt status register
|
||||
* GPIIS and defines what triggers the parent IRQ line.
|
||||
* Writing to GPIIS always clears both rising and
|
||||
* falling interrupt flags internally, regardless of the
|
||||
* currently configured trigger.
|
||||
*
|
||||
* In consequence, we can cleanly implement the
|
||||
* edge-both trigger in software by first clearing the
|
||||
* interrupt and then setting the new trigger based on
|
||||
* the current GPIO input in tqmx86_gpio_irq_config() -
|
||||
* even if an edge arrives between reading the input and
|
||||
* setting the trigger, we will have a new interrupt
|
||||
* pending.
|
||||
*/
|
||||
if ((gpio->irq_type[hwirq] & TQMX86_INT_TRIG_MASK) ==
|
||||
TQMX86_INT_TRIG_BOTH)
|
||||
tqmx86_gpio_irq_config(gpio, hwirq);
|
||||
}
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
|
||||
|
||||
for_each_set_bit(i, &irq_bits, TQMX86_NGPI)
|
||||
generic_handle_domain_irq(gpio->chip.irq.domain,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct twl6040 *twl6040 = dev_get_drvdata(chip->parent->parent);
|
||||
struct twl6040 *twl6040 = gpiochip_get_data(chip);
|
||||
int ret = 0;
|
||||
|
||||
ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL);
|
||||
|
|
@ -46,7 +46,7 @@ static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset,
|
|||
|
||||
static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct twl6040 *twl6040 = dev_get_drvdata(chip->parent->parent);
|
||||
struct twl6040 *twl6040 = gpiochip_get_data(chip);
|
||||
int ret;
|
||||
u8 gpoctl;
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ static int gpo_twl6040_probe(struct platform_device *pdev)
|
|||
|
||||
twl6040gpo_chip.parent = &pdev->dev;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &twl6040gpo_chip, NULL);
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &twl6040gpo_chip, twl6040);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
|
||||
twl6040gpo_chip.ngpio = 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user