作者:刘昊昱
博客:http://blog.csdn.net/liuhaoyutz
内核版本:3.10.1
MMC
MMC全称MultiMedia Card,由西门子公司和SanDisk公司1997年推出的多媒体记忆卡标准。MMC卡尺寸为32mm x24mm x 1.4mm,它将存贮单元和控制器一同做到了卡上,智能的控制器使得MMC保证兼容性和灵活性。
MMC卡具有MMC和SPI两种工作模式,MMC模式是默认工作模式,具有MMC的全部特性。而SPI模式则是MMC协议的一个子集,主要用于低速系统。
SD
SD卡全称Secure DigitalMemory Card,由松下、东芝和SanDisk公司于1999年8月共同开发的新一代记忆卡标准,已完全兼容MMC标准。SD卡比MMC卡多了一个进行数据著作权保护的暗号认证功能,读写速度比MMC卡快4倍。
SD卡尺寸为32mm x 24mm x2.1mm,长宽和MMC卡一样,只是比MMC卡厚了0.7mm,以容纳更大容量的存贮单元。SD卡与MMC卡保持向上兼容,也就是说,MMC卡可以被新的设有SD卡插槽的设备存取,但是SD卡却不可以被设有MMC插槽的设备存取。
SDIO
SDIO全称Secure DigitalInput and Output Card,SDIO是在SD标准上定义了一种外设接口,它使用SD的I/O接口来连接外围设备,并通过SD上的I/O数据接口与这些外围设备传输数据。现在已经有很多手持设备支持SDIO功能,而且许多SDIO外设也被开发出来,目前常见的SDIO外设有:WIFI Card、GPS Card、 Bluetooth Card等等。
eMMC
eMMC全称Embedded MultiMediaCard,是MMC协会所制定的内嵌式存储器标准规格,主要应用于智能手机和移动嵌入式产品等。eMMC是一种嵌入式非易失性存储系统,由闪存和闪存控制器两部分组成,它的一个明显优势是在封装中集成了一个闪存控制器,它采用JEDEC标准BGA封装,并采用统一闪存接口管理闪存。
eMMC结构由一个嵌入式存储解决方案组成,带有MMC接口、快闪存储设备及主控制器,所有这些由一个小型BGA封装。由于采用标准封装,eMMC也很容易升级,并不用改变硬件结构。
eMMC的这种将Nand Flash芯片和控制芯片封装在一起的设计概念,就是为了简化产品内存储器的使用,客户只需要采购eMMC芯片放进产品中,不需要处理其它复杂的Nand Flash兼容性和管理问题,减少研发成本和研发周期。
下面我们以Mini2440为例,分析其SDI驱动程序。
Mini2440 MMC/SD硬件接口电路原理图如下:
从Mini2440原理图可以看出,Mini2440 SDI使用的GPE7-GPE10作为4根数据信号线,使用GPE6作为命令信号线,使用GPE5作为时钟信号线。另外,使用GPG8的外部中断功能来作SD卡的插拨检测,使用GPH8来判断SD卡是否有写保护。
一、SDI设备的注册
先来看device注册过程,在arch/arm/mach-s3c24xx/mach-mini2440.c文件中,有如下内容:
505static struct platform_device*mini2440_devices[] __initdata = {
506 &s3c_device_ohci,
507 &s3c_device_wdt,
508 &s3c_device_i2c0,
509 &s3c_device_rtc,
510 &s3c_device_usbgadget,
511 &mini2440_device_eth,
512 &mini2440_led1,
513 &mini2440_led2,
514 &mini2440_led3,
515 &mini2440_led4,
516 &mini2440_button_device,
517 &s3c_device_nand,
518 &s3c_device_sdi,
519 &s3c_device_iis,
520 &uda1340_codec,
521 &mini2440_audio,
522};
这里定义了Mini2440所有的platform device,这里,我们要关注的是s3c_device_sdi,它是Mini2440的SDI控制器。
s3c_device_sdi定义在arch/arm/plat-samsung/devs.c文件中:
1172struct platform_device s3c_device_sdi ={
1173 .name ="s3c2410-sdi",
1174 .id = -1,
1175 .num_resources =ARRAY_SIZE(s3c_sdi_resource),
1176 .resource = s3c_sdi_resource,
1177};
回忆一下platform_device定义在include/linux/platform_device.h文件中:
22structplatform_device {
23 const char *name;
24 int id;
25 bool id_auto;
26 struct device dev;
27 u32 num_resources;
28 struct resource *resource;
29
30 const struct platform_device_id *id_entry;
31
32 /*MFD cell pointer */
33 struct mfd_cell *mfd_cell;
34
35 /*arch specific additions */
36 struct pdev_archdata archdata;
37};
其中,s3c_sdi_resource定义在arch/arm/plat-samsung/devs.c文件中:
1167static struct resources3c_sdi_resource[] = {
1168 [0] = DEFINE_RES_MEM(S3C24XX_PA_SDI, S3C24XX_SZ_SDI),
1169 [1] = DEFINE_RES_IRQ(IRQ_SDI),
1170};
struct resource定义在include/linux/ioport.h文件中:
14/*
15 *Resources are tree-like, allowing
16 *nesting etc..
17*/
18structresource {
19 resource_size_t start;
20 resource_size_t end;
21 const char *name;
22 unsigned long flags;
23 struct resource *parent, *sibling, *child;
24};
宏DEFINE_RES_MEM定义在include/linux/ioport.h文件中:
124#define DEFINE_RES_MEM(_start,_size) \
125 DEFINE_RES_MEM_NAMED((_start), (_size), NULL)
……
122#define DEFINE_RES_MEM_NAMED(_start,_size, _name) \
123 DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_MEM)
……
109#define DEFINE_RES_NAMED(_start, _size,_name, _flags) \
110 { \
111 .start = (_start), \
112 .end = (_start) + (_size) - 1, \
113 .name = (_name), \
114 .flags = (_flags), \
115 }
宏DEFINE_RES_IRQ宏定义在include/linux/ioport.h文件中:
129#define DEFINE_RES_IRQ(_irq) \
130 DEFINE_RES_IRQ_NAMED((_irq), NULL)
……
127#define DEFINE_RES_IRQ_NAMED(_irq,_name) \
128 DEFINE_RES_NAMED((_irq), 1, (_name), IORESOURCE_IRQ)
……
109#define DEFINE_RES_NAMED(_start, _size,_name, _flags) \
110 { \
111 .start = (_start), \
112 .end = (_start) + (_size) - 1, \
113 .name = (_name), \
114 .flags = (_flags), \
115 }
宏S3C24XX_PA_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:
155#define S3C24XX_PA_SDI S3C2410_PA_SDI
宏S3C2410_PA_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:
105#define S3C2410_PA_SDI (0x5A000000)
0x5A000000是S3C2440 SDICON寄存器的地址。
宏S3C24XX_SZ_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:
61#define S3C24XX_SZ_SDI SZ_1M
宏SZ_1M定义在include/linux/sizes.h文件中:
33#define SZ_1M 0x00100000
宏IRQ_SDI定义在arch/arm/mach-s3c24xx/include/mach/irqs.h文件中:
48#define IRQ_SDI S3C2410_IRQ(21)
……
23#define S3C2410_IRQ(x) ((x) +S3C2410_CPUIRQ_OFFSET)
……
21#define S3C2410_CPUIRQ_OFFSET (16)
至此,我们知道了Mini2440的platform_device s3c_device_sdi的定义,下面就是要注册这个平台设备,在arch/arm/mach-s3c24xx/mach-mini2440.c文件中:
622static void __init mini2440_init(void)
{
……
678 platform_add_devices(mini2440_devices,ARRAY_SIZE(mini2440_devices));
……
}
platform_add_devices定义在drivers/base/platform.c文件中:
139/**
140* platform_add_devices - add a numbers of platform devices
141* @devs: array of platform devices to add
142* @num: number of platform devices in array
143*/
144int platform_add_devices(structplatform_device **devs, int num)
145{
146 int i, ret = 0;
147
148 for (i = 0; i < num; i++) {
149 ret = platform_device_register(devs[i]);
150 if (ret) {
151 while (--i >= 0)
152 platform_device_unregister(devs[i]);
153 break;
154 }
155 }
156
157 return ret;
158}
149行,通过调用platform_device_register完成对平台设备的注册,其中包括s3c_device_sdi。
二、SDI驱动分析
Mini2440的SDI驱动定义在drivers/mmc/host/s3cmci.c文件中:
1980static struct platform_drivers3cmci_driver = {
1981 .driver = {
1982 .name = "s3c-sdi",
1983 .owner = THIS_MODULE,
1984 .pm = s3cmci_pm_ops,
1985 },
1986 .id_table = s3cmci_driver_ids,
1987 .probe = s3cmci_probe,
1988 .remove = s3cmci_remove,
1989 .shutdown = s3cmci_shutdown,
1990};
s3cmci_driver_ids定义在drivers/mmc/host/s3cmci.c文件中:
1936static struct platform_device_ids3cmci_driver_ids[] = {
1937 {
1938 .name = "s3c2410-sdi",
1939 .driver_data = 0,
1940 }, {
1941 .name = "s3c2412-sdi",
1942 .driver_data = 1,
1943 }, {
1944 .name = "s3c2440-sdi",
1945 .driver_data = 1,
1946 },
1947 { }
1948};
我们来看platform_driver s3cmci_driver 的注册,在drivers/mmc/host/s3cmci.c文件中:
1992module_platform_driver(s3cmci_driver);
module_platform_driver是一个宏,定义在include/linux/platform_device.h文件中:
203/* module_platform_driver() - Helpermacro for drivers that don't do
204 * anything special in moduleinit/exit. This eliminates a lot of
205 * boilerplate. Each module may only use this macro once, and
206 * calling it replaces module_init() andmodule_exit()
207 */
208#definemodule_platform_driver(__platform_driver) \
209 module_driver(__platform_driver, platform_driver_register, \
210 platform_driver_unregister)
宏module_driver定义在include/linux/device.h文件中,其内容如下:
1108/**
1109 * module_driver() - Helper macro fordrivers that don't do anything
1110 * special in module init/exit. Thiseliminates a lot of boilerplate.
1111 * Each module may only use this macroonce, and calling it replaces
1112 * module_init() and module_exit().
1113 *
1114 * @__driver: driver name
1115 * @__register: register function forthis driver type
1116 * @__unregister: unregister functionfor this driver type
1117 * @...: Additional arguments to bepassed to __register and __unregister.
1118 *
1119 * Use this macro to construct busspecific macros for registering
1120 * drivers, and do not use it on itsown.
1121 */
1122#define module_driver(__driver,__register, __unregister, ...) \
1123static int __init __driver##_init(void)\
1124{ \
1125 return __register(&(__driver) , ##__VA_ARGS__); \
1126} \
1127module_init(__driver##_init); \
1128static void __exit__driver##_exit(void) \
1129{ \
1130 __unregister(&(__driver) ,##__VA_ARGS__); \
1131} \
1132module_exit(__driver##_exit);
我们知道,注册s3cmci_driver的过程中,会触发s3cmci_probe函数的执行,所以先来看s3cmci_probe函数,它定义在drivers/mmc/host/s3cmci.c文件中,其内容如下:
1622static int s3cmci_probe(structplatform_device *pdev)
1623{
1624 struct s3cmci_host *host;
1625 struct mmc_host *mmc;
1626 int ret;
1627 int is2440;
1628 int i;
1629
1630 is2440 = platform_get_device_id(pdev)->driver_data;
1631
1632 mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);
1633 if (!mmc) {
1634 ret = -ENOMEM;
1635 goto probe_out;
1636 }
1637
1638 for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) {
1639 ret = gpio_request(i, dev_name(&pdev->dev));
1640 if (ret) {
1641 dev_err(&pdev->dev,"failed to get gpio %d\n", i);
1642
1643 for (i--; i >= S3C2410_GPE(5);i--)
1644 gpio_free(i);
1645
1646 goto probe_free_host;
1647 }
1648 }
1649
1650 host = mmc_priv(mmc);
1651 host->mmc = mmc;
1652 host->pdev = pdev;
1653 host->is2440 = is2440;
1654
1655 host->pdata = pdev->dev.platform_data;
1656 if (!host->pdata) {
1657 pdev->dev.platform_data = &s3cmci_def_pdata;
1658 host->pdata = &s3cmci_def_pdata;
1659 }
1660
1661 spin_lock_init(&host->complete_lock);
1662 tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long)host);
1663
1664 if (is2440) {
1665 host->sdiimsk =S3C2440_SDIIMSK;
1666 host->sdidata =S3C2440_SDIDATA;
1667 host->clk_div = 1;
1668 } else {
1669 host->sdiimsk =S3C2410_SDIIMSK;
1670 host->sdidata =S3C2410_SDIDATA;
1671 host->clk_div = 2;
1672 }
1673
1674 host->complete_what =COMPLETION_NONE;
1675 host->pio_active =XFER_NONE;
1676
1677#ifdef CONFIG_MMC_S3C_PIODMA
1678 host->dodma =host->pdata->use_dma;
1679#endif
1680
1681 host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1682 if (!host->mem) {
1683 dev_err(&pdev->dev,
1684 "failed to get io memoryregion resource.\n");
1685
1686 ret = -ENOENT;
1687 goto probe_free_gpio;
1688 }
1689
1690 host->mem = request_mem_region(host->mem->start,
1691 resource_size(host->mem), pdev->name);
1692
1693 if (!host->mem) {
1694 dev_err(&pdev->dev, "failed to request io memoryregion.\n");
1695 ret = -ENOENT;
1696 goto probe_free_gpio;
1697 }
1698
1699 host->base = ioremap(host->mem->start,resource_size(host->mem));
1700 if (!host->base) {
1701 dev_err(&pdev->dev, "failed to ioremap() io memoryregion.\n");
1702 ret = -EINVAL;
1703 goto probe_free_mem_region;
1704 }
1705
1706 host->irq = platform_get_irq(pdev, 0);
1707 if (host->irq == 0) {
1708 dev_err(&pdev->dev, "failed to get interruptresource.\n");
1709 ret = -EINVAL;
1710 goto probe_iounmap;
1711 }
1712
1713 if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
1714 dev_err(&pdev->dev, "failed to request mciinterrupt.\n");
1715 ret = -ENOENT;
1716 goto probe_iounmap;
1717 }
1718
1719 /* We get spurious interrupts even when we have set the IMSK
1720 * register to ignore everything, so use disable_irq() to make
1721 * ensure we don't lock the system with un-serviceable requests. */
1722
1723 disable_irq(host->irq);
1724 host->irq_state = false;
1725
1726 if (!host->pdata->no_detect) {
1727 ret = gpio_request(host->pdata->gpio_detect, "s3cmcidetect");
1728 if (ret) {
1729 dev_err(&pdev->dev,"failed to get detect gpio\n");
1730 goto probe_free_irq;
1731 }
1732
1733 host->irq_cd = gpio_to_irq(host->pdata->gpio_detect);
1734
1735 if (host->irq_cd >= 0) {
1736 if (request_irq(host->irq_cd,s3cmci_irq_cd,
1737 IRQF_TRIGGER_RISING |
1738 IRQF_TRIGGER_FALLING,
1739 DRIVER_NAME, host)) {
1740 dev_err(&pdev->dev,
1741 "can't get card detectirq.\n");
1742 ret = -ENOENT;
1743 goto probe_free_gpio_cd;
1744 }
1745 } else {
1746 dev_warn(&pdev->dev,
1747 "host detect has no irqavailable\n");
1748 gpio_direction_input(host->pdata->gpio_detect);
1749 }
1750 } else
1751 host->irq_cd = -1;
1752
1753 if (!host->pdata->no_wprotect) {
1754 ret = gpio_request(host->pdata->gpio_wprotect, "s3cmciwp");
1755 if (ret) {
1756 dev_err(&pdev->dev,"failed to get writeprotect\n");
1757 goto probe_free_irq_cd;
1758 }
1759
1760 gpio_direction_input(host->pdata->gpio_wprotect);
1761 }
1762
1763 /* depending on the dma state, get a dma channel to use. */
1764
1765 if (s3cmci_host_usedma(host)) {
1766 host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client,
1767 host);
1768 if (host->dma < 0) {
1769 dev_err(&pdev->dev,"cannot get DMA channel.\n");
1770 if (!s3cmci_host_canpio()) {
1771 ret = -EBUSY;
1772 goto probe_free_gpio_wp;
1773 } else {
1774 dev_warn(&pdev->dev,"falling back to PIO.\n");
1775 host->dodma = 0;
1776 }
1777 }
1778 }
1779
1780 host->clk = clk_get(&pdev->dev, "sdi");
1781 if (IS_ERR(host->clk)) {
1782 dev_err(&pdev->dev, "failed to find clock source.\n");
1783 ret = PTR_ERR(host->clk);
1784 host->clk = NULL;
1785 goto probe_free_dma;
1786 }
1787
1788 ret = clk_enable(host->clk);
1789 if (ret) {
1790 dev_err(&pdev->dev, "failed to enable clocksource.\n");
1791 goto clk_free;
1792 }
1793
1794 host->clk_rate = clk_get_rate(host->clk);
1795
1796 mmc->ops = &s3cmci_ops;
1797 mmc->ocr_avail = MMC_VDD_32_33| MMC_VDD_33_34;
1798#ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ
1799 mmc->caps =MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
1800#else
1801 mmc->caps =MMC_CAP_4_BIT_DATA;
1802#endif
1803 mmc->f_min = host->clk_rate/ (host->clk_div * 256);
1804 mmc->f_max = host->clk_rate/ host->clk_div;
1805
1806 if (host->pdata->ocr_avail)
1807 mmc->ocr_avail = host->pdata->ocr_avail;
1808
1809 mmc->max_blk_count = 4095;
1810 mmc->max_blk_size = 4095;
1811 mmc->max_req_size = 4095 *512;
1812 mmc->max_seg_size =mmc->max_req_size;
1813
1814 mmc->max_segs = 128;
1815
1816 dbg(host, dbg_debug,
1817 "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%udma:%u.\n",
1818 (host->is2440?"2440":""),
1819 host->base, host->irq, host->irq_cd, host->dma);
1820
1821 ret = s3cmci_cpufreq_register(host);
1822 if (ret) {
1823 dev_err(&pdev->dev, "failed to register cpufreq\n");
1824 goto free_dmabuf;
1825 }
1826
1827 ret = mmc_add_host(mmc);
1828 if (ret) {
1829 dev_err(&pdev->dev, "failed to add mmc host.\n");
1830 goto free_cpufreq;
1831 }
1832
1833 s3cmci_debugfs_attach(host);
1834
1835 platform_set_drvdata(pdev, mmc);
1836 dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n",mmc_hostname(mmc),
1837 s3cmci_host_usedma(host) ? "dma" : "pio",
1838 mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw");
1839
1840 return 0;
1841
1842 free_cpufreq:
1843 s3cmci_cpufreq_deregister(host);
1844
1845 free_dmabuf:
1846 clk_disable(host->clk);
1847
1848 clk_free:
1849 clk_put(host->clk);
1850
1851 probe_free_dma:
1852 if (s3cmci_host_usedma(host))
1853 s3c2410_dma_free(host->dma, &s3cmci_dma_client);
1854
1855 probe_free_gpio_wp:
1856 if (!host->pdata->no_wprotect)
1857 gpio_free(host->pdata->gpio_wprotect);
1858
1859 probe_free_gpio_cd:
1860 if (!host->pdata->no_detect)
1861 gpio_free(host->pdata->gpio_detect);
1862
1863 probe_free_irq_cd:
1864 if (host->irq_cd >= 0)
1865 free_irq(host->irq_cd, host);
1866
1867 probe_free_irq:
1868 free_irq(host->irq, host);
1869
1870 probe_iounmap:
1871 iounmap(host->base);
1872
1873 probe_free_mem_region:
1874 release_mem_region(host->mem->start, resource_size(host->mem));
1875
1876 probe_free_gpio:
1877 for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++)
1878 gpio_free(i);
1879
1880 probe_free_host:
1881 mmc_free_host(mmc);
1882
1883 probe_out:
1884 return ret;
1885}
1624行,定义structs3cmci_host指针变量host,struct s3cmci_host定义在drivers/mmc/host/s3cmci.h文件中,其内容如下:
20struct s3cmci_host {
21 struct platform_device *pdev;
22 struct s3c24xx_mci_pdata *pdata;
23 struct mmc_host *mmc;
24 struct resource *mem;
25 struct clk *clk;
26 void __iomem *base;
27 int irq;
28 int irq_cd;
29 int dma;
30
31 unsigned long clk_rate;
32 unsigned long clk_div;
33 unsigned long real_rate;
34 u8 prescaler;
35
36 int is2440;
37 unsigned sdiimsk;
38 unsigned sdidata;
39 int dodma;
40 int dmatogo;
41
42 bool irq_disabled;
43 bool irq_enabled;
44 bool irq_state;
45 int sdio_irqen;
46
47 struct mmc_request *mrq;
48 int cmd_is_stop;
49
50 spinlock_t complete_lock;
51 enum s3cmci_waitfor complete_what;
52
53 int dma_complete;
54
55 u32 pio_sgptr;
56 u32 pio_bytes;
57 u32 pio_count;
58 u32 *pio_ptr;
59#define XFER_NONE 0
60#define XFER_READ 1
61#define XFER_WRITE 2
62 u32 pio_active;
63
64 int bus_width;
65
66 char dbgmsg_cmd[301];
67 char dbgmsg_dat[301];
68 char *status;
69
70 unsigned int ccnt, dcnt;
71 struct tasklet_struct pio_tasklet;
72
73#ifdef CONFIG_DEBUG_FS
74 struct dentry *debug_root;
75 struct dentry *debug_state;
76 struct dentry *debug_regs;
77#endif
78
79#ifdef CONFIG_CPU_FREQ
80 struct notifier_block freq_transition;
81#endif
82};
可以看到,struct s3cmci_host描述了整个SDI控制器。
1625行,定义了struct mmc_host指针变量mmc,structmmc_host定义在include/linux/mmc/host.h文件中,其内容如下:
198struct mmc_host {
199 struct device *parent;
200 struct device class_dev;
201 int index;
202 const struct mmc_host_ops *ops;
203 unsigned int f_min;
204 unsigned int f_max;
205 unsigned int f_init;
206 u32 ocr_avail;
207 u32 ocr_avail_sdio; /*SDIO-specific OCR */
208 u32 ocr_avail_sd; /* SD-specific OCR */
209 u32 ocr_avail_mmc; /* MMC-specific OCR */
210 struct notifier_block pm_notify;
211 u32 max_current_330;
212 u32 max_current_300;
213 u32 max_current_180;
214
215#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
216#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
217#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
218#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
219#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
220#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
221#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
222#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
223#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
224#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
225#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
226#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
227#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
228#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
229#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
230#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
231#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
232
233 u32 caps; /* Host capabilities */
234
235#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
236#define MMC_CAP_MMC_HIGHSPEED (1 << 1) /* Can do MMC high-speed timing */
237#define MMC_CAP_SD_HIGHSPEED (1 << 2) /*Can do SD high-speed timing */
238#define MMC_CAP_SDIO_IRQ (1 << 3) /* Can signal pending SDIO IRQs */
239#define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */
240#define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */
241#define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */
242
243#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
244#define MMC_CAP_WAIT_WHILE_BUSY (1<< 9) /* Waits while card isbusy */
245#define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */
246#define MMC_CAP_1_8V_DDR (1 << 11) /* can support */
247 /* DDR mode at 1.8V */
248#define MMC_CAP_1_2V_DDR (1 << 12) /* can support */
249 /* DDR mode at 1.2V */
250#define MMC_CAP_POWER_OFF_CARD (1 << 13) /* Can power off after boot */
251#define MMC_CAP_BUS_WIDTH_TEST (1 << 14) /* CMD14/CMD19 bus width ok */
252#define MMC_CAP_UHS_SDR12 (1 << 15) /* Host supports UHS SDR12 mode */
253#define MMC_CAP_UHS_SDR25 (1 << 16) /* Host supports UHS SDR25 mode */
254#define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */
255#define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */
256#define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */
257#define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
258#define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
259#define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */
260#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
261#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
262
263 u32 caps2; /* More host capabilities */
264
265#define MMC_CAP2_BOOTPART_NOACC (1<< 0) /* Boot partition noaccess */
266#define MMC_CAP2_CACHE_CTRL (1 <<1) /* Allow cache control */
267#define MMC_CAP2_POWEROFF_NOTIFY (1<< 2) /* Notify poweroffsupported */
268#define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */
269#define MMC_CAP2_NO_SLEEP_CMD (1 << 4) /* Don't allow sleep command */
270#define MMC_CAP2_HS200_1_8V_SDR (1<< 5) /* can support */
271#define MMC_CAP2_HS200_1_2V_SDR (1<< 6) /* can support */
272#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
273 MMC_CAP2_HS200_1_2V_SDR)
274#define MMC_CAP2_BROKEN_VOLTAGE (1<< 7) /* Use the broken voltage*/
275#define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */
276#define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */
277#define MMC_CAP2_CD_ACTIVE_HIGH (1<< 10) /* Card-detect signalactive high */
278#define MMC_CAP2_RO_ACTIVE_HIGH (1<< 11) /* Write-protect signalactive high */
279#define MMC_CAP2_PACKED_RD (1 << 12) /* Allow packed read */
280#define MMC_CAP2_PACKED_WR (1 << 13) /* Allow packed write */
281#define MMC_CAP2_PACKED_CMD(MMC_CAP2_PACKED_RD | \
282 MMC_CAP2_PACKED_WR)
283#define MMC_CAP2_NO_PRESCAN_POWERUP (1<< 14) /* Don't power up beforescan */
284
285 mmc_pm_flag_t pm_caps; /* supported pm features */
286
287#ifdef CONFIG_MMC_CLKGATE
288 int clk_requests; /* internal reference counter */
289 unsigned int clk_delay; /* number of MCI clkhold cycles */
290 bool clk_gated; /* clock gated */
291 struct delayed_work clk_gate_work; /* delayed clock gate */
292 unsigned int clk_old; /* old clock value cache */
293 spinlock_t clk_lock; /* lock for clk fields */
294 struct mutex clk_gate_mutex; /* mutex for clock gating */
295 struct device_attribute clkgate_delay_attr;
296 unsigned long clkgate_delay;
297#endif
298
299 /* host specific block data */
300 unsigned int max_seg_size; /* seeblk_queue_max_segment_size */
301 unsigned short max_segs; /* see blk_queue_max_segments */
302 unsigned short unused;
303 unsigned int max_req_size; /* maximum number of bytes in one req */
304 unsigned int max_blk_size; /* maximum size ofone mmc block */
305 unsigned int max_blk_count; /* maximum numberof blocks in one req */
306 unsigned int max_discard_to; /* max. discard timeout in ms */
307
308 /* private data */
309 spinlock_t lock; /* lock for claim and bus ops */
310
311 struct mmc_ios ios; /* current io bus settings */
312 u32 ocr; /* the current OCR setting */
313
314 /* group bitfields together to minimize padding */
315 unsigned int use_spi_crc:1;
316 unsigned int claimed:1; /* host exclusivelyclaimed */
317 unsigned int bus_dead:1; /* bus has been released */
318#ifdef CONFIG_MMC_DEBUG
319 unsigned int removed:1; /* host is beingremoved */
320#endif
321
322 int rescan_disable; /*disable card detection */
323 int rescan_entered; /* usedwith nonremovable devices */
324
325 struct mmc_card *card; /* device attached to this host */
326
327 wait_queue_head_t wq;
328 struct task_struct *claimer; /* task that has host claimed */
329 int claim_cnt; /* "claim" nesting count */
330
331 struct delayed_work detect;
332 int detect_change; /* card detect flag */
333 struct mmc_slot slot;
334
335 const struct mmc_bus_ops *bus_ops; /* current bus driver */
336 unsigned int bus_refs; /* reference counter */
337
338 unsigned int sdio_irqs;
339 struct task_struct *sdio_irq_thread;
340 bool sdio_irq_pending;
341 atomic_t sdio_irq_thread_abort;
342
343 mmc_pm_flag_t pm_flags; /* requested pm features */
344
345 struct led_trigger *led; /* activity led */
346
347#ifdef CONFIG_REGULATOR
348 bool regulator_enabled;/* regulator state */
349#endif
350 struct mmc_supply supply;
351
352 struct dentry *debugfs_root;
353
354 struct mmc_async_req *areq; /* active async req */
355 struct mmc_context_info context_info; /* async synchronization info */
356
357#ifdef CONFIG_FAIL_MMC_REQUEST
358 struct fault_attr fail_mmc_request;
359#endif
360
361 unsigned int actual_clock; /* Actual HC clockrate */
362
363 unsigned int slotno; /*used for sdio acpi binding */
364
365 unsigned long private[0]____cacheline_aligned;
366};
1630行,调用platform_get_device_id宏,取得处理器类型,该宏定义在include/linux/platform_device.h文件中:
39#define platform_get_device_id(pdev) ((pdev)->id_entry)
但是,回忆一下我们注册的platform_device s3c_device_sdi,我们并没有初始化platform_device.id_entry成员,那么这里的platform_get_device_id宏返回值是NULL吗?如果不是NULL,应该是什么值呢?
答案是platform_get_device_id(pdev)->driver_data返回值为1。
原因是s3cmci_driver.id_table被设置为s3cmci_driver_ids。s3cmci_driver_ids定义在drivers/mmc/host/s3cmci.c文件中:
1936static struct platform_device_ids3cmci_driver_ids[] = {
1937 {
1938 .name = "s3c2410-sdi",
1939 .driver_data = 0,
1940 }, {
1941 .name = "s3c2412-sdi",
1942 .driver_data = 1,
1943 }, {
1944 .name = "s3c2440-sdi",
1945 .driver_data = 1,
1946 },
1947 { }
1948};
struct platform_device_id定义在include/linux/mod_devicetable.h文件中:
482struct platform_device_id {
483 char name[PLATFORM_NAME_SIZE];
484 kernel_ulong_t driver_data;
485};
platform_driver.id_table是platform_driver所支持的设备列表。可以看到,s3cmci_driver支持3种设备,分别是"s3c2410-sdi"、"s3c2412-sdi"和"s3c2440-sdi"。对于"s3c2410-sdi",其driver_data成员值为0,对于其它两种设备,它们的driver_data成员值为1。
当调用platform_driver_register函数注册s3cmci_driver时,s3cmci_driver.driver.bus被设置为 platform_bus_type,structbus_type platform_bus_type定义在drivers/base/platform.c文件中:
895structbus_type platform_bus_type = {
896 .name = "platform",
897 .dev_attrs = platform_dev_attrs,
898 .match = platform_match,
899 .uevent = platform_uevent,
900 .pm =&platform_dev_pm_ops,
901};
根据《Linux设备模型分析之device_driver(基于3.10.1内核)》一文对Linux设备模型的分析,在s3cmci_driver.probe函数被调用执行之前,platform_bus_type.match即platform_match首先会被调用执行。platform_match函数定义在drivers/base/platform.c文件中:
710/**
711* platform_match - bind platform device to platform driver.
712* @dev: device.
713* @drv: driver.
714*
715* Platform device IDs are assumed to be encoded like this:
716* "", where is a shortdescription of the type of
717* device, like "pci" or "floppy", and isthe enumerated
718* instance of the device, like '0' or '42'. Driver IDs are simply
719* "". So, extractthe from the platform_device structure,
720* and compare it against the name of the driver. Return whether they match
721* or not.
722*/
723static int platform_match(struct device*dev, struct device_driver *drv)
724{
725 struct platform_device *pdev = to_platform_device(dev);
726 struct platform_driver *pdrv = to_platform_driver(drv);
727
728 /* Attempt an OF style match first */
729 if (of_driver_match_device(dev, drv))
730 return 1;
731
732 /* Then try ACPI style match */
733 if (acpi_driver_match_device(dev, drv))
734 return 1;
735
736 /* Then try to match against the id table */
737 if (pdrv->id_table)
738 return platform_match_id(pdrv->id_table, pdev) != NULL;
739
740 /* fall-back to driver name match */
741 return (strcmp(pdev->name, drv->name) == 0);
742}
737行,如果pdrv->id_table不为空,则调用platform_match_id函数。而我们的platform_drivers3cmci_driver.id_table被设置为s3cmci_driver_ids,所以platform_match_id函数会被执行。
platform_match_id函数定义在drivers/base/platform.c文件中:
696staticconst struct platform_device_id *platform_match_id(
697 const struct platform_device_id *id,
698 struct platform_device *pdev)
699{
700 while (id->name[0]) {
701 if (strcmp(pdev->name, id->name)== 0) {
702 pdev->id_entry = id;
703 return id;
704 }
705 id++;
706 }
707 return NULL;
708}
可以看到,在701行,如果platform_device.name与platform_device_id.name相同,则将id赋值给pdev->id_entry。
回到我们的platform_driver s3cmci_driver和platform_device s3c_device_sdi,s3c_device_sdi.name被初始化为"s3c2410-sdi",但是因为我们基于的平台是Mini2440,处理器是S3C2440,所以s3c244x_map_io函数会被调用,至于什么时候该函数会被调用我还没有搞清楚,呵呵!该函数定义在arch/arm/mach-s3c24xx/s3c244x.c文件中:
63void__init s3c244x_map_io(void)
64{
65 /* register our io-tables */
66
67 iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
68
69 /*rename any peripherals used differing from the s3c2410 */
70
71 s3c_device_sdi.name ="s3c2440-sdi";
72 s3c_device_i2c0.name ="s3c2440-i2c";
73 s3c_nand_setname("s3c2440-nand");
74 s3c_device_ts.name = "s3c2440-ts";
75 s3c_device_usbgadget.name = "s3c2440-usbgadget";
76}
71行,将s3c_device_sdi.name设置为"s3c2440-sdi"
而s3cmci_driver.id_table被设置为s3cmci_driver_ids,s3cmci_driver_ids[2].name同样为"s3c2440-sdi",所以,虽然s3c_device_sdi.id_entry在初始化时没有赋值,但是在platform_match_id函数中,它会被赋值为s3cmci_driver_ids[2]。
现在我们可以回到s3cmci_probe函数了:
1630行,经过前面的分析,我们知道platform_get_device_id(pdev)->driver_data的值其实就是s3cmci_driver_ids[2].driver_data,其值为1。所以,对于Mini2440平台,is2440变量被赋值为1。
1632行,调用mmc_alloc_host函数为struct mmc_host指针变量mmc分配内存空间并初始化。注意mmc_alloc_host的第一个参数表示除了mmc_host结构体外,还要额外多分配的内存空间大小,所以这里分配的内存大小是struct mmc_host加上struct s3cmci_host。
mmc_alloc_host函数定义在drivers/mmc/core/host.c文件中,其内容如下:
420/**
421 * mmc_alloc_host - initialise the per-host structure.
422 * @extra: sizeof private data structure
423 * @dev: pointer to host device model structure
424 *
425 * Initialise the per-host structure.
426 */
427struct mmc_host *mmc_alloc_host(intextra, struct device *dev)
428{
429 int err;
430 struct mmc_host *host;
431
432 host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
433 if (!host)
434 return NULL;
435
436 /* scanning will be enabled when we're ready */
437 host->rescan_disable = 1;
438 idr_preload(GFP_KERNEL);
439 spin_lock(&mmc_host_lock);
440 err = idr_alloc(&mmc_host_idr, host, 0, 0, GFP_NOWAIT);
441 if (err >= 0)
442 host->index = err;
443 spin_unlock(&mmc_host_lock);
444 idr_preload_end();
445 if (err < 0)
446 goto free;
447
448 dev_set_name(&host->class_dev, "mmc%d",host->index);
449
450 host->parent = dev;
451 host->class_dev.parent = dev;
452 host->class_dev.class = &mmc_host_class;
453 device_initialize(&host->class_dev);
454
455 mmc_host_clk_init(host);
456
457 mutex_init(&host->slot.lock);
458 host->slot.cd_irq = -EINVAL;
459
460 spin_lock_init(&host->lock);
461 init_waitqueue_head(&host->wq);
462 INIT_DELAYED_WORK(&host->detect, mmc_rescan);
463#ifdef CONFIG_PM
464 host->pm_notify.notifier_call = mmc_pm_notify;
465#endif
466
467 /*
468 * By default, hosts do not support SGIO or large requests.
469 * They have to set these according to their abilities.
470 */
471 host->max_segs = 1;
472 host->max_seg_size = PAGE_CACHE_SIZE;
473
474 host->max_req_size = PAGE_CACHE_SIZE;
475 host->max_blk_size = 512;
476 host->max_blk_count = PAGE_CACHE_SIZE / 512;
477
478 return host;
479
480free:
481 kfree(host);
482 return NULL;
483}
回到s3cmci_probe函数:
1638-1648行,通过gpio_request函数申请获取GPE5-GPE10。从Mini2440原理图可以看出,Mini2440SDI使用的GPE7-GPE10作为4根数据信号线,使用GPE6作为命令信号线,使用GPE5作为时钟信号线。另外,使用GPG8的外部中断功能来作SD卡的插拨检测,使用GPH8来判断SD卡是否有写保护。
1650行,通过调用mmc_priv(mmc)取得s3cmci_host指针变量host。
下面的内容就是初始化host的各个成员变量。
1681行,调用platform_get_resource(pdev,IORESOURCE_MEM, 0)取得IORESOURCE_MEM类型资源。IORESOURCE_MEM宏定义在include/linux/ioport.h文件中:
32#define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */
33#define IORESOURCE_MEM 0x00000200
34#define IORESOURCE_REG 0x00000300 /* Register offsets */
35#define IORESOURCE_IRQ 0x00000400
36#define IORESOURCE_DMA 0x00000800
37#define IORESOURCE_BUS 0x00001000
platform_get_resource函数定义在drivers/base/platform.c文件中:
59/**
60* platform_get_resource - get a resource for a device
61* @dev: platform device
62* @type: resource type
63* @num: resource index
64*/
65struct resource *platform_get_resource(struct platform_device *dev,
66 unsigned int type, unsigned int num)
67{
68 int i;
69
70 for (i = 0; i num_resources; i++) {
71 struct resource *r =&dev->resource[i];
72
73 if (type ==resource_type(r) && num-- == 0)
74 return r;
75 }
76 return NULL;
77}
resource_type定义在include/linux/ioport.h文件中:
168static inline unsigned longresource_type(const struct resource *res)
169{
170 return res->flags & IORESOURCE_TYPE_BITS;
171}
回忆一下,Mini2440的资源文件s3c_sdi_resource定义在arch/arm/plat-samsung/devs.c文件中:
1167static struct resources3c_sdi_resource[] = {
1168 [0] = DEFINE_RES_MEM(S3C24XX_PA_SDI, S3C24XX_SZ_SDI),
1169 [1] = DEFINE_RES_IRQ(IRQ_SDI),
1170};
宏S3C24XX_PA_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:
155#define S3C24XX_PA_SDI S3C2410_PA_SDI
宏S3C2410_PA_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:
105#define S3C2410_PA_SDI (0x5A000000)
0x5A000000是S3C2440 SDICON寄存器的地址。
宏S3C24XX_SZ_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:
61#define S3C24XX_SZ_SDI SZ_1M
宏SZ_1M定义在include/linux/sizes.h文件中:
33#define SZ_1M 0x00100000
所以s3cmci_probe函数1681行,platform_get_resource(pdev, IORESOURCE_MEM, 0)函数返回的就是s3c_sdi_resource[0]。
1690-1691行,调用request_mem_region(host->mem->start,resource_size(host->mem), pdev->name)函数,该函数用于获取参数指定的内存空间。request_mem_region函数定义在include/linux/ioport.h文件中:
177#define request_mem_region(start,n,name)__request_region(&iomem_resource, (start), (n), (name), 0)
__request_region定义在kernel/resource.c文件中:
931/**
932* __request_region - create a new busy resource region
933* @parent: parent resource descriptor
934* @start: resource start address
935* @n: resource region size
936* @name: reserving caller's ID string
937* @flags: IO resource flags
938*/
939struct resource * __request_region(structresource *parent,
940 resource_size_t start,resource_size_t n,
941 const char *name, int flags)
942{
943 DECLARE_WAITQUEUE(wait, current);
944 struct resource *res = alloc_resource(GFP_KERNEL);
945
946 if (!res)
947 return NULL;
948
949 res->name = name;
950 res->start = start;
951 res->end = start + n - 1;
952 res->flags = IORESOURCE_BUSY;
953 res->flags |= flags;
954
955 write_lock(&resource_lock);
956
957 for (;;) {
958 struct resource *conflict;
959
960 conflict = __request_resource(parent, res);
961 if (!conflict)
962 break;
963 if (conflict != parent) {
964 parent = conflict;
965 if (!(conflict->flags &IORESOURCE_BUSY))
966 continue;
967 }
968 if (conflict->flags & flags & IORESOURCE_MUXED) {
969 add_wait_queue(&muxed_resource_wait, &wait);
970 write_unlock(&resource_lock);
971 set_current_state(TASK_UNINTERRUPTIBLE);
972 schedule();
973 remove_wait_queue(&muxed_resource_wait, &wait);
974 write_lock(&resource_lock);
975 continue;
976 }
977 /* Uhhuh, that didn't work out.. */
978 free_resource(res);
979 res = NULL;
980 break;
981 }
982 write_unlock(&resource_lock);
983 return res;
984}
1699行,调用ioremap(host->mem->start,resource_size(host->mem))宏,该宏完成物理内存到虚拟内存的映射。ioremap宏定义在arch/arm/include/asm/io.h文件中:
328#define ioremap(cookie,size) __arm_ioremap((cookie), (size),MT_DEVICE)
__arm_ioremap函数定义在arch/arm/mm/ioremap.c文件中:
374void __iomem *
375__arm_ioremap(unsigned long phys_addr,size_t size, unsigned int mtype)
376{
377 return arch_ioremap_caller(phys_addr, size, mtype,
378 __builtin_return_address(0));
379}
1706行,调用platform_get_irq函数获取设备中断。platform_get_irq函数定义在drivers/base/platform.c文件中:
80/**
81* platform_get_irq - get an IRQ for a device
82* @dev: platform device
83* @num: IRQ number index
84*/
85int platform_get_irq(struct platform_device *dev, unsigned int num)
86{
87#ifdef CONFIG_SPARC
88 /* sparc does not have irqsrepresented as IORESOURCE_IRQ resources */
89 if (!dev || num >=dev->archdata.num_irqs)
90 return -ENXIO;
91 returndev->archdata.irqs[num];
92#else
93 struct resource *r =platform_get_resource(dev, IORESOURCE_IRQ, num);
94
95 return r ? r->start :-ENXIO;
96#endif
97}
1713行,调用request_irq(host->irq,s3cmci_irq, 0, DRIVER_NAME, host)申请中断,中断处理函数是s3cmci_irq。
1723行,调用disable_irq禁用中断。
1726-1751行,处理SD卡探测相关内容。
1753-1761行,处理SD卡写保护相关内容。
1765-1778行,处理DMA相关内容。
1780-1794行,处理时钟相关内容。
1796-1814行,初始化mmc。
需要注意的是1796行,设置mmc->ops为s3cmci_ops,s3cmci_ops定义在drivers/mmc/host/s3cmci.c文件中:
1427static struct mmc_host_ops s3cmci_ops ={
1428 .request = s3cmci_request,
1429 .set_ios = s3cmci_set_ios,
1430 .get_ro = s3cmci_get_ro,
1431 .get_cd = s3cmci_card_present,
1432 .enable_sdio_irq = s3cmci_enable_sdio_irq,
1433};
1821行,调用s3cmci_cpufreq_register(host),提供对变频的支持。
1827行,调用mmc_add_host(mmc),向core层注册mmc_host。
1833行,调用s3cmci_debugfs_attach(host)创建debugfs相关节点。
至此,s3cmci_probe函数我们就分析完了。