Skip to content

Commit 90dd7de

Browse files
tq-schiffermBartosz Golaszewski
authored andcommitted
gpio: tqmx86: fix broken IRQ_TYPE_EDGE_BOTH interrupt type
The TQMx86 GPIO controller only supports falling and rising edge triggers, but not both. Fix this by implementing a software both-edge mode that toggles the edge type after every interrupt. Fixes: b868db9 ("gpio: tqmx86: Add GPIO from for this IO controller") Co-developed-by: Gregor Herburger <gregor.herburger@tq-group.com> Signed-off-by: Gregor Herburger <gregor.herburger@tq-group.com> Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com> Link: https://lore.kernel.org/r/515324f0491c4d44f4ef49f170354aca002d81ef.1717063994.git.matthias.schiffer@ew.tq-group.com Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
1 parent 08af509 commit 90dd7de

File tree

1 file changed

+42
-4
lines changed

1 file changed

+42
-4
lines changed

drivers/gpio/gpio-tqmx86.c

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
#define TQMX86_GPII_NONE 0
3333
#define TQMX86_GPII_FALLING BIT(0)
3434
#define TQMX86_GPII_RISING BIT(1)
35+
/* Stored in irq_type as a trigger type, but not actually valid as a register
36+
* value, so the name doesn't use "GPII"
37+
*/
38+
#define TQMX86_INT_BOTH (BIT(0) | BIT(1))
3539
#define TQMX86_GPII_MASK (BIT(0) | BIT(1))
3640
#define TQMX86_GPII_BITS 2
3741
/* Stored in irq_type with GPII bits */
@@ -113,9 +117,15 @@ static void tqmx86_gpio_irq_config(struct tqmx86_gpio_data *gpio, int offset)
113117
{
114118
u8 type = TQMX86_GPII_NONE, gpiic;
115119

116-
if (gpio->irq_type[offset] & TQMX86_INT_UNMASKED)
120+
if (gpio->irq_type[offset] & TQMX86_INT_UNMASKED) {
117121
type = gpio->irq_type[offset] & TQMX86_GPII_MASK;
118122

123+
if (type == TQMX86_INT_BOTH)
124+
type = tqmx86_gpio_get(&gpio->chip, offset + TQMX86_NGPO)
125+
? TQMX86_GPII_FALLING
126+
: TQMX86_GPII_RISING;
127+
}
128+
119129
gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);
120130
gpiic &= ~(TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS));
121131
gpiic |= type << (offset * TQMX86_GPII_BITS);
@@ -169,7 +179,7 @@ static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type)
169179
new_type = TQMX86_GPII_FALLING;
170180
break;
171181
case IRQ_TYPE_EDGE_BOTH:
172-
new_type = TQMX86_GPII_FALLING | TQMX86_GPII_RISING;
182+
new_type = TQMX86_INT_BOTH;
173183
break;
174184
default:
175185
return -EINVAL; /* not supported */
@@ -189,8 +199,8 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc)
189199
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
190200
struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);
191201
struct irq_chip *irq_chip = irq_desc_get_chip(desc);
192-
unsigned long irq_bits;
193-
int i = 0;
202+
unsigned long irq_bits, flags;
203+
int i;
194204
u8 irq_status;
195205

196206
chained_irq_enter(irq_chip, desc);
@@ -199,6 +209,34 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc)
199209
tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);
200210

201211
irq_bits = irq_status;
212+
213+
raw_spin_lock_irqsave(&gpio->spinlock, flags);
214+
for_each_set_bit(i, &irq_bits, TQMX86_NGPI) {
215+
/*
216+
* Edge-both triggers are implemented by flipping the edge
217+
* trigger after each interrupt, as the controller only supports
218+
* either rising or falling edge triggers, but not both.
219+
*
220+
* Internally, the TQMx86 GPIO controller has separate status
221+
* registers for rising and falling edge interrupts. GPIIC
222+
* configures which bits from which register are visible in the
223+
* interrupt status register GPIIS and defines what triggers the
224+
* parent IRQ line. Writing to GPIIS always clears both rising
225+
* and falling interrupt flags internally, regardless of the
226+
* currently configured trigger.
227+
*
228+
* In consequence, we can cleanly implement the edge-both
229+
* trigger in software by first clearing the interrupt and then
230+
* setting the new trigger based on the current GPIO input in
231+
* tqmx86_gpio_irq_config() - even if an edge arrives between
232+
* reading the input and setting the trigger, we will have a new
233+
* interrupt pending.
234+
*/
235+
if ((gpio->irq_type[i] & TQMX86_GPII_MASK) == TQMX86_INT_BOTH)
236+
tqmx86_gpio_irq_config(gpio, i);
237+
}
238+
raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
239+
202240
for_each_set_bit(i, &irq_bits, TQMX86_NGPI)
203241
generic_handle_domain_irq(gpio->chip.irq.domain,
204242
i + TQMX86_NGPO);

0 commit comments

Comments
 (0)