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

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
Loading
Loading
Loading
Loading
+36 −28
Original line number Diff line number Diff line
@@ -344,28 +344,32 @@ static struct platform_device db1200_ide_dev = {

/* SD carddetects:  they're supposed to be edge-triggered, but ack
 * doesn't seem to work (CPLD Rev 2).  Instead, the screaming one
 * is disabled and its counterpart enabled.  The 500ms timeout is
 * because the carddetect isn't debounced in hardware.
 * is disabled and its counterpart enabled.  The 200ms timeout is
 * because the carddetect usually triggers twice, after debounce.
 */
static irqreturn_t db1200_mmc_cd(int irq, void *ptr)
{
	void(*mmc_cd)(struct mmc_host *, unsigned long);

	if (irq == DB1200_SD0_INSERT_INT) {
		disable_irq_nosync(DB1200_SD0_INSERT_INT);
		enable_irq(DB1200_SD0_EJECT_INT);
	} else {
		disable_irq_nosync(DB1200_SD0_EJECT_INT);
		enable_irq(DB1200_SD0_INSERT_INT);
	disable_irq_nosync(irq);
	return IRQ_WAKE_THREAD;
}

static irqreturn_t db1200_mmc_cdfn(int irq, void *ptr)
{
	void (*mmc_cd)(struct mmc_host *, unsigned long);

	/* link against CONFIG_MMC=m */
	mmc_cd = symbol_get(mmc_detect_change);
	if (mmc_cd) {
		mmc_cd(ptr, msecs_to_jiffies(500));
		mmc_cd(ptr, msecs_to_jiffies(200));
		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;
}

@@ -374,13 +378,13 @@ static int db1200_mmc_cd_setup(void *mmc_host, int en)
	int ret;

	if (en) {
		ret = request_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd,
				  0, "sd_insert", mmc_host);
		ret = request_threaded_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd,
				db1200_mmc_cdfn, 0, "sd_insert", mmc_host);
		if (ret)
			goto out;

		ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd,
				  0, "sd_eject", mmc_host);
		ret = request_threaded_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd,
				db1200_mmc_cdfn, 0, "sd_eject", mmc_host);
		if (ret) {
			free_irq(DB1200_SD0_INSERT_INT, mmc_host);
			goto out;
@@ -436,23 +440,27 @@ static struct led_classdev db1200_mmc_led = {

static irqreturn_t pb1200_mmc1_cd(int irq, void *ptr)
{
	void(*mmc_cd)(struct mmc_host *, unsigned long);

	if (irq == PB1200_SD1_INSERT_INT) {
		disable_irq_nosync(PB1200_SD1_INSERT_INT);
		enable_irq(PB1200_SD1_EJECT_INT);
	} else {
		disable_irq_nosync(PB1200_SD1_EJECT_INT);
		enable_irq(PB1200_SD1_INSERT_INT);
	disable_irq_nosync(irq);
	return IRQ_WAKE_THREAD;
}

static irqreturn_t pb1200_mmc1_cdfn(int irq, void *ptr)
{
	void (*mmc_cd)(struct mmc_host *, unsigned long);

	/* link against CONFIG_MMC=m */
	mmc_cd = symbol_get(mmc_detect_change);
	if (mmc_cd) {
		mmc_cd(ptr, msecs_to_jiffies(500));
		mmc_cd(ptr, msecs_to_jiffies(200));
		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;
}

@@ -461,13 +469,13 @@ static int pb1200_mmc1_cd_setup(void *mmc_host, int en)
	int ret;

	if (en) {
		ret = request_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, 0,
				  "sd1_insert", mmc_host);
		ret = request_threaded_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd,
				pb1200_mmc1_cdfn, 0, "sd1_insert", mmc_host);
		if (ret)
			goto out;

		ret = request_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, 0,
				  "sd1_eject", mmc_host);
		ret = request_threaded_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd,
				pb1200_mmc1_cdfn, 0, "sd1_eject", mmc_host);
		if (ret) {
			free_irq(PB1200_SD1_INSERT_INT, mmc_host);
			goto out;
+17 −14
Original line number Diff line number Diff line
@@ -450,24 +450,27 @@ static struct platform_device db1300_ide_dev = {

static irqreturn_t db1300_mmc_cd(int irq, void *ptr)
{
	void(*mmc_cd)(struct mmc_host *, unsigned long);

	/* disable the one currently screaming. No other way to shut it up */
	if (irq == DB1300_SD1_INSERT_INT) {
		disable_irq_nosync(DB1300_SD1_INSERT_INT);
		enable_irq(DB1300_SD1_EJECT_INT);
	} else {
		disable_irq_nosync(DB1300_SD1_EJECT_INT);
		enable_irq(DB1300_SD1_INSERT_INT);
	disable_irq_nosync(irq);
	return IRQ_WAKE_THREAD;
}

static irqreturn_t db1300_mmc_cdfn(int irq, void *ptr)
{
	void (*mmc_cd)(struct mmc_host *, unsigned long);

	/* link against CONFIG_MMC=m.  We can only be called once MMC core has
	 * initialized the controller, so symbol_get() should always succeed.
	 */
	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);

	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;
}

@@ -487,13 +490,13 @@ static int db1300_mmc_cd_setup(void *mmc_host, int en)
	int ret;

	if (en) {
		ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0,
				  "sd_insert", mmc_host);
		ret = request_threaded_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd,
				db1300_mmc_cdfn, 0, "sd_insert", mmc_host);
		if (ret)
			goto out;

		ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0,
				  "sd_eject", mmc_host);
		ret = request_threaded_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd,
				db1300_mmc_cdfn, 0, "sd_eject", mmc_host);
		if (ret) {
			free_irq(DB1300_SD1_INSERT_INT, mmc_host);
			goto out;
+19 −14
Original line number Diff line number Diff line
@@ -131,22 +131,27 @@ static irqreturn_t db1000_pcmcia_stschgirq(int irq, void *data)
	return IRQ_HANDLED;
}

static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data)
{
	struct db1x_pcmcia_sock *sock = data;

/* 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.
 */
	if (irq == sock->insert_irq) {
		disable_irq_nosync(sock->insert_irq);
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;

	/* Wait a bit for the signals to stop bouncing. */
	msleep(100);
	if (irq == sock->insert_irq)
		enable_irq(sock->eject_irq);
	} else {
		disable_irq_nosync(sock->eject_irq);
	else
		enable_irq(sock->insert_irq);
	}

	pcmcia_parse_events(&sock->socket, SS_DETECT);

@@ -172,13 +177,13 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
	 */
	if ((sock->board_type == BOARD_TYPE_DB1200) ||
	    (sock->board_type == BOARD_TYPE_DB1300)) {
		ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
				  0, "pcmcia_insert", sock);
		ret = request_threaded_irq(sock->insert_irq, db1200_pcmcia_cdirq,
			db1200_pcmcia_cdirq_fn, 0, "pcmcia_insert", sock);
		if (ret)
			goto out1;

		ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq,
				  0, "pcmcia_eject", sock);
		ret = request_threaded_irq(sock->eject_irq, db1200_pcmcia_cdirq,
			db1200_pcmcia_cdirq_fn, 0, "pcmcia_eject", sock);
		if (ret) {
			free_irq(sock->insert_irq, sock);
			goto out1;