Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: adp5588.c: Switch to events system

Interupts were generated using GPIN interrupts of
ADP5588. These interrupts have two important limitations:
1. Interrupts can only be generated for either rising or
falling edges but not both.
2. Interrupts are reasserted as long as the interrupt condition
persists (i.e. high or low level on that GPIN). This generates
lots of interrupts unless the event is very short.

To overcome this, ADP5588 provides an event system which queues
up to 10 events in a buffer. GPIN events are queued whenever the
GPIN is asserted or deasserted. This makes it possible to support
generating GPIN interrupts for both edges and to generate only one
interrupt per state change.
Thus it is possible to chain the gpio-keys driver for some GPIOs.

Signed-off-by: Nikolaus Voss <nikolaus.voss@loewensteinmedical.de>
Acked-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Nikolaus Voss and committed by
Linus Walleij
5d643eda 9f22af11

+32 -53
+32 -53
drivers/gpio/gpio-adp5588.c
··· 36 36 struct mutex irq_lock; 37 37 uint8_t dat_out[3]; 38 38 uint8_t dir[3]; 39 - uint8_t int_lvl[3]; 39 + uint8_t int_lvl_low[3]; 40 + uint8_t int_lvl_high[3]; 40 41 uint8_t int_en[3]; 41 42 uint8_t irq_mask[3]; 42 - uint8_t irq_stat[3]; 43 43 uint8_t int_input_en[3]; 44 - uint8_t int_lvl_cached[3]; 45 44 }; 46 45 47 46 static int adp5588_gpio_read(struct i2c_client *client, u8 reg) ··· 179 180 mutex_unlock(&dev->lock); 180 181 } 181 182 182 - if (dev->int_lvl_cached[i] != dev->int_lvl[i]) { 183 - dev->int_lvl_cached[i] = dev->int_lvl[i]; 184 - adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + i, 185 - dev->int_lvl[i]); 186 - } 187 - 188 183 if (dev->int_en[i] ^ dev->irq_mask[i]) { 189 184 dev->int_en[i] = dev->irq_mask[i]; 190 - adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i, 185 + adp5588_gpio_write(dev->client, GPI_EM1 + i, 191 186 dev->int_en[i]); 192 187 } 193 188 } ··· 212 219 uint16_t gpio = d->hwirq; 213 220 unsigned bank, bit; 214 221 215 - if ((type & IRQ_TYPE_EDGE_BOTH)) { 216 - dev_err(&dev->client->dev, "irq %d: unsupported type %d\n", 217 - d->irq, type); 218 - return -EINVAL; 219 - } 220 - 221 222 bank = ADP5588_BANK(gpio); 222 223 bit = ADP5588_BIT(gpio); 223 224 224 - if (type & IRQ_TYPE_LEVEL_HIGH) 225 - dev->int_lvl[bank] |= bit; 226 - else if (type & IRQ_TYPE_LEVEL_LOW) 227 - dev->int_lvl[bank] &= ~bit; 228 - else 229 - return -EINVAL; 225 + dev->int_lvl_low[bank] &= ~bit; 226 + dev->int_lvl_high[bank] &= ~bit; 227 + 228 + if (type & IRQ_TYPE_EDGE_BOTH || type & IRQ_TYPE_LEVEL_HIGH) 229 + dev->int_lvl_high[bank] |= bit; 230 + 231 + if (type & IRQ_TYPE_EDGE_BOTH || type & IRQ_TYPE_LEVEL_LOW) 232 + dev->int_lvl_low[bank] |= bit; 230 233 231 234 dev->int_input_en[bank] |= bit; 232 235 ··· 238 249 .irq_set_type = adp5588_irq_set_type, 239 250 }; 240 251 241 - static int adp5588_gpio_read_intstat(struct i2c_client *client, u8 *buf) 242 - { 243 - int ret = i2c_smbus_read_i2c_block_data(client, GPIO_INT_STAT1, 3, buf); 244 - 245 - if (ret < 0) 246 - dev_err(&client->dev, "Read INT_STAT Error\n"); 247 - 248 - return ret; 249 - } 250 - 251 252 static irqreturn_t adp5588_irq_handler(int irq, void *devid) 252 253 { 253 254 struct adp5588_gpio *dev = devid; 254 - unsigned status, bank, bit, pending; 255 - int ret; 256 - status = adp5588_gpio_read(dev->client, INT_STAT); 255 + int status = adp5588_gpio_read(dev->client, INT_STAT); 257 256 258 - if (status & ADP5588_GPI_INT) { 259 - ret = adp5588_gpio_read_intstat(dev->client, dev->irq_stat); 260 - if (ret < 0) 261 - memset(dev->irq_stat, 0, ARRAY_SIZE(dev->irq_stat)); 257 + if (status & ADP5588_KE_INT) { 258 + int ev_cnt = adp5588_gpio_read(dev->client, KEY_LCK_EC_STAT); 262 259 263 - for (bank = 0, bit = 0; bank <= ADP5588_BANK(ADP5588_MAXGPIO); 264 - bank++, bit = 0) { 265 - pending = dev->irq_stat[bank] & dev->irq_mask[bank]; 260 + if (ev_cnt > 0) { 261 + int i; 266 262 267 - while (pending) { 268 - if (pending & (1 << bit)) { 269 - handle_nested_irq( 270 - irq_find_mapping( 271 - dev->gpio_chip.irq.domain, 272 - (bank << 3) + bit)); 273 - pending &= ~(1 << bit); 274 - } 275 - bit++; 263 + for (i = 0; i < (ev_cnt & ADP5588_KEC); i++) { 264 + int key = adp5588_gpio_read(dev->client, 265 + Key_EVENTA + i); 266 + /* GPIN events begin at 97, 267 + * bit 7 indicates logic level 268 + */ 269 + int gpio = (key & 0x7f) - 97; 270 + int lvl = key & (1 << 7); 271 + int bank = ADP5588_BANK(gpio); 272 + int bit = ADP5588_BIT(gpio); 273 + 274 + if ((lvl && dev->int_lvl_high[bank] & bit) || 275 + (!lvl && dev->int_lvl_low[bank] & bit)) 276 + handle_nested_irq(irq_find_mapping( 277 + dev->gpio_chip.irq.domain, gpio)); 276 278 } 277 279 } 278 280 } ··· 283 303 284 304 adp5588_gpio_write(client, CFG, ADP5588_AUTO_INC); 285 305 adp5588_gpio_write(client, INT_STAT, -1); /* status is W1C */ 286 - adp5588_gpio_read_intstat(client, dev->irq_stat); /* read to clear */ 287 306 288 307 mutex_init(&dev->irq_lock); 289 308 ··· 309 330 client->irq); 310 331 311 332 adp5588_gpio_write(client, CFG, 312 - ADP5588_AUTO_INC | ADP5588_INT_CFG | ADP5588_GPI_INT); 333 + ADP5588_AUTO_INC | ADP5588_INT_CFG | ADP5588_KE_IEN); 313 334 314 335 return 0; 315 336 }