sd卡driver最关键的是host部分,各个厂商需要根据自己平台的特性,定制自己的host
部分,当然内核也会提供一个专用的描述结构,在这里就是:
struct mmc_host {
171 struct device *parent;
172 struct device class_dev;
173 int index; //编号
174 const struct mmc_host_ops *ops; //特定控制器的操作函数,这个很重要
175 unsigned int f_min;
176 unsigned int f_max;
177 unsigned int f_init;
178 u32 ocr_avail; //支持电压范围
179 u32 ocr_avail_sdio; /* SDIO-specific OCR */
180 u32 ocr_avail_sd; /* SD-specific OCR */
181 u32 ocr_avail_mmc; /* MMC-specific OCR */
182 struct notifier_block pm_notify;
183
184 #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 – 1.95 */
185 #define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
186 #define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
187 #define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
188 #define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
189 #define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
190 #define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
191 #define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
192 #define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
193 #define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
194 #define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
195 #define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
196 #define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
197 #define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
198 #define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
199 #define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
200 #define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
201
202 unsigned long caps; /* Host capabilities */
203
204 #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
205 #define MMC_CAP_MMC_HIGHSPEED (1 << 1) /* Can do MMC high-speed timing */
206 #define MMC_CAP_SD_HIGHSPEED (1 << 2) /* Can do SD high-speed timing */
207 #define MMC_CAP_SDIO_IRQ (1 << 3) /* Can signal pending SDIO IRQs */
208 #define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */
209 #define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */
210 #define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */
211 #define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */
212 #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
213 #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */
214 #define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */
215 #define MMC_CAP_1_8V_DDR (1 << 11) /* can support */
216 /* DDR mode at 1.8V */
217 #define MMC_CAP_1_2V_DDR (1 << 12) /* can support */
218 /* DDR mode at 1.2V */
219 #define MMC_CAP_POWER_OFF_CARD (1 << 13) /* Can power off after boot */
220 #define MMC_CAP_BUS_WIDTH_TEST (1 << 14) /* CMD14/CMD19 bus width ok */
221 #define MMC_CAP_UHS_SDR12 (1 << 15) /* Host supports UHS SDR12 mode */
222 #define MMC_CAP_UHS_SDR25 (1 << 16) /* Host supports UHS SDR25 mode */
223 #define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */
224 #define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */
225 #define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */
226 #define MMC_CAP_SET_XPC_330 (1 << 20) /* Host supports >150mA current at 3.3V */
227 #define MMC_CAP_SET_XPC_300 (1 << 21) /* Host supports >150mA current at 3.0V */
228 #define MMC_CAP_SET_XPC_180 (1 << 22) /* Host supports >150mA current at 1.8V */
229 #define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
230 #define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
231 #define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */
232 #define MMC_CAP_MAX_CURRENT_200 (1 << 26) /* Host max current limit is 200mA */
233 #define MMC_CAP_MAX_CURRENT_400 (1 << 27) /* Host max current limit is 400mA */
234 #define MMC_CAP_MAX_CURRENT_600 (1 << 28) /* Host max current limit is 600mA */
235 #define MMC_CAP_MAX_CURRENT_800 (1 << 29) /* Host max current limit is 800mA */
236 #define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
237 #define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
238
239 unsigned int caps2; /* More host capabilities */
240
241 #define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
242 #define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */
243 #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2) /* Notify poweroff supported */
244 #define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don’t work */
245
246 mmc_pm_flag_t pm_caps; /* supported pm features */
247 unsigned int power_notify_type;
248 #define MMC_HOST_PW_NOTIFY_NONE 0
249 #define MMC_HOST_PW_NOTIFY_SHORT 1
250 #define MMC_HOST_PW_NOTIFY_LONG 2
251
252 #ifdef CONFIG_MMC_CLKGATE
253 int clk_requests; /* internal reference counter */
254 unsigned int clk_delay; /* number of MCI clk hold cycles */
255 bool clk_gated; /* clock gated */
256 struct work_struct clk_gate_work; /* delayed clock gate */
257 unsigned int clk_old; /* old clock value cache */
258 spinlock_t clk_lock; /* lock for clk fields */
259 struct mutex clk_gate_mutex; /* mutex for clock gating */
260 #endif
261
262 /* host specific block data */
263 unsigned int max_seg_size; /* see blk_queue_max_segment_size */
264 unsigned short max_segs; /* see blk_queue_max_segments */
265 unsigned short unused;
266 unsigned int max_req_size; /* maximum number of bytes in one req */
267 unsigned int max_blk_size; /* maximum size of one mmc block */
268 unsigned int max_blk_count; /* maximum number of blocks in one req */
269 unsigned int max_discard_to; /* max. discard timeout in ms */
270
271 /* private data */
272 spinlock_t lock; /* lock for claim and bus ops */
273
274 struct mmc_ios ios; /* current io bus settings */
275 u32 ocr; /* the current OCR setting */
276
277 /* group bitfields together to minimize padding */
278 unsigned int use_spi_crc:1;
279 unsigned int claimed:1; /* host exclusively claimed */
280 unsigned int bus_dead:1; /* bus has been released */
281 #ifdef CONFIG_MMC_DEBUG
282 unsigned int removed:1; /* host is being removed */
283 #endif
284
285 /* Only used with MMC_CAP_DISABLE */
286 int enabled; /* host is enabled */
287 int rescan_disable; /* disable card detection */
288 int nesting_cnt; /* “enable” nesting count */
289 int en_dis_recurs; /* detect recursion */
290 unsigned int disable_delay; /* disable delay in msecs */
291 struct delayed_work disable; /* disabling work */
292
293 struct mmc_card *card; /* device attached to this host */
294
295 wait_queue_head_t wq;
296 struct task_struct *claimer; /* task that has host claimed */
297 int claim_cnt; /* “claim” nesting count */
298
299 struct delayed_work detect;
300
301 const struct mmc_bus_ops *bus_ops; /* current bus driver */
302 unsigned int bus_refs; /* reference counter */
303
304 unsigned int sdio_irqs;
305 struct task_struct *sdio_irq_thread;
306 atomic_t sdio_irq_thread_abort;
307
308 mmc_pm_flag_t pm_flags; /* requested pm features */
309
310 #ifdef CONFIG_LEDS_TRIGGERS
311 struct led_trigger *led; /* activity led */
312 #endif
313
314 #ifdef CONFIG_REGULATOR
315 bool regulator_enabled; /* regulator state */
316 #endif
317
318 struct dentry *debugfs_root;
319
320 struct mmc_async_req *areq; /* active async req */
321
322 #ifdef CONFIG_FAIL_MMC_REQUEST
323 struct fault_attr fail_mmc_request;
324 #endif
325
326 unsigned long private[0] ____cacheline_aligned;
327 };
#厂商不会直接拿这个结构体来用,一般都是在这基础上封装出自己的结构,还是拿满街都是的mini来看吧,
struct s3cmci_host {
struct platform_device *pdev;
struct s3c24xx_mci_pdata *pdata;
struct mmc_host *mmc; //内嵌标准的结构
struct resource *mem;
struct clk *clk; 、
void __iomem *base;
int irq;
int irq_cd;
int dma; //dma通道
unsigned long clk_rate; //频率
unsigned long clk_div; //分频
unsigned long real_rate;
u8 prescaler;
int is2440; //平台判断
unsigned sdiimsk;
unsigned sdidata;
int dodma;
int dmatogo;
bool irq_disabled; //irq相关
bool irq_enabled;
bool irq_state;
int sdio_irqen;
struct mmc_request *mrq;
int cmd_is_stop;
spinlock_t complete_lock;
enum s3cmci_waitfor complete_what;
int dma_complete;
u32 pio_sgptr;
u32 pio_bytes;
u32 pio_count;
u32 *pio_ptr;
#define XFER_NONE 0
#define XFER_READ 1
#define XFER_WRITE 2
u32 pio_active;
int bus_width;
char dbgmsg_cmd[301];
char dbgmsg_dat[301];
char *status;
unsigned int ccnt, dcnt;
struct tasklet_struct pio_tasklet;
#ifdef CONFIG_DEBUG_FS
struct dentry *debug_root;
struct dentry *debug_state;
struct dentry *debug_regs;
#endif
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
};#看一下host的注册过程吧,怎么进入mmc框架的,
#host对应的文件driver/mmc/host/s3cmci.c
#host的初始化
static int __init s3cmci_init(void)
{
return platform_driver_register(&s3cmci_driver);
}
static struct platform_driver s3cmci_driver = {
.driver = {
.name = “s3c-sdi”,
.owner = THIS_MODULE,
.pm = s3cmci_pm_ops,
},
.id_table = s3cmci_driver_ids, //支持的列表
.probe = s3cmci_probe,
.remove = __devexit_p(s3cmci_remove),
.shutdown = s3cmci_shutdown,
};
#有了driver,把设备也翻出来,
#mach-mini2440.c
/* MMC/SD */
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_rtc,
&s3c_device_usbgadget,
&mini2440_device_eth,
&mini2440_led1,
&mini2440_led2,
&mini2440_led3,
&mini2440_led4,
&mini2440_button_device,
&s3c_device_nand,
&s3c_device_sdi,
&s3c_device_iis,
&uda1340_codec,
&mini2440_audio,
&samsung_asoc_dma,
};
struct platform_device s3c_device_sdi = {
.name = “s3c2410-sdi”,
.id = -1,
.num_resources = ARRAY_SIZE(s3c_sdi_resource),
.resource = s3c_sdi_resource,
};
static struct resource s3c_sdi_resource[] = {
[0] = DEFINE_RES_MEM(S3C24XX_PA_SDI, S3C24XX_SZ_SDI),
[1] = DEFINE_RES_IRQ(IRQ_SDI),
};
#匹配后会调用probe,
#即:
static int __devinit s3cmci_probe(struct platform_device *pdev)
{
struct s3cmci_host *host; //封装的结构体
struct mmc_host *mmc; //标准mmc host
int ret;
int is2440;
int i;
is2440 = platform_get_device_id(pdev)->driver_data; //得到id号,判断具体平台
mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); //为host结构分配空间,id号,加入sys文件系统,还有个很重要的操作
if (!mmc) { //初始化了工作队列,mmc_rescan.
ret = -ENOMEM;
goto probe_out;
}
for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) { //特定于平台的gpio配置
ret = gpio_request(i, dev_name(&pdev->dev));
if (ret) {
dev_err(&pdev->dev, “failed to get gpio %d\n”, i);
for (i–; i >= S3C2410_GPE(5); i–)
gpio_free(i);
goto probe_free_host;
}
}
host = mmc_priv(mmc);
host->mmc = mmc;
host->pdev = pdev;
host->is2440 = is2440;
host->pdata = pdev->dev.platform_data;
if (!host->pdata) {
pdev->dev.platform_data = &s3cmci_def_pdata;
host->pdata = &s3cmci_def_pdata;
}
spin_lock_init(&host->complete_lock);
tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
if (is2440) {
host->sdiimsk = S3C2440_SDIIMSK;
host->sdidata = S3C2440_SDIDATA;
host->clk_div = 1;
} else {
host->sdiimsk = S3C2410_SDIIMSK;
host->sdidata = S3C2410_SDIDATA;
host->clk_div = 2;
}
host->complete_what = COMPLETION_NONE;
host->pio_active = XFER_NONE;
#ifdef CONFIG_MMC_S3C_PIODMA
host->dodma = host->pdata->use_dma;
#endif
host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); //io资源映射以及配置
if (!host->mem) {
dev_err(&pdev->dev,
“failed to get io memory region resouce.\n”);
ret = -ENOENT;
goto probe_free_gpio;
}
host->mem = request_mem_region(host->mem->start,
resource_size(host->mem), pdev->name);
if (!host->mem) {
dev_err(&pdev->dev, “failed to request io memory region.\n”);
ret = -ENOENT;
goto probe_free_gpio;
}
host->base = ioremap(host->mem->start, resource_size(host->mem));
if (!host->base) {
dev_err(&pdev->dev, “failed to ioremap() io memory region.\n”);
ret = -EINVAL;
goto probe_free_mem_region;
}
host->irq = platform_get_irq(pdev, 0); //中断的申请及配置,这个是控制器
//的中断信息,如命令成功与否,crc校验信息错误
if (host->irq == 0) {
dev_err(&pdev->dev, “failed to get interrupt resouce.\n”);
ret = -EINVAL;
goto probe_iounmap;
}
if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
dev_err(&pdev->dev, “failed to request mci interrupt.\n”);
ret = -ENOENT;
goto probe_iounmap;
}
/* We get spurious interrupts even when we have set the IMSK
* register to ignore everything, so use disable_irq() to make
* ensure we don’t lock the system with un-serviceable requests. */
disable_irq(host->irq); //先disable该中断
host->irq_state = false;
if (!host->pdata->no_detect) { //插拔卡探测中断
ret = gpio_request(host->pdata->gpio_detect, “s3cmci detect”);
if (ret) {
dev_err(&pdev->dev, “failed to get detect gpio\n”);
goto probe_free_irq;
}
host->irq_cd = gpio_to_irq(host->pdata->gpio_detect);
if (host->irq_cd >= 0) { //必须双延触发,假如插入后为高,拔出则为低
if (request_irq(host->irq_cd, s3cmci_irq_cd,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
DRIVER_NAME, host)) {
dev_err(&pdev->dev,
“can’t get card detect irq.\n”);
ret = -ENOENT;
goto probe_free_gpio_cd;
}
} else {
dev_warn(&pdev->dev,
“host detect has no irq available\n”);
gpio_direction_input(host->pdata->gpio_detect);
}
} else
host->irq_cd = -1;
//写保护???
if (!host->pdata->no_wprotect) {
ret = gpio_request(host->pdata->gpio_wprotect, “s3cmci wp”);
if (ret) {
dev_err(&pdev->dev, “failed to get writeprotect\n”);
goto probe_free_irq_cd;
}
gpio_direction_input(host->pdata->gpio_wprotect);
}
/* depending on the dma state, get a dma channel to use. */
//dma通道请求
if (s3cmci_host_usedma(host)) {
host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client,
host);
if (host->dma < 0) {
dev_err(&pdev->dev, “cannot get DMA channel.\n”);
if (!s3cmci_host_canpio()) {
ret = -EBUSY;
goto probe_free_gpio_wp;
} else {
dev_warn(&pdev->dev, “falling back to PIO.\n”);
host->dodma = 0;
}
}
}
//io clk
host->clk = clk_get(&pdev->dev, “sdi”);
if (IS_ERR(host->clk)) {
dev_err(&pdev->dev, “failed to find clock source.\n”);
ret = PTR_ERR(host->clk);
host->clk = NULL;
goto probe_free_dma;
}
//使能
ret = clk_enable(host->clk);
if (ret) {
dev_err(&pdev->dev, “failed to enable clock source.\n”);
goto clk_free;
}
host->clk_rate = clk_get_rate(host->clk);
mmc->ops = &s3cmci_ops; //mmc操作函数,重要
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; //支持电压范围,预定义值
#ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
#else
mmc->caps = MMC_CAP_4_BIT_DATA;
#endif
mmc->f_min = host->clk_rate / (host->clk_div * 256);
mmc->f_max = host->clk_rate / host->clk_div;
if (host->pdata->ocr_avail)
mmc->ocr_avail = host->pdata->ocr_avail; //平台相关自己设定值
mmc->max_blk_count = 4095; //块数量,大小
mmc->max_blk_size = 4095;
mmc->max_req_size = 4095 * 512;
mmc->max_seg_size = mmc->max_req_size;
mmc->max_segs = 128;
dbg(host, dbg_debug,
“probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n”,
(host->is2440?”2440″:””),
host->base, host->irq, host->irq_cd, host->dma);
ret = s3cmci_cpufreq_register(host); //通知链,状态改变
if (ret) {
dev_err(&pdev->dev, “failed to register cpufreq\n”);
goto free_dmabuf;
}
ret = mmc_add_host(mmc); //把host加入,每个平台都会调用该函数把host真正加入linux子系统,下文会介绍
if (ret) {
dev_err(&pdev->dev, “failed to add mmc host.\n”);
goto free_cpufreq;
}
s3cmci_debugfs_attach(host);
platform_set_drvdata(pdev, mmc);
dev_info(&pdev->dev, “%s – using %s, %s SDIO IRQ\n”, mmc_hostname(mmc),
s3cmci_host_usedma(host) ? “dma” : “pio”,
mmc->caps & MMC_CAP_SDIO_IRQ ? “hw” : “sw”);
return 0;
free_cpufreq:
s3cmci_cpufreq_deregister(host);
free_dmabuf:
clk_disable(host->clk);
clk_free:
clk_put(host->clk);
probe_free_dma:
if (s3cmci_host_usedma(host))
s3c2410_dma_free(host->dma, &s3cmci_dma_client);
probe_free_gpio_wp:
if (!host->pdata->no_wprotect)
gpio_free(host->pdata->gpio_wprotect);
probe_free_gpio_cd:
if (!host->pdata->no_detect)
gpio_free(host->pdata->gpio_detect);
probe_free_irq_cd:
if (host->irq_cd >= 0)
free_irq(host->irq_cd, host);
probe_free_irq:
free_irq(host->irq, host);
probe_iounmap:
iounmap(host->base);
probe_free_mem_region:
release_mem_region(host->mem->start, resource_size(host->mem));
probe_free_gpio:
for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++)
gpio_free(i);
probe_free_host:
mmc_free_host(mmc);
probe_out:
return ret;
}
#重点是mmc_add_host函数,
#drivers/mmc/core/host.c
/**
* mmc_add_host – initialise host hardware
* @host: mmc host
*
* Register the host with the driver model. The host must be
* prepared to start servicing requests before this function
* completes.
*/
int mmc_add_host(struct mmc_host *host)
{
int err;
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
!host->ops->enable_sdio_irq);
err = device_add(&host->class_dev); //加入bus
if (err)
return err;
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
//用于显示卡状态的led
#ifdef CONFIG_DEBUG_FS
mmc_add_host_debugfs(host);
#endif
mmc_start_host(host);
register_pm_notifier(&host->pm_notify); //加入块设备通知链
return 0;
}
EXPORT_SYMBOL(mmc_add_host);
#继续mmc_start_host(host);
/drivers/mmc/core/core.c
void mmc_start_host(struct mmc_host *host)
{
mmc_power_off(host); //host power off
mmc_detect_change(host, 0); //detect
}
这两个函数都很重要,放到下文来说明。
总结:概要的说明了添加一个mmc host的过程,下文(见 http://www.linuxidc.com/Linux/2012-02/53024.htm)会重点分析一些很重要的函数,包括mmc_rescan.
Thanks
Linux设备模型之mmc,sd子系统<一>
转载请注明出处:服务器评测 » Linux设备模型之mmc,sd子系统<一>