Loading drivers/mmc/core/sdio.c +63 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> #include <linux/mmc/sdio.h> #include <linux/mmc/sdio_func.h> #include "core.h" Loading @@ -39,6 +40,61 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) return 0; } static int sdio_read_cccr(struct mmc_card *card) { int ret; int cccr_vsn; unsigned char data; memset(&card->cccr, 0, sizeof(struct sdio_cccr)); ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); if (ret) goto out; cccr_vsn = data & 0x0f; if (cccr_vsn > SDIO_CCCR_REV_1_20) { printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", mmc_hostname(card->host), cccr_vsn); return -EINVAL; } card->cccr.sdio_vsn = (data & 0xf0) >> 4; ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); if (ret) goto out; if (data & SDIO_CCCR_CAP_SMB) card->cccr.multi_block = 1; if (data & SDIO_CCCR_CAP_LSC) card->cccr.low_speed = 1; if (data & SDIO_CCCR_CAP_4BLS) card->cccr.wide_bus = 1; if (cccr_vsn >= SDIO_CCCR_REV_1_10) { ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data); if (ret) goto out; if (data & SDIO_POWER_SMPC) card->cccr.high_power = 1; } if (cccr_vsn >= SDIO_CCCR_REV_1_20) { ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); if (ret) goto out; if (data & SDIO_SPEED_SHS) card->cccr.high_speed = 1; } out: return ret; } /* * Host is being removed. Free up the current card. */ Loading Loading @@ -180,6 +236,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto remove; /* * Read the common registers. */ err = sdio_read_cccr(card); if (err) goto remove; /* * Initialize (but don't add) all present functions. */ Loading include/linux/mmc/card.h +11 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,16 @@ struct sd_switch_caps { unsigned int hs_max_dtr; }; struct sdio_cccr { unsigned int sdio_vsn; unsigned int sd_vsn; unsigned int multi_block:1, low_speed:1, wide_bus:1, high_power:1, high_speed:1; }; struct mmc_host; struct sdio_func; Loading Loading @@ -87,6 +97,7 @@ struct mmc_card { struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ unsigned int sdio_funcs; /* number of SDIO functions */ struct sdio_cccr cccr; /* common card info */ struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ }; Loading Loading
drivers/mmc/core/sdio.c +63 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> #include <linux/mmc/sdio.h> #include <linux/mmc/sdio_func.h> #include "core.h" Loading @@ -39,6 +40,61 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn) return 0; } static int sdio_read_cccr(struct mmc_card *card) { int ret; int cccr_vsn; unsigned char data; memset(&card->cccr, 0, sizeof(struct sdio_cccr)); ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); if (ret) goto out; cccr_vsn = data & 0x0f; if (cccr_vsn > SDIO_CCCR_REV_1_20) { printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", mmc_hostname(card->host), cccr_vsn); return -EINVAL; } card->cccr.sdio_vsn = (data & 0xf0) >> 4; ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data); if (ret) goto out; if (data & SDIO_CCCR_CAP_SMB) card->cccr.multi_block = 1; if (data & SDIO_CCCR_CAP_LSC) card->cccr.low_speed = 1; if (data & SDIO_CCCR_CAP_4BLS) card->cccr.wide_bus = 1; if (cccr_vsn >= SDIO_CCCR_REV_1_10) { ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data); if (ret) goto out; if (data & SDIO_POWER_SMPC) card->cccr.high_power = 1; } if (cccr_vsn >= SDIO_CCCR_REV_1_20) { ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); if (ret) goto out; if (data & SDIO_SPEED_SHS) card->cccr.high_speed = 1; } out: return ret; } /* * Host is being removed. Free up the current card. */ Loading Loading @@ -180,6 +236,13 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) if (err) goto remove; /* * Read the common registers. */ err = sdio_read_cccr(card); if (err) goto remove; /* * Initialize (but don't add) all present functions. */ Loading
include/linux/mmc/card.h +11 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,16 @@ struct sd_switch_caps { unsigned int hs_max_dtr; }; struct sdio_cccr { unsigned int sdio_vsn; unsigned int sd_vsn; unsigned int multi_block:1, low_speed:1, wide_bus:1, high_power:1, high_speed:1; }; struct mmc_host; struct sdio_func; Loading Loading @@ -87,6 +97,7 @@ struct mmc_card { struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ unsigned int sdio_funcs; /* number of SDIO functions */ struct sdio_cccr cccr; /* common card info */ struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */ }; Loading