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

mmc: detect SDIO cards

Really basic init sequence for SDIO cards.

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

+305 -15
+1 -1
MAINTAINERS
··· 2561 2561 W: http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html 2562 2562 S: Maintained 2563 2563 2564 - MULTIMEDIA CARD (MMC) AND SECURE DIGITAL (SD) SUBSYSTEM 2564 + MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM 2565 2565 P: Pierre Ossman 2566 2566 M: drzeus-mmc@drzeus.cx 2567 2567 L: linux-kernel@vger.kernel.org
+2 -1
drivers/mmc/core/Makefile
··· 8 8 9 9 obj-$(CONFIG_MMC) += mmc_core.o 10 10 mmc_core-y := core.o sysfs.o bus.o host.o \ 11 - mmc.o mmc_ops.o sd.o sd_ops.o 11 + mmc.o mmc_ops.o sd.o sd_ops.o \ 12 + sdio.o sdio_ops.o 12 13
+8
drivers/mmc/core/bus.c
··· 34 34 return sprintf(buf, "MMC\n"); 35 35 case MMC_TYPE_SD: 36 36 return sprintf(buf, "SD\n"); 37 + case MMC_TYPE_SDIO: 38 + return sprintf(buf, "SDIO\n"); 37 39 default: 38 40 return -EFAULT; 39 41 } ··· 77 75 break; 78 76 case MMC_TYPE_SD: 79 77 add_env("MMC_TYPE=%s", "SD"); 78 + break; 79 + case MMC_TYPE_SDIO: 80 + add_env("MMC_TYPE=%s", "SDIO"); 80 81 break; 81 82 } 82 83 ··· 225 220 type = "SD"; 226 221 if (mmc_card_blockaddr(card)) 227 222 type = "SDHC"; 223 + break; 224 + case MMC_TYPE_SDIO: 225 + type = "SDIO"; 228 226 break; 229 227 default: 230 228 type = "?";
+29 -13
drivers/mmc/core/core.c
··· 32 32 33 33 #include "mmc_ops.h" 34 34 #include "sd_ops.h" 35 + #include "sdio_ops.h" 35 36 36 37 extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr); 37 38 extern int mmc_attach_sd(struct mmc_host *host, u32 ocr); 39 + extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr); 38 40 39 41 static struct workqueue_struct *workqueue; 40 42 ··· 597 595 598 596 mmc_send_if_cond(host, host->ocr_avail); 599 597 598 + /* 599 + * First we search for SDIO... 600 + */ 601 + err = mmc_send_io_op_cond(host, 0, &ocr); 602 + if (!err) { 603 + if (mmc_attach_sdio(host, ocr)) 604 + mmc_power_off(host); 605 + return; 606 + } 607 + 608 + /* 609 + * ...then normal SD... 610 + */ 600 611 err = mmc_send_app_op_cond(host, 0, &ocr); 601 612 if (!err) { 602 613 if (mmc_attach_sd(host, ocr)) 603 614 mmc_power_off(host); 604 - } else { 605 - /* 606 - * If we fail to detect any SD cards then try 607 - * searching for MMC cards. 608 - */ 609 - err = mmc_send_op_cond(host, 0, &ocr); 610 - if (!err) { 611 - if (mmc_attach_mmc(host, ocr)) 612 - mmc_power_off(host); 613 - } else { 614 - mmc_power_off(host); 615 - mmc_release_host(host); 616 - } 615 + return; 617 616 } 617 + 618 + /* 619 + * ...and finally MMC. 620 + */ 621 + err = mmc_send_op_cond(host, 0, &ocr); 622 + if (!err) { 623 + if (mmc_attach_mmc(host, ocr)) 624 + mmc_power_off(host); 625 + return; 626 + } 627 + 628 + mmc_release_host(host); 629 + mmc_power_off(host); 618 630 } else { 619 631 if (host->bus_ops->detect && !host->bus_dead) 620 632 host->bus_ops->detect(host);
+176
drivers/mmc/core/sdio.c
··· 1 + /* 2 + * linux/drivers/mmc/sdio.c 3 + * 4 + * Copyright 2006-2007 Pierre Ossman 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or (at 9 + * your option) any later version. 10 + */ 11 + 12 + #include <linux/err.h> 13 + 14 + #include <linux/mmc/host.h> 15 + #include <linux/mmc/card.h> 16 + 17 + #include "core.h" 18 + #include "bus.h" 19 + #include "mmc_ops.h" 20 + #include "sd_ops.h" 21 + #include "sdio_ops.h" 22 + 23 + /* 24 + * Host is being removed. Free up the current card. 25 + */ 26 + static void mmc_sdio_remove(struct mmc_host *host) 27 + { 28 + BUG_ON(!host); 29 + BUG_ON(!host->card); 30 + 31 + mmc_remove_card(host->card); 32 + host->card = NULL; 33 + } 34 + 35 + /* 36 + * Card detection callback from host. 37 + */ 38 + static void mmc_sdio_detect(struct mmc_host *host) 39 + { 40 + int err; 41 + 42 + BUG_ON(!host); 43 + BUG_ON(!host->card); 44 + 45 + mmc_claim_host(host); 46 + 47 + /* 48 + * Just check if our card has been removed. 49 + */ 50 + err = mmc_select_card(host->card); 51 + 52 + mmc_release_host(host); 53 + 54 + if (err) { 55 + mmc_sdio_remove(host); 56 + 57 + mmc_claim_host(host); 58 + mmc_detach_bus(host); 59 + mmc_release_host(host); 60 + } 61 + } 62 + 63 + 64 + static const struct mmc_bus_ops mmc_sdio_ops = { 65 + .remove = mmc_sdio_remove, 66 + .detect = mmc_sdio_detect, 67 + }; 68 + 69 + 70 + /* 71 + * Starting point for SDIO card init. 72 + */ 73 + int mmc_attach_sdio(struct mmc_host *host, u32 ocr) 74 + { 75 + int err; 76 + int funcs; 77 + struct mmc_card *card; 78 + 79 + BUG_ON(!host); 80 + BUG_ON(!host->claimed); 81 + 82 + mmc_attach_bus(host, &mmc_sdio_ops); 83 + 84 + /* 85 + * Sanity check the voltages that the card claims to 86 + * support. 87 + */ 88 + if (ocr & 0x7F) { 89 + printk(KERN_WARNING "%s: card claims to support voltages " 90 + "below the defined range. These will be ignored.\n", 91 + mmc_hostname(host)); 92 + ocr &= ~0x7F; 93 + } 94 + 95 + if (ocr & MMC_VDD_165_195) { 96 + printk(KERN_WARNING "%s: SDIO card claims to support the " 97 + "incompletely defined 'low voltage range'. This " 98 + "will be ignored.\n", mmc_hostname(host)); 99 + ocr &= ~MMC_VDD_165_195; 100 + } 101 + 102 + host->ocr = mmc_select_voltage(host, ocr); 103 + 104 + /* 105 + * Can we support the voltage(s) of the card(s)? 106 + */ 107 + if (!host->ocr) { 108 + err = -EINVAL; 109 + goto err; 110 + } 111 + 112 + /* 113 + * Inform the card of the voltage 114 + */ 115 + err = mmc_send_io_op_cond(host, host->ocr, &ocr); 116 + if (err) 117 + goto err; 118 + 119 + /* 120 + * The number of functions on the card is encoded inside 121 + * the ocr. 122 + */ 123 + funcs = (ocr & 0x70000000) >> 28; 124 + 125 + /* 126 + * Allocate card structure. 127 + */ 128 + card = mmc_alloc_card(host); 129 + if (IS_ERR(card)) { 130 + err = PTR_ERR(card); 131 + goto err; 132 + } 133 + 134 + card->type = MMC_TYPE_SDIO; 135 + 136 + /* 137 + * Set card RCA. 138 + */ 139 + err = mmc_send_relative_addr(host, &card->rca); 140 + if (err) 141 + goto free_card; 142 + 143 + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); 144 + 145 + /* 146 + * Select card, as all following commands rely on that. 147 + */ 148 + err = mmc_select_card(card); 149 + if (err) 150 + goto free_card; 151 + 152 + host->card = card; 153 + 154 + mmc_release_host(host); 155 + 156 + err = mmc_add_card(host->card); 157 + if (err) 158 + goto reclaim_host; 159 + 160 + return 0; 161 + 162 + reclaim_host: 163 + mmc_claim_host(host); 164 + free_card: 165 + mmc_remove_card(card); 166 + host->card = NULL; 167 + err: 168 + mmc_detach_bus(host); 169 + mmc_release_host(host); 170 + 171 + printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", 172 + mmc_hostname(host), err); 173 + 174 + return err; 175 + } 176 +
+49
drivers/mmc/core/sdio_ops.c
··· 1 + /* 2 + * linux/drivers/mmc/sdio_ops.c 3 + * 4 + * Copyright 2006-2007 Pierre Ossman 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or (at 9 + * your option) any later version. 10 + */ 11 + 12 + #include <linux/mmc/host.h> 13 + #include <linux/mmc/mmc.h> 14 + #include <linux/mmc/sdio.h> 15 + 16 + #include "core.h" 17 + 18 + int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) 19 + { 20 + struct mmc_command cmd; 21 + int i, err = 0; 22 + 23 + BUG_ON(!host); 24 + 25 + memset(&cmd, 0, sizeof(struct mmc_command)); 26 + 27 + cmd.opcode = SD_IO_SEND_OP_COND; 28 + cmd.arg = ocr; 29 + cmd.flags = MMC_RSP_R4 | MMC_CMD_BCR; 30 + 31 + for (i = 100; i; i--) { 32 + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); 33 + if (err) 34 + break; 35 + 36 + if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) 37 + break; 38 + 39 + err = -ETIMEDOUT; 40 + 41 + mmc_delay(10); 42 + } 43 + 44 + if (rocr) 45 + *rocr = cmd.resp[0]; 46 + 47 + return err; 48 + } 49 +
+18
drivers/mmc/core/sdio_ops.h
··· 1 + /* 2 + * linux/drivers/mmc/sdio_ops.c 3 + * 4 + * Copyright 2006-2007 Pierre Ossman 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or (at 9 + * your option) any later version. 10 + */ 11 + 12 + #ifndef _MMC_SDIO_OPS_H 13 + #define _MMC_SDIO_OPS_H 14 + 15 + int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); 16 + 17 + #endif 18 +
+2
include/linux/mmc/card.h
··· 67 67 unsigned int type; /* card type */ 68 68 #define MMC_TYPE_MMC 0 /* MMC card */ 69 69 #define MMC_TYPE_SD 1 /* SD card */ 70 + #define MMC_TYPE_SDIO 2 /* SDIO card */ 70 71 unsigned int state; /* (our) card state */ 71 72 #define MMC_STATE_PRESENT (1<<0) /* present in sysfs */ 72 73 #define MMC_STATE_READONLY (1<<1) /* card is read-only */ ··· 85 84 86 85 #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) 87 86 #define mmc_card_sd(c) ((c)->type == MMC_TYPE_SD) 87 + #define mmc_card_sdio(c) ((c)->type == MMC_TYPE_SDIO) 88 88 89 89 #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) 90 90 #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
+1
include/linux/mmc/core.h
··· 41 41 #define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY) 42 42 #define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) 43 43 #define MMC_RSP_R3 (MMC_RSP_PRESENT) 44 + #define MMC_RSP_R4 (MMC_RSP_PRESENT) 44 45 #define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) 45 46 #define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) 46 47
+19
include/linux/mmc/sdio.h
··· 1 + /* 2 + * include/linux/mmc/sdio.h 3 + * 4 + * Copyright 2006-2007 Pierre Ossman 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or (at 9 + * your option) any later version. 10 + */ 11 + 12 + #ifndef MMC_SDIO_H 13 + #define MMC_SDIO_H 14 + 15 + /* SDIO commands type argument response */ 16 + #define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */ 17 + 18 + #endif 19 +