作者:刘昊昱
博客: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* "<name><instance>", where <name> is a shortdescription of the type of 717* device, like "pci" or "floppy", and <instance> isthe enumerated 718* instance of the device, like '0' or '42'. Driver IDs are simply 719* "<name>". So, extractthe <name> 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 <dev->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函数我们就分析完了。