Commit cc10815e authored by Manuel Lauss's avatar Manuel Lauss Committed by Ralf Baechle

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: default avatarManuel 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: default avatarRalf Baechle <ralf@linux-mips.org>
parent 60d5973c
...@@ -344,28 +344,32 @@ static struct platform_device db1200_ide_dev = { ...@@ -344,28 +344,32 @@ static struct platform_device db1200_ide_dev = {
/* SD carddetects: they're supposed to be edge-triggered, but ack /* SD carddetects: they're supposed to be edge-triggered, but ack
* doesn't seem to work (CPLD Rev 2). Instead, the screaming one * doesn't seem to work (CPLD Rev 2). Instead, the screaming one
* is disabled and its counterpart enabled. The 500ms timeout is * is disabled and its counterpart enabled. The 200ms timeout is
* because the carddetect isn't debounced in hardware. * because the carddetect usually triggers twice, after debounce.
*/ */
static irqreturn_t db1200_mmc_cd(int irq, void *ptr) static irqreturn_t db1200_mmc_cd(int irq, void *ptr)
{ {
void(*mmc_cd)(struct mmc_host *, unsigned long); disable_irq_nosync(irq);
return IRQ_WAKE_THREAD;
}
if (irq == DB1200_SD0_INSERT_INT) { static irqreturn_t db1200_mmc_cdfn(int irq, void *ptr)
disable_irq_nosync(DB1200_SD0_INSERT_INT); {
enable_irq(DB1200_SD0_EJECT_INT); void (*mmc_cd)(struct mmc_host *, unsigned long);
} else {
disable_irq_nosync(DB1200_SD0_EJECT_INT);
enable_irq(DB1200_SD0_INSERT_INT);
}
/* link against CONFIG_MMC=m */ /* link against CONFIG_MMC=m */
mmc_cd = symbol_get(mmc_detect_change); mmc_cd = symbol_get(mmc_detect_change);
if (mmc_cd) { if (mmc_cd) {
mmc_cd(ptr, msecs_to_jiffies(500)); mmc_cd(ptr, msecs_to_jiffies(200));
symbol_put(mmc_detect_change); symbol_put(mmc_detect_change);
} }
msleep(100); /* debounce */
if (irq == DB1200_SD0_INSERT_INT)
enable_irq(DB1200_SD0_EJECT_INT);
else
enable_irq(DB1200_SD0_INSERT_INT);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -374,13 +378,13 @@ static int db1200_mmc_cd_setup(void *mmc_host, int en) ...@@ -374,13 +378,13 @@ static int db1200_mmc_cd_setup(void *mmc_host, int en)
int ret; int ret;
if (en) { if (en) {
ret = request_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd, ret = request_threaded_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd,
0, "sd_insert", mmc_host); db1200_mmc_cdfn, 0, "sd_insert", mmc_host);
if (ret) if (ret)
goto out; goto out;
ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd, ret = request_threaded_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd,
0, "sd_eject", mmc_host); db1200_mmc_cdfn, 0, "sd_eject", mmc_host);
if (ret) { if (ret) {
free_irq(DB1200_SD0_INSERT_INT, mmc_host); free_irq(DB1200_SD0_INSERT_INT, mmc_host);
goto out; goto out;
...@@ -436,23 +440,27 @@ static struct led_classdev db1200_mmc_led = { ...@@ -436,23 +440,27 @@ static struct led_classdev db1200_mmc_led = {
static irqreturn_t pb1200_mmc1_cd(int irq, void *ptr) static irqreturn_t pb1200_mmc1_cd(int irq, void *ptr)
{ {
void(*mmc_cd)(struct mmc_host *, unsigned long); disable_irq_nosync(irq);
return IRQ_WAKE_THREAD;
}
if (irq == PB1200_SD1_INSERT_INT) { static irqreturn_t pb1200_mmc1_cdfn(int irq, void *ptr)
disable_irq_nosync(PB1200_SD1_INSERT_INT); {
enable_irq(PB1200_SD1_EJECT_INT); void (*mmc_cd)(struct mmc_host *, unsigned long);
} else {
disable_irq_nosync(PB1200_SD1_EJECT_INT);
enable_irq(PB1200_SD1_INSERT_INT);
}
/* link against CONFIG_MMC=m */ /* link against CONFIG_MMC=m */
mmc_cd = symbol_get(mmc_detect_change); mmc_cd = symbol_get(mmc_detect_change);
if (mmc_cd) { if (mmc_cd) {
mmc_cd(ptr, msecs_to_jiffies(500)); mmc_cd(ptr, msecs_to_jiffies(200));
symbol_put(mmc_detect_change); symbol_put(mmc_detect_change);
} }
msleep(100); /* debounce */
if (irq == PB1200_SD1_INSERT_INT)
enable_irq(PB1200_SD1_EJECT_INT);
else
enable_irq(PB1200_SD1_INSERT_INT);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -461,13 +469,13 @@ static int pb1200_mmc1_cd_setup(void *mmc_host, int en) ...@@ -461,13 +469,13 @@ static int pb1200_mmc1_cd_setup(void *mmc_host, int en)
int ret; int ret;
if (en) { if (en) {
ret = request_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, 0, ret = request_threaded_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd,
"sd1_insert", mmc_host); pb1200_mmc1_cdfn, 0, "sd1_insert", mmc_host);
if (ret) if (ret)
goto out; goto out;
ret = request_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, 0, ret = request_threaded_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd,
"sd1_eject", mmc_host); pb1200_mmc1_cdfn, 0, "sd1_eject", mmc_host);
if (ret) { if (ret) {
free_irq(PB1200_SD1_INSERT_INT, mmc_host); free_irq(PB1200_SD1_INSERT_INT, mmc_host);
goto out; goto out;
......
...@@ -450,24 +450,27 @@ static struct platform_device db1300_ide_dev = { ...@@ -450,24 +450,27 @@ static struct platform_device db1300_ide_dev = {
static irqreturn_t db1300_mmc_cd(int irq, void *ptr) static irqreturn_t db1300_mmc_cd(int irq, void *ptr)
{ {
void(*mmc_cd)(struct mmc_host *, unsigned long); disable_irq_nosync(irq);
return IRQ_WAKE_THREAD;
}
/* disable the one currently screaming. No other way to shut it up */ static irqreturn_t db1300_mmc_cdfn(int irq, void *ptr)
if (irq == DB1300_SD1_INSERT_INT) { {
disable_irq_nosync(DB1300_SD1_INSERT_INT); void (*mmc_cd)(struct mmc_host *, unsigned long);
enable_irq(DB1300_SD1_EJECT_INT);
} else {
disable_irq_nosync(DB1300_SD1_EJECT_INT);
enable_irq(DB1300_SD1_INSERT_INT);
}
/* link against CONFIG_MMC=m. We can only be called once MMC core has /* link against CONFIG_MMC=m. We can only be called once MMC core has
* initialized the controller, so symbol_get() should always succeed. * initialized the controller, so symbol_get() should always succeed.
*/ */
mmc_cd = symbol_get(mmc_detect_change); mmc_cd = symbol_get(mmc_detect_change);
mmc_cd(ptr, msecs_to_jiffies(500)); mmc_cd(ptr, msecs_to_jiffies(200));
symbol_put(mmc_detect_change); symbol_put(mmc_detect_change);
msleep(100); /* debounce */
if (irq == DB1300_SD1_INSERT_INT)
enable_irq(DB1300_SD1_EJECT_INT);
else
enable_irq(DB1300_SD1_INSERT_INT);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -487,13 +490,13 @@ static int db1300_mmc_cd_setup(void *mmc_host, int en) ...@@ -487,13 +490,13 @@ static int db1300_mmc_cd_setup(void *mmc_host, int en)
int ret; int ret;
if (en) { if (en) {
ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0, ret = request_threaded_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd,
"sd_insert", mmc_host); db1300_mmc_cdfn, 0, "sd_insert", mmc_host);
if (ret) if (ret)
goto out; goto out;
ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0, ret = request_threaded_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd,
"sd_eject", mmc_host); db1300_mmc_cdfn, 0, "sd_eject", mmc_host);
if (ret) { if (ret) {
free_irq(DB1300_SD1_INSERT_INT, mmc_host); free_irq(DB1300_SD1_INSERT_INT, mmc_host);
goto out; goto out;
......
...@@ -131,22 +131,27 @@ static irqreturn_t db1000_pcmcia_stschgirq(int irq, void *data) ...@@ -131,22 +131,27 @@ static irqreturn_t db1000_pcmcia_stschgirq(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/* Db/Pb1200 have separate per-socket insertion and ejection
* interrupts which stay asserted as long as the card is
* inserted/missing. The one which caused us to be called
* needs to be disabled and the other one enabled.
*/
static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data) static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data)
{
disable_irq_nosync(irq);
return IRQ_WAKE_THREAD;
}
static irqreturn_t db1200_pcmcia_cdirq_fn(int irq, void *data)
{ {
struct db1x_pcmcia_sock *sock = data; struct db1x_pcmcia_sock *sock = data;
/* Db/Pb1200 have separate per-socket insertion and ejection /* Wait a bit for the signals to stop bouncing. */
* interrupts which stay asserted as long as the card is msleep(100);
* inserted/missing. The one which caused us to be called if (irq == sock->insert_irq)
* needs to be disabled and the other one enabled.
*/
if (irq == sock->insert_irq) {
disable_irq_nosync(sock->insert_irq);
enable_irq(sock->eject_irq); enable_irq(sock->eject_irq);
} else { else
disable_irq_nosync(sock->eject_irq);
enable_irq(sock->insert_irq); enable_irq(sock->insert_irq);
}
pcmcia_parse_events(&sock->socket, SS_DETECT); pcmcia_parse_events(&sock->socket, SS_DETECT);
...@@ -172,13 +177,13 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock) ...@@ -172,13 +177,13 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
*/ */
if ((sock->board_type == BOARD_TYPE_DB1200) || if ((sock->board_type == BOARD_TYPE_DB1200) ||
(sock->board_type == BOARD_TYPE_DB1300)) { (sock->board_type == BOARD_TYPE_DB1300)) {
ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq, ret = request_threaded_irq(sock->insert_irq, db1200_pcmcia_cdirq,
0, "pcmcia_insert", sock); db1200_pcmcia_cdirq_fn, 0, "pcmcia_insert", sock);
if (ret) if (ret)
goto out1; goto out1;
ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq, ret = request_threaded_irq(sock->eject_irq, db1200_pcmcia_cdirq,
0, "pcmcia_eject", sock); db1200_pcmcia_cdirq_fn, 0, "pcmcia_eject", sock);
if (ret) { if (ret) {
free_irq(sock->insert_irq, sock); free_irq(sock->insert_irq, sock);
goto out1; goto out1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment