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

MIPS: Alchemy: Threaded carddetect irqs for devboards

This introduces threaded carddetect irqs for the db1200/db1300 boards.
Main benefit is that the broken insertion/ejection interrupt pairs
can now be better supported and debounced in software.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/15287/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Manuel Lauss and committed by
Ralf Baechle
cc10815e 60d5973c

+72 -56
+36 -28
arch/mips/alchemy/devboards/db1200.c
··· 344 344 345 345 /* SD carddetects: they're supposed to be edge-triggered, but ack 346 346 * doesn't seem to work (CPLD Rev 2). Instead, the screaming one 347 - * is disabled and its counterpart enabled. The 500ms timeout is 348 - * because the carddetect isn't debounced in hardware. 347 + * is disabled and its counterpart enabled. The 200ms timeout is 348 + * because the carddetect usually triggers twice, after debounce. 349 349 */ 350 350 static irqreturn_t db1200_mmc_cd(int irq, void *ptr) 351 351 { 352 - void(*mmc_cd)(struct mmc_host *, unsigned long); 352 + disable_irq_nosync(irq); 353 + return IRQ_WAKE_THREAD; 354 + } 353 355 354 - if (irq == DB1200_SD0_INSERT_INT) { 355 - disable_irq_nosync(DB1200_SD0_INSERT_INT); 356 - enable_irq(DB1200_SD0_EJECT_INT); 357 - } else { 358 - disable_irq_nosync(DB1200_SD0_EJECT_INT); 359 - enable_irq(DB1200_SD0_INSERT_INT); 360 - } 356 + static irqreturn_t db1200_mmc_cdfn(int irq, void *ptr) 357 + { 358 + void (*mmc_cd)(struct mmc_host *, unsigned long); 361 359 362 360 /* link against CONFIG_MMC=m */ 363 361 mmc_cd = symbol_get(mmc_detect_change); 364 362 if (mmc_cd) { 365 - mmc_cd(ptr, msecs_to_jiffies(500)); 363 + mmc_cd(ptr, msecs_to_jiffies(200)); 366 364 symbol_put(mmc_detect_change); 367 365 } 366 + 367 + msleep(100); /* debounce */ 368 + if (irq == DB1200_SD0_INSERT_INT) 369 + enable_irq(DB1200_SD0_EJECT_INT); 370 + else 371 + enable_irq(DB1200_SD0_INSERT_INT); 368 372 369 373 return IRQ_HANDLED; 370 374 } ··· 378 374 int ret; 379 375 380 376 if (en) { 381 - ret = request_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd, 382 - 0, "sd_insert", mmc_host); 377 + ret = request_threaded_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd, 378 + db1200_mmc_cdfn, 0, "sd_insert", mmc_host); 383 379 if (ret) 384 380 goto out; 385 381 386 - ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd, 387 - 0, "sd_eject", mmc_host); 382 + ret = request_threaded_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd, 383 + db1200_mmc_cdfn, 0, "sd_eject", mmc_host); 388 384 if (ret) { 389 385 free_irq(DB1200_SD0_INSERT_INT, mmc_host); 390 386 goto out; ··· 440 436 441 437 static irqreturn_t pb1200_mmc1_cd(int irq, void *ptr) 442 438 { 443 - void(*mmc_cd)(struct mmc_host *, unsigned long); 439 + disable_irq_nosync(irq); 440 + return IRQ_WAKE_THREAD; 441 + } 444 442 445 - if (irq == PB1200_SD1_INSERT_INT) { 446 - disable_irq_nosync(PB1200_SD1_INSERT_INT); 447 - enable_irq(PB1200_SD1_EJECT_INT); 448 - } else { 449 - disable_irq_nosync(PB1200_SD1_EJECT_INT); 450 - enable_irq(PB1200_SD1_INSERT_INT); 451 - } 443 + static irqreturn_t pb1200_mmc1_cdfn(int irq, void *ptr) 444 + { 445 + void (*mmc_cd)(struct mmc_host *, unsigned long); 452 446 453 447 /* link against CONFIG_MMC=m */ 454 448 mmc_cd = symbol_get(mmc_detect_change); 455 449 if (mmc_cd) { 456 - mmc_cd(ptr, msecs_to_jiffies(500)); 450 + mmc_cd(ptr, msecs_to_jiffies(200)); 457 451 symbol_put(mmc_detect_change); 458 452 } 453 + 454 + msleep(100); /* debounce */ 455 + if (irq == PB1200_SD1_INSERT_INT) 456 + enable_irq(PB1200_SD1_EJECT_INT); 457 + else 458 + enable_irq(PB1200_SD1_INSERT_INT); 459 459 460 460 return IRQ_HANDLED; 461 461 } ··· 469 461 int ret; 470 462 471 463 if (en) { 472 - ret = request_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, 0, 473 - "sd1_insert", mmc_host); 464 + ret = request_threaded_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, 465 + pb1200_mmc1_cdfn, 0, "sd1_insert", mmc_host); 474 466 if (ret) 475 467 goto out; 476 468 477 - ret = request_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, 0, 478 - "sd1_eject", mmc_host); 469 + ret = request_threaded_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, 470 + pb1200_mmc1_cdfn, 0, "sd1_eject", mmc_host); 479 471 if (ret) { 480 472 free_irq(PB1200_SD1_INSERT_INT, mmc_host); 481 473 goto out;
+17 -14
arch/mips/alchemy/devboards/db1300.c
··· 450 450 451 451 static irqreturn_t db1300_mmc_cd(int irq, void *ptr) 452 452 { 453 - void(*mmc_cd)(struct mmc_host *, unsigned long); 453 + disable_irq_nosync(irq); 454 + return IRQ_WAKE_THREAD; 455 + } 454 456 455 - /* disable the one currently screaming. No other way to shut it up */ 456 - if (irq == DB1300_SD1_INSERT_INT) { 457 - disable_irq_nosync(DB1300_SD1_INSERT_INT); 458 - enable_irq(DB1300_SD1_EJECT_INT); 459 - } else { 460 - disable_irq_nosync(DB1300_SD1_EJECT_INT); 461 - enable_irq(DB1300_SD1_INSERT_INT); 462 - } 457 + static irqreturn_t db1300_mmc_cdfn(int irq, void *ptr) 458 + { 459 + void (*mmc_cd)(struct mmc_host *, unsigned long); 463 460 464 461 /* link against CONFIG_MMC=m. We can only be called once MMC core has 465 462 * initialized the controller, so symbol_get() should always succeed. 466 463 */ 467 464 mmc_cd = symbol_get(mmc_detect_change); 468 - mmc_cd(ptr, msecs_to_jiffies(500)); 465 + mmc_cd(ptr, msecs_to_jiffies(200)); 469 466 symbol_put(mmc_detect_change); 467 + 468 + msleep(100); /* debounce */ 469 + if (irq == DB1300_SD1_INSERT_INT) 470 + enable_irq(DB1300_SD1_EJECT_INT); 471 + else 472 + enable_irq(DB1300_SD1_INSERT_INT); 470 473 471 474 return IRQ_HANDLED; 472 475 } ··· 490 487 int ret; 491 488 492 489 if (en) { 493 - ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0, 494 - "sd_insert", mmc_host); 490 + ret = request_threaded_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 491 + db1300_mmc_cdfn, 0, "sd_insert", mmc_host); 495 492 if (ret) 496 493 goto out; 497 494 498 - ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0, 499 - "sd_eject", mmc_host); 495 + ret = request_threaded_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 496 + db1300_mmc_cdfn, 0, "sd_eject", mmc_host); 500 497 if (ret) { 501 498 free_irq(DB1300_SD1_INSERT_INT, mmc_host); 502 499 goto out;
+19 -14
drivers/pcmcia/db1xxx_ss.c
··· 131 131 return IRQ_HANDLED; 132 132 } 133 133 134 + /* Db/Pb1200 have separate per-socket insertion and ejection 135 + * interrupts which stay asserted as long as the card is 136 + * inserted/missing. The one which caused us to be called 137 + * needs to be disabled and the other one enabled. 138 + */ 134 139 static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data) 140 + { 141 + disable_irq_nosync(irq); 142 + return IRQ_WAKE_THREAD; 143 + } 144 + 145 + static irqreturn_t db1200_pcmcia_cdirq_fn(int irq, void *data) 135 146 { 136 147 struct db1x_pcmcia_sock *sock = data; 137 148 138 - /* Db/Pb1200 have separate per-socket insertion and ejection 139 - * interrupts which stay asserted as long as the card is 140 - * inserted/missing. The one which caused us to be called 141 - * needs to be disabled and the other one enabled. 142 - */ 143 - if (irq == sock->insert_irq) { 144 - disable_irq_nosync(sock->insert_irq); 149 + /* Wait a bit for the signals to stop bouncing. */ 150 + msleep(100); 151 + if (irq == sock->insert_irq) 145 152 enable_irq(sock->eject_irq); 146 - } else { 147 - disable_irq_nosync(sock->eject_irq); 153 + else 148 154 enable_irq(sock->insert_irq); 149 - } 150 155 151 156 pcmcia_parse_events(&sock->socket, SS_DETECT); 152 157 ··· 177 172 */ 178 173 if ((sock->board_type == BOARD_TYPE_DB1200) || 179 174 (sock->board_type == BOARD_TYPE_DB1300)) { 180 - ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq, 181 - 0, "pcmcia_insert", sock); 175 + ret = request_threaded_irq(sock->insert_irq, db1200_pcmcia_cdirq, 176 + db1200_pcmcia_cdirq_fn, 0, "pcmcia_insert", sock); 182 177 if (ret) 183 178 goto out1; 184 179 185 - ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq, 186 - 0, "pcmcia_eject", sock); 180 + ret = request_threaded_irq(sock->eject_irq, db1200_pcmcia_cdirq, 181 + db1200_pcmcia_cdirq_fn, 0, "pcmcia_eject", sock); 187 182 if (ret) { 188 183 free_irq(sock->insert_irq, sock); 189 184 goto out1;