Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5c4e6f13 authored by Pierre Ossman's avatar Pierre Ossman
Browse files

mmc: detect SDIO cards



Really basic init sequence for SDIO cards.

Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
parent 1d4de9ed
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2561,7 +2561,7 @@ L: linux-kernel@vger.kernel.org
W:	http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html
S:	Maintained

MULTIMEDIA CARD (MMC) AND SECURE DIGITAL (SD) SUBSYSTEM
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
P:	Pierre Ossman
M:	drzeus-mmc@drzeus.cx
L:	linux-kernel@vger.kernel.org
+2 −1
Original line number Diff line number Diff line
@@ -8,5 +8,6 @@ endif

obj-$(CONFIG_MMC)		+= mmc_core.o
mmc_core-y			:= core.o sysfs.o bus.o host.o \
				   mmc.o mmc_ops.o sd.o sd_ops.o
				   mmc.o mmc_ops.o sd.o sd_ops.o \
				   sdio.o sdio_ops.o
+8 −0
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ static ssize_t mmc_type_show(struct device *dev,
		return sprintf(buf, "MMC\n");
	case MMC_TYPE_SD:
		return sprintf(buf, "SD\n");
	case MMC_TYPE_SDIO:
		return sprintf(buf, "SDIO\n");
	default:
		return -EFAULT;
	}
@@ -76,6 +78,9 @@ mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
	case MMC_TYPE_SD:
		add_env("MMC_TYPE=%s", "SD");
		break;
	case MMC_TYPE_SDIO:
		add_env("MMC_TYPE=%s", "SDIO");
		break;
	}

	add_env("MMC_NAME=%s", mmc_card_name(card));
@@ -221,6 +226,9 @@ int mmc_add_card(struct mmc_card *card)
		if (mmc_card_blockaddr(card))
			type = "SDHC";
		break;
	case MMC_TYPE_SDIO:
		type = "SDIO";
		break;
	default:
		type = "?";
		break;
+28 −12
Original line number Diff line number Diff line
@@ -32,9 +32,11 @@

#include "mmc_ops.h"
#include "sd_ops.h"
#include "sdio_ops.h"

extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr);

static struct workqueue_struct *workqueue;

@@ -595,24 +597,38 @@ void mmc_rescan(struct work_struct *work)

		mmc_send_if_cond(host, host->ocr_avail);

		/*
		 * First we search for SDIO...
		 */
		err = mmc_send_io_op_cond(host, 0, &ocr);
		if (!err) {
			if (mmc_attach_sdio(host, ocr))
				mmc_power_off(host);
			return;
		}

		/*
		 * ...then normal SD...
		 */
		err = mmc_send_app_op_cond(host, 0, &ocr);
		if (!err) {
			if (mmc_attach_sd(host, ocr))
				mmc_power_off(host);
		} else {
			return;
		}

		/*
			 * If we fail to detect any SD cards then try
			 * searching for MMC cards.
		 * ...and finally MMC.
		 */
		err = mmc_send_op_cond(host, 0, &ocr);
		if (!err) {
			if (mmc_attach_mmc(host, ocr))
				mmc_power_off(host);
			} else {
				mmc_power_off(host);
				mmc_release_host(host);
			}
			return;
		}

		mmc_release_host(host);
		mmc_power_off(host);
	} else {
		if (host->bus_ops->detect && !host->bus_dead)
			host->bus_ops->detect(host);
+176 −0
Original line number Diff line number Diff line
/*
 *  linux/drivers/mmc/sdio.c
 *
 *  Copyright 2006-2007 Pierre Ossman
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 */

#include <linux/err.h>

#include <linux/mmc/host.h>
#include <linux/mmc/card.h>

#include "core.h"
#include "bus.h"
#include "mmc_ops.h"
#include "sd_ops.h"
#include "sdio_ops.h"

/*
 * Host is being removed. Free up the current card.
 */
static void mmc_sdio_remove(struct mmc_host *host)
{
	BUG_ON(!host);
	BUG_ON(!host->card);

	mmc_remove_card(host->card);
	host->card = NULL;
}

/*
 * Card detection callback from host.
 */
static void mmc_sdio_detect(struct mmc_host *host)
{
	int err;

	BUG_ON(!host);
	BUG_ON(!host->card);

	mmc_claim_host(host);

	/*
	 * Just check if our card has been removed.
	 */
	err = mmc_select_card(host->card);

	mmc_release_host(host);

	if (err) {
		mmc_sdio_remove(host);

		mmc_claim_host(host);
		mmc_detach_bus(host);
		mmc_release_host(host);
	}
}


static const struct mmc_bus_ops mmc_sdio_ops = {
	.remove = mmc_sdio_remove,
	.detect = mmc_sdio_detect,
};


/*
 * Starting point for SDIO card init.
 */
int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
{
	int err;
	int funcs;
	struct mmc_card *card;

	BUG_ON(!host);
	BUG_ON(!host->claimed);

	mmc_attach_bus(host, &mmc_sdio_ops);

	/*
	 * Sanity check the voltages that the card claims to
	 * support.
	 */
	if (ocr & 0x7F) {
		printk(KERN_WARNING "%s: card claims to support voltages "
		       "below the defined range. These will be ignored.\n",
		       mmc_hostname(host));
		ocr &= ~0x7F;
	}

	if (ocr & MMC_VDD_165_195) {
		printk(KERN_WARNING "%s: SDIO card claims to support the "
		       "incompletely defined 'low voltage range'. This "
		       "will be ignored.\n", mmc_hostname(host));
		ocr &= ~MMC_VDD_165_195;
	}

	host->ocr = mmc_select_voltage(host, ocr);

	/*
	 * Can we support the voltage(s) of the card(s)?
	 */
	if (!host->ocr) {
		err = -EINVAL;
		goto err;
	}

	/*
	 * Inform the card of the voltage
	 */
	err = mmc_send_io_op_cond(host, host->ocr, &ocr);
	if (err)
		goto err;

	/*
	 * The number of functions on the card is encoded inside
	 * the ocr.
	 */
	funcs = (ocr & 0x70000000) >> 28;

	/*
	 * Allocate card structure.
	 */
	card = mmc_alloc_card(host);
	if (IS_ERR(card)) {
		err = PTR_ERR(card);
		goto err;
	}

	card->type = MMC_TYPE_SDIO;

	/*
	 * Set card RCA.
	 */
	err = mmc_send_relative_addr(host, &card->rca);
	if (err)
		goto free_card;

	mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);

	/*
	 * Select card, as all following commands rely on that.
	 */
	err = mmc_select_card(card);
	if (err)
		goto free_card;

	host->card = card;

	mmc_release_host(host);

	err = mmc_add_card(host->card);
	if (err)
		goto reclaim_host;

	return 0;

reclaim_host:
	mmc_claim_host(host);
free_card:
	mmc_remove_card(card);
	host->card = NULL;
err:
	mmc_detach_bus(host);
	mmc_release_host(host);

	printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n",
		mmc_hostname(host), err);

	return err;
}
Loading