📄 sdio.c
字号:
/* * linux/drivers/mmc/core/sdio.c * * Copyright (C) 2007 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/err.h>#include <linux/mmc/host.h>#include <linux/mmc/card.h>#include <linux/mmc/sdio.h>#include "core.h"#include "sysfs.h"#include "sdio_ops.h"#include "mmc_ops.h"extern int read_cia,sdioresp;struct mmc_card *sdiocard;/* * Allocate a new SDIO card, and assign a RCA. */static struct mmc_card *sdio_alloc_card(struct mmc_host *host, int io_rca){ struct mmc_card *card; card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); if (!card) return ERR_PTR(-ENOMEM); mmc_init_card(card, host); card->rca = io_rca; card->raw_cid[0]=io_rca; card->raw_cid[1]=io_rca; card->raw_cid[2]=io_rca; card->raw_cid[3]=io_rca; return card;}/* * Card detection callback from host. */static void sdio_detect(struct mmc_host *host){ int err; BUG_ON(!host); BUG_ON(!host->card); mmc_claim_host(host); /* * Just check if our card has been removed. */ err = io_select_card(host); mmc_release_host(host); if (err != MMC_ERR_NONE) { mmc_remove_card(host->card); host->card = NULL; mmc_claim_host(host); mmc_detach_bus(host); mmc_release_host(host); }}/* * Host is being removed. Free up the current card. */static void sdio_remove(struct mmc_host *host){ BUG_ON(!host); BUG_ON(!host->card); mmc_remove_card(host->card); host->card = NULL;}static const struct mmc_bus_ops sdio_ops = { .remove = sdio_remove, .detect = sdio_detect, .suspend = NULL, .resume = NULL,};/* * Read the CCCR register contents of an I/O card. */static void io_read_cia(struct mmc_host *host){ int sdio_rev,io_cardtype,io_buswidth,io_cardcap; read_cia = 1; sdioresp = io_select_card(host); host->ios.bus_width = MMC_BUS_WIDTH_1; if (sdioresp == 0) { if (host->caps & MMC_CAP_4_BIT_DATA || host->caps & MMC_CAP_8_BIT_DATA) { io_cardcap = io_rw_direct(SDIO_READ, SDIO_FUNCTION_0, 0, CCCR_CARD_CAPACITY, 0x0); if (io_cardcap & (1<<6)) { host->ios.clock = host->f_min; host->ops->set_ios(host, &host->ios); if (io_cardcap & (1<<7)) { io_buswidth = io_rw_direct(SDIO_READ, SDIO_FUNCTION_0, 0, CCCR_BUS_INTF_CONTROL, 0x0); io_buswidth |= 0x2; io_rw_direct(SDIO_WRITE,SDIO_FUNCTION_0, 0, CCCR_BUS_INTF_CONTROL, io_buswidth); host->ios.bus_width = MMC_BUS_WIDTH_4; } } else { host->ios.clock = 25000000; host->ios.bus_width = MMC_BUS_WIDTH_4; host->ops->set_ios(host, &host->ios); io_buswidth = io_rw_direct(SDIO_READ, SDIO_FUNCTION_0, 0, CCCR_BUS_INTF_CONTROL, 0x0); io_buswidth |= 0x2; io_rw_direct(SDIO_WRITE,SDIO_FUNCTION_0, 0, CCCR_BUS_INTF_CONTROL, io_buswidth); } } sdio_rev = io_rw_direct(SDIO_READ,SDIO_FUNCTION_0, 0, CCCR_SDIO_REVISION, 0x0); /* * Enable all the functions in the card. */ io_rw_direct(SDIO_WRITE, SDIO_FUNCTION_0, 0, CCCR_IO_ENABLE,0xFF); io_rw_direct(SDIO_WRITE, SDIO_FUNCTION_0, 0, CCCR_FUNCTION_SELECT, io_rw_direct(SDIO_READ, SDIO_FUNCTION_0, 0, CCCR_FUNCTION_SELECT, 0x0) | 0x1); io_cardtype = io_rw_direct(SDIO_READ, SDIO_FUNCTION_1, 0, FBR1, 0x0); if (io_cardtype == 0x0) printk(KERN_INFO"Non SDIO standard interface detected\n"); else if (io_cardtype == 0x1) printk(KERN_INFO"SDIO UART interface detected\n"); else if (io_cardtype == 0x2) printk(KERN_INFO"SDIO thin bluetooth interface detected\n"); else if (io_cardtype == 0x3) printk(KERN_INFO"SDIO complete bluetooth interface detected\n"); else if (io_cardtype == 0x4) printk(KERN_INFO"SDIO GPS standard interface detected\n"); else if (io_cardtype == 0x5) printk(KERN_INFO"SDIO Camera standard interface detected\n"); else if (io_cardtype == 0x6) printk(KERN_INFO"SDIO PHS Radio standard interface detected\n"); else if (io_cardtype == 0x7) printk(KERN_INFO"SDIO WLAN interface detected\n"); if (sdio_rev == 0x00) printk(KERN_INFO"SDIO revision 1.00\n"); } read_cia = 0;}static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, struct mmc_card *oldcard){ struct mmc_command cmd; int err; u32 cid[4], io_rca; BUG_ON(!host); BUG_ON(!host->claimed); /* * Since we're changing the OCR value, we seem to * need to tell some cards to go back to the idle * state. We wait 1ms to give cards time to * respond. */ mmc_go_idle(host); err = io_send_op_cond(host, ocr, NULL); if (err != MMC_ERR_NONE) goto err; while(1) { /* * Read the rca of an SDIO card. */ cmd.opcode = SDIO_SEND_RELATIVE_ADDR; cmd.arg = 0x0; cmd.flags = MMC_RSP_R6; err = mmc_wait_for_cmd(host, &cmd,0); if (err == MMC_ERR_NONE){ io_rca = cmd.resp[0] & 0xFFFF0000; cid[0]=io_rca; cid[1]=io_rca; cid[2]=io_rca; cid[3]=io_rca; break; } } if (oldcard) { if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) goto err; sdiocard = oldcard; } else { /* * Allocate card structure. */ sdiocard = sdio_alloc_card(host, io_rca); if (IS_ERR(sdiocard)) goto err; sdiocard->type = MMC_TYPE_SDIO; host->mode = MMC_MODE_SDIO; memcpy(sdiocard->raw_cid, cid, sizeof(sdiocard->raw_cid)); } /* * Fetch CIA from card. */ io_read_cia(host); if (!oldcard) host->card = sdiocard; return MMC_ERR_NONE;err: return MMC_ERR_FAILED;}int mmc_attach_sdio(struct mmc_host *host, u32 ocr){ int err; BUG_ON(!host); BUG_ON(!host->claimed); mmc_attach_bus(host, &sdio_ops); /* * Sanity check the voltages that the card claims to * support. */ if (ocr & 0x7F) { printk(KERN_WARNING "%s: card claims to support voltages " "below the defined range. These will be ignored.\n", mmc_hostname(host)); ocr &= ~0x7F; } host->ocr = mmc_select_voltage(host, ocr); /* * Can we support the voltage of the card? */ if (!host->ocr) goto err; /* * Detect and init the card. */ err = mmc_sd_init_card(host, host->ocr, NULL); if (err != MMC_ERR_NONE) goto err; mmc_release_host(host); err = mmc_register_card(host->card); if (err) goto reclaim_host; return 0;reclaim_host: mmc_claim_host(host); mmc_remove_card(host->card); host->card = NULL;err: mmc_detach_bus(host); mmc_release_host(host); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -