| 1 | From 62d51f0d0d0b3c758b4505c3855b61288b8e90aa Mon Sep 17 00:00:00 2001 |
| 2 | From: San Mehat <san@android.com> |
| 3 | Date: Mon, 14 Apr 2008 15:22:49 -0700 |
| 4 | Subject: [PATCH 095/134] mmc: Add concept of an 'embedded' SDIO device. |
| 5 | |
| 6 | This is required to support chips which use SDIO for signaling/ |
| 7 | communication but do not implement the various card enumeration registers |
| 8 | as required for full SD / SDIO cards. |
| 9 | |
| 10 | mmc: sdio: Fix bug where we're freeing the CIS tables we never allocated when using EMBEDDED_SDIO |
| 11 | mmc: Add max_blksize to embedded SDIO data |
| 12 | |
| 13 | Signed-off-by: San Mehat <san@google.com> |
| 14 | --- |
| 15 | arch/arm/include/asm/mach/mmc.h | 10 ++++++ |
| 16 | drivers/mmc/core/Kconfig | 10 +++++- |
| 17 | drivers/mmc/core/core.c | 16 +++++++++ |
| 18 | drivers/mmc/core/sdio.c | 67 ++++++++++++++++++++++++++++++++------- |
| 19 | drivers/mmc/core/sdio_bus.c | 13 +++++++- |
| 20 | include/linux/mmc/host.h | 17 ++++++++++ |
| 21 | include/linux/mmc/sdio_func.h | 8 +++++ |
| 22 | 7 files changed, 127 insertions(+), 14 deletions(-) |
| 23 | |
| 24 | --- a/arch/arm/include/asm/mach/mmc.h |
| 25 | +++ b/arch/arm/include/asm/mach/mmc.h |
| 26 | @@ -5,12 +5,22 @@ |
| 27 | #define ASMARM_MACH_MMC_H |
| 28 | |
| 29 | #include <linux/mmc/host.h> |
| 30 | +#include <linux/mmc/card.h> |
| 31 | +#include <linux/mmc/sdio_func.h> |
| 32 | + |
| 33 | +struct embedded_sdio_data { |
| 34 | + struct sdio_cis cis; |
| 35 | + struct sdio_cccr cccr; |
| 36 | + struct sdio_embedded_func *funcs; |
| 37 | + int num_funcs; |
| 38 | +}; |
| 39 | |
| 40 | struct mmc_platform_data { |
| 41 | unsigned int ocr_mask; /* available voltages */ |
| 42 | u32 (*translate_vdd)(struct device *, unsigned int); |
| 43 | unsigned int (*status)(struct device *); |
| 44 | unsigned int status_irq; |
| 45 | + struct embedded_sdio_data *embedded_sdio; |
| 46 | int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id); |
| 47 | }; |
| 48 | |
| 49 | --- a/drivers/mmc/core/Kconfig |
| 50 | +++ b/drivers/mmc/core/Kconfig |
| 51 | @@ -14,11 +14,19 @@ config MMC_UNSAFE_RESUME |
| 52 | This option is usually just for embedded systems which use |
| 53 | a MMC/SD card for rootfs. Most people should say N here. |
| 54 | |
| 55 | +config MMC_EMBEDDED_SDIO |
| 56 | + boolean "MMC embedded SDIO device support (EXPERIMENTAL)" |
| 57 | + depends on EXPERIMENTAL |
| 58 | + help |
| 59 | + If you say Y here, support will be added for embedded SDIO |
| 60 | + devices which do not contain the necessary enumeration |
| 61 | + support in hardware to be properly detected. |
| 62 | + |
| 63 | config MMC_PARANOID_SD_INIT |
| 64 | bool "Enable paranoid SD card initialization (EXPERIMENTAL)" |
| 65 | + depends on EXPERIMENTAL |
| 66 | help |
| 67 | If you say Y here, the MMC layer will be extra paranoid |
| 68 | about re-trying SD init requests. This can be a useful |
| 69 | work-around for buggy controllers and hardware. Enable |
| 70 | if you are experiencing issues with SD detection. |
| 71 | - |
| 72 | --- a/drivers/mmc/core/core.c |
| 73 | +++ b/drivers/mmc/core/core.c |
| 74 | @@ -1011,6 +1011,22 @@ EXPORT_SYMBOL(mmc_resume_host); |
| 75 | |
| 76 | #endif |
| 77 | |
| 78 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 79 | +void mmc_set_embedded_sdio_data(struct mmc_host *host, |
| 80 | + struct sdio_cis *cis, |
| 81 | + struct sdio_cccr *cccr, |
| 82 | + struct sdio_embedded_func *funcs, |
| 83 | + int num_funcs) |
| 84 | +{ |
| 85 | + host->embedded_sdio_data.cis = cis; |
| 86 | + host->embedded_sdio_data.cccr = cccr; |
| 87 | + host->embedded_sdio_data.funcs = funcs; |
| 88 | + host->embedded_sdio_data.num_funcs = num_funcs; |
| 89 | +} |
| 90 | + |
| 91 | +EXPORT_SYMBOL(mmc_set_embedded_sdio_data); |
| 92 | +#endif |
| 93 | + |
| 94 | static int __init mmc_init(void) |
| 95 | { |
| 96 | int ret; |
| 97 | --- a/drivers/mmc/core/sdio.c |
| 98 | +++ b/drivers/mmc/core/sdio.c |
| 99 | @@ -24,6 +24,10 @@ |
| 100 | #include "sdio_ops.h" |
| 101 | #include "sdio_cis.h" |
| 102 | |
| 103 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 104 | +#include <linux/mmc/sdio_ids.h> |
| 105 | +#endif |
| 106 | + |
| 107 | static int sdio_read_fbr(struct sdio_func *func) |
| 108 | { |
| 109 | int ret; |
| 110 | @@ -314,6 +318,11 @@ int mmc_attach_sdio(struct mmc_host *hos |
| 111 | */ |
| 112 | funcs = (ocr & 0x70000000) >> 28; |
| 113 | |
| 114 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 115 | + if (host->embedded_sdio_data.funcs) |
| 116 | + funcs = host->embedded_sdio_data.num_funcs; |
| 117 | +#endif |
| 118 | + |
| 119 | /* |
| 120 | * Allocate card structure. |
| 121 | */ |
| 122 | @@ -351,17 +360,33 @@ int mmc_attach_sdio(struct mmc_host *hos |
| 123 | /* |
| 124 | * Read the common registers. |
| 125 | */ |
| 126 | - err = sdio_read_cccr(card); |
| 127 | - if (err) |
| 128 | - goto remove; |
| 129 | |
| 130 | - /* |
| 131 | - * Read the common CIS tuples. |
| 132 | - */ |
| 133 | - err = sdio_read_common_cis(card); |
| 134 | - if (err) |
| 135 | - goto remove; |
| 136 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 137 | + if (host->embedded_sdio_data.cccr) |
| 138 | + memcpy(&card->cccr, host->embedded_sdio_data.cccr, sizeof(struct sdio_cccr)); |
| 139 | + else { |
| 140 | +#endif |
| 141 | + err = sdio_read_cccr(card); |
| 142 | + if (err) |
| 143 | + goto remove; |
| 144 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 145 | + } |
| 146 | +#endif |
| 147 | |
| 148 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 149 | + if (host->embedded_sdio_data.cis) |
| 150 | + memcpy(&card->cis, host->embedded_sdio_data.cis, sizeof(struct sdio_cis)); |
| 151 | + else { |
| 152 | +#endif |
| 153 | + /* |
| 154 | + * Read the common CIS tuples. |
| 155 | + */ |
| 156 | + err = sdio_read_common_cis(card); |
| 157 | + if (err) |
| 158 | + goto remove; |
| 159 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 160 | + } |
| 161 | +#endif |
| 162 | /* |
| 163 | * Switch to high-speed (if supported). |
| 164 | */ |
| 165 | @@ -395,9 +420,27 @@ int mmc_attach_sdio(struct mmc_host *hos |
| 166 | * Initialize (but don't add) all present functions. |
| 167 | */ |
| 168 | for (i = 0;i < funcs;i++) { |
| 169 | - err = sdio_init_func(host->card, i + 1); |
| 170 | - if (err) |
| 171 | - goto remove; |
| 172 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 173 | + if (host->embedded_sdio_data.funcs) { |
| 174 | + struct sdio_func *tmp; |
| 175 | + |
| 176 | + tmp = sdio_alloc_func(host->card); |
| 177 | + if (IS_ERR(tmp)) |
| 178 | + goto remove; |
| 179 | + tmp->num = (i + 1); |
| 180 | + card->sdio_func[i] = tmp; |
| 181 | + tmp->class = host->embedded_sdio_data.funcs[i].f_class; |
| 182 | + tmp->max_blksize = host->embedded_sdio_data.funcs[i].f_maxblksize; |
| 183 | + tmp->vendor = card->cis.vendor; |
| 184 | + tmp->device = card->cis.device; |
| 185 | + } else { |
| 186 | +#endif |
| 187 | + err = sdio_init_func(host->card, i + 1); |
| 188 | + if (err) |
| 189 | + goto remove; |
| 190 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 191 | + } |
| 192 | +#endif |
| 193 | } |
| 194 | |
| 195 | mmc_release_host(host); |
| 196 | --- a/drivers/mmc/core/sdio_bus.c |
| 197 | +++ b/drivers/mmc/core/sdio_bus.c |
| 198 | @@ -20,6 +20,10 @@ |
| 199 | #include "sdio_cis.h" |
| 200 | #include "sdio_bus.h" |
| 201 | |
| 202 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 203 | +#include <linux/mmc/host.h> |
| 204 | +#endif |
| 205 | + |
| 206 | #define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) |
| 207 | #define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) |
| 208 | |
| 209 | @@ -202,7 +206,14 @@ static void sdio_release_func(struct dev |
| 210 | { |
| 211 | struct sdio_func *func = dev_to_sdio_func(dev); |
| 212 | |
| 213 | - sdio_free_func_cis(func); |
| 214 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 215 | + /* |
| 216 | + * If this device is embedded then we never allocated |
| 217 | + * cis tables for this func |
| 218 | + */ |
| 219 | + if (!func->card->host->embedded_sdio_data.funcs) |
| 220 | +#endif |
| 221 | + sdio_free_func_cis(func); |
| 222 | |
| 223 | if (func->info) |
| 224 | kfree(func->info); |
| 225 | --- a/include/linux/mmc/host.h |
| 226 | +++ b/include/linux/mmc/host.h |
| 227 | @@ -161,6 +161,15 @@ struct mmc_host { |
| 228 | |
| 229 | struct dentry *debugfs_root; |
| 230 | |
| 231 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 232 | + struct { |
| 233 | + struct sdio_cis *cis; |
| 234 | + struct sdio_cccr *cccr; |
| 235 | + struct sdio_embedded_func *funcs; |
| 236 | + int num_funcs; |
| 237 | + } embedded_sdio_data; |
| 238 | +#endif |
| 239 | + |
| 240 | unsigned long private[0] ____cacheline_aligned; |
| 241 | }; |
| 242 | |
| 243 | @@ -169,6 +178,14 @@ extern int mmc_add_host(struct mmc_host |
| 244 | extern void mmc_remove_host(struct mmc_host *); |
| 245 | extern void mmc_free_host(struct mmc_host *); |
| 246 | |
| 247 | +#ifdef CONFIG_MMC_EMBEDDED_SDIO |
| 248 | +extern void mmc_set_embedded_sdio_data(struct mmc_host *host, |
| 249 | + struct sdio_cis *cis, |
| 250 | + struct sdio_cccr *cccr, |
| 251 | + struct sdio_embedded_func *funcs, |
| 252 | + int num_funcs); |
| 253 | +#endif |
| 254 | + |
| 255 | static inline void *mmc_priv(struct mmc_host *host) |
| 256 | { |
| 257 | return (void *)host->private; |
| 258 | --- a/include/linux/mmc/sdio_func.h |
| 259 | +++ b/include/linux/mmc/sdio_func.h |
| 260 | @@ -21,6 +21,14 @@ struct sdio_func; |
| 261 | typedef void (sdio_irq_handler_t)(struct sdio_func *); |
| 262 | |
| 263 | /* |
| 264 | + * Structure used to hold embedded SDIO device data from platform layer |
| 265 | + */ |
| 266 | +struct sdio_embedded_func { |
| 267 | + uint8_t f_class; |
| 268 | + uint32_t f_maxblksize; |
| 269 | +}; |
| 270 | + |
| 271 | +/* |
| 272 | * SDIO function CIS tuple (unknown to the core) |
| 273 | */ |
| 274 | struct sdio_func_tuple { |
| 275 | |