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

mmc: esdhc: Add support for 8-bit bus width and non-removable card

This patch adds support of connecting an MMC media using an 8-bit
bus width connection to Freescale's P2020 H/W SDHC controller. During
the probe function, the generic function mmc_of_parse is called to
detect whether the controller is configured with 8-bit bus width.

Also, the generic function detects if the non-removable property is
set in the device tree. The function esdhc_pltfm_bus_width was added
because the bus width configuration is platform specific.

Signed-off-by: Oded Gabbay <ogabbay@advaoptical.com>
Reviewed-by: Anton Vorontsov <anton@enomsg.org>
Signed-off-by: Chris Ball <cjb@laptop.org>

authored by

Oded Gabbay and committed by
Chris Ball
66b50a00 7c4f10ac

+50 -1
+7
drivers/mmc/host/sdhci-esdhc.h
··· 36 36 /* pltfm-specific */ 37 37 #define ESDHC_HOST_CONTROL_LE 0x20 38 38 39 + /* 40 + * P2020 interpretation of the SDHCI_HOST_CONTROL register 41 + */ 42 + #define ESDHC_CTRL_4BITBUS (0x1 << 1) 43 + #define ESDHC_CTRL_8BITBUS (0x2 << 1) 44 + #define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) 45 + 39 46 /* OF-specific */ 40 47 #define ESDHC_DMA_SYSCTL 0x40c 41 48 #define ESDHC_DMA_SNOOP 0x00000040
+43 -1
drivers/mmc/host/sdhci-of-esdhc.c
··· 13 13 * your option) any later version. 14 14 */ 15 15 16 + #include <linux/err.h> 16 17 #include <linux/io.h> 17 18 #include <linux/of.h> 18 19 #include <linux/delay.h> ··· 231 230 host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; 232 231 } 233 232 233 + static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) 234 + { 235 + u32 ctrl; 236 + 237 + switch (width) { 238 + case MMC_BUS_WIDTH_8: 239 + ctrl = ESDHC_CTRL_8BITBUS; 240 + break; 241 + 242 + case MMC_BUS_WIDTH_4: 243 + ctrl = ESDHC_CTRL_4BITBUS; 244 + break; 245 + 246 + default: 247 + ctrl = 0; 248 + break; 249 + } 250 + 251 + clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL, 252 + ESDHC_CTRL_BUSWIDTH_MASK, ctrl); 253 + 254 + return 0; 255 + } 256 + 234 257 static const struct sdhci_ops sdhci_esdhc_ops = { 235 258 .read_l = esdhc_readl, 236 259 .read_w = esdhc_readw, ··· 272 247 .platform_resume = esdhc_of_resume, 273 248 #endif 274 249 .adma_workaround = esdhci_of_adma_workaround, 250 + .platform_bus_width = esdhc_pltfm_bus_width, 275 251 }; 276 252 277 253 static const struct sdhci_pltfm_data sdhci_esdhc_pdata = { ··· 288 262 289 263 static int sdhci_esdhc_probe(struct platform_device *pdev) 290 264 { 291 - return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata, 0); 265 + struct sdhci_host *host; 266 + int ret; 267 + 268 + host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0); 269 + if (IS_ERR(host)) 270 + return PTR_ERR(host); 271 + 272 + sdhci_get_of_property(pdev); 273 + 274 + /* call to generic mmc_of_parse to support additional capabilities */ 275 + mmc_of_parse(host->mmc); 276 + 277 + ret = sdhci_add_host(host); 278 + if (ret) 279 + sdhci_pltfm_free(pdev); 280 + 281 + return ret; 292 282 } 293 283 294 284 static int sdhci_esdhc_remove(struct platform_device *pdev)