一、sdhci-pltfm说明

sdhci-pltfm并不是实际某个host的driver。

sdhci-pltfm是指在sdhci core的基础上,提供了统一对sdhci_host的必要属性进行解析和设置的方法。

但是,对于sdhci类的host driver来说,使用sdhci-pltfm并不是必须的,host driver也可以自己来实现对应的操作。

通过《host(第二章)——sdhci》,我们知道了host driver调用sdhci_add_host注册sdhci_host的之前需要设置的信息如下:

  • sdhci的寄存器的映射过后的基地址(sdhci_host->ioaddr)
  • sdhci的癖好quirks、quirks2(sdhci_host->quirks,sdhci_host->quirks2)
  • sdhci的中断号(sdhci_host->irq)
  • host提供给sdhci core用来操作硬件的操作集(sdhci_host->ops)

因此,sdhci-pltfm实现了两个方法来统一设置这些信息,方便host driver对于sdhci driver的使用。

后续继续说明。

二、数据结构说明

1、sdhci_pltfm_data

首先看一下sdhci-pltfm要设置的sdhci_host的成员的来源信息:

  • sdhci的寄存器的映射过后的基地址(sdhci_host->ioaddr)

由DTS节点中的地址属性解析出来寄存器的物理地址之后,进行映射得到

  • sdhci的癖好quirks、quirks2(sdhci_host->quirks,sdhci_host->quirks2)

由平台host驱动(host driver)提供最基本的值,后续会进行调整

  • sdhci的中断号(sdhci_host->irq)

由DTS节点中的中断属性解析出来

  • host提供给sdhci core用来操作硬件的操作集(sdhci_host->ops)

由平台host驱动(host driver)提供

综上,ops、quirks和quirks2这几个的值是必须由平台host驱动(host driver)提供,而ioaddr和irq可以通过解析属性得到。

因此,sdhci-pltfm把ops、quirks和quirks2的值封装到sdhci_pltfm_data中,由底层host驱动提供。

其内容如下:

struct sdhci_pltfm_data {
const struct sdhci_ops *ops; // host提供给sdhci core用来操作硬件的操作集
unsigned int quirks; // sdhci的癖好quirks
unsigned int quirks2; // sdhci的癖好quirks2
};

2、sdhci_pltfm_host

sdhci_pltfm也为host抽象出一个host结构体sdhci_pltfm_host来作为sdhci_host和平台定制的host的中间层。

struct sdhci_pltfm_host {
struct clk *clk; /* migrate from sdhci_of_host */
unsigned int clock;
u16 xfer_mode_shadow; unsigned long private[0] ____cacheline_aligned;
};

以高通定制的host结构体sdhci_msm_host为例,三者之间的关系如下:

sdhci_host->private = sdhci_pltfm_host
sdhci_pltfm_host->priv = sdhci_msm_host
platform_get_drvdata(sdhci_msm_host->struct platform_device) = sdhci_host
sdhci_pltfm_host = sdhci_priv(sdhci_host);
sdhci_msm_host= sdhci_pltfm_priv(sdhci_pltfm_host);

三、API总览

1、sdhci_pltfm分配和释放相关

  • sdhci_pltfm_init & sdhci_pltfm_free

    由底层host driver调用。

sdhci_pltfm_init 用于分配sdhci_pltfm_host和sdhci_host的部分成员进行设置。

sdhci_pltfm_free用于释放sdhci_pltfm_host和sdhci_host。

    原型:struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, const struct sdhci_pltfm_data *pdata)
参数说明:struct platform_device *pdev——》host对应的平台设备的device
struct sdhci_pltfm_data *pdata——》需要host driver提供给sdhci_host的一些信息,前面说过了
使用案例:sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata); 原型:void sdhci_pltfm_free(struct platform_device *pdev)

2、属性解析相关

  • sdhci_get_of_property

由底层host driver调用。

用来解析host的dtsi节点的部分属性,前提是要求这部分属性必须按照一定的规范来。

    原型:void sdhci_get_of_property(struct platform_device *pdev)

3、sdhci_host注册相关

  • sdhci_pltfm_register & sdhci_pltfm_unregister

由底层host driver调用。

sdhci_pltfm_register 直接根据sdhci_pltfm_data来注册一个sdhci_host,会调用上述的sdhci_pltfm_init 和sdhci_get_of_property操作。

注意,但是一般用得比较少,因为host driver得到sdhci_host可能需要根据自己的需求来设置sdhci_host,而不是马上注册sdhci_host。

    原型:int sdhci_pltfm_register(struct platform_device *pdev, const struct sdhci_pltfm_data *pdata)
参数说明:struct platform_device *pdev——》host对应的平台设备的device
struct sdhci_pltfm_data *pdata——》需要host driver提供给sdhci_host的一些信息,前面说过了

四、接口代码说明

1、sdhci_pltfm_init

  • 主要工作

    • 调用sdhci_alloc_host分配一个sdhci_host
    • 根据sdhci_pltfm_data设置sdhci_host->ops
    • 根据sdhci_pltfm_data设置sdhci_host->quirks
    • 根据sdhci_pltfm_data设置sdhci_host->quirks2
    • 获取dtsi节点中的第一个中断属性并申请,设置sdhci_host->irq
    • 获取dtsi节点中的第一个寄存器属性并映射,设置sdhci_host->ioaddr
    • 调用平台的初始化操作
  • 具体代码如下

struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
const struct sdhci_pltfm_data *pdata)
{
// struct platform_device:sdhci host的平台设备
// const struct sdhci_pltfm_data:sdhci host的平台数据结构体,包含了对应host的sdhci_ops操作集
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct device_node *np = pdev->dev.of_node;
struct resource *iomem;
int ret; /* 获取sdhci内存资源区域 */
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); // 所以在dtsi节点中,sdhci的内存资源必须作为内存列表的第一个属性!!!! /* 调用sdhci_alloc_host获取一个标准的struct sdhci_host结构体 */
host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host)); /* 将struct sdhci_host的私有数据和struct sdhci_pltfm_host关联 */
pltfm_host = sdhci_priv(host); /* 根据传进来的sdhci host的平台数据来初始化sdhci_host的ops、quirks */
host->hw_name = dev_name(&pdev->dev);
host->ops = pdata->ops;
host->quirks = pdata->quirks; /* 获取中断 */
host->irq = platform_get_irq(pdev, 0); // 所以在dtsi节点中,sdhci的中断属性必须作为中断列表的第一个属性!!!!! /* 申请sdhci的内存资源并且进行映射 */
if (!request_mem_region(iomem->start, resource_size(iomem),
mmc_hostname(host->mmc))) {
dev_err(&pdev->dev, "cannot request region\n");
ret = -EBUSY;
goto err_request;
} host->ioaddr = ioremap(iomem->start, resource_size(iomem));
if (!host->ioaddr) {
dev_err(&pdev->dev, "failed to remap registers\n");
ret = -ENOMEM;
goto err_remap;
} /* 调用host->ops->platform_init进行初始化 */
if (host->ops && host->ops->platform_init)
host->ops->platform_init(host); /* 将struct sdhci_host作为对应host的私有数据 */
platform_set_drvdata(pdev, host); return host;
}

注意,通过上述代码,sdhci-pltfm要求必须把sdhci的寄存器属性放在host的dtsi的寄存器属性的第一个,同时,也要把sdhci的中断属性放在host的dtsi的中断属性的第一个。简单dtsi的例子如下图所示:

        sdhc_1: sdhci@07824000 {
reg = <0x07824900 0x11c>, <0x07824000 0x800>;
reg-names = "hc_mem", "core_mem"; // 其中,hc_mem表示sdhci的寄存器属性,放在了第一个 interrupts = <0 123 0>, <0 138 0>;
interrupt-names = "hc_irq", "pwr_irq"; // 其中,hc_irq表示sdhci的中断,放在了第一个

2、sdhci_get_of_property

代码如下:

void sdhci_get_of_property(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct sdhci_host *host = platform_get_drvdata(pdev); // 从平台设备结构体中获取私有数据,对应就是sdhci_host
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); // sdhci_host的私有护具就是struct sdhci_pltfm_host
const __be32 *clk;
u32 bus_width;
int size; if (of_device_is_available(np)) {
if (of_get_property(np, "sdhci,auto-cmd12", NULL))
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
// 解析"sdhci,auto-cmd12"属性,设置quirks的SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12标识
// sdhci,auto-cmd12————》SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12
// Controller uses Auto CMD12 command to stop the transfer,控制器使用CMD12自动结束传输 if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
(of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
bus_width == 1))
host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
// 解析"sdhci,1-bit-only"属性,设置quirks的SDHCI_QUIRK_FORCE_1_BIT_DATA标识
// sdhci,1-bit-only————》SDHCI_QUIRK_FORCE_1_BIT_DATA
// Controller can only handle 1-bit data transfers,该sdhci controller只支持1bit位宽传输 if (sdhci_of_wp_inverted(np))
host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
// sdhci,wp-inverted | wp-inverted————》SDHCI_QUIRK_INVERTED_WRITE_PROTECT if (of_get_property(np, "broken-cd", NULL))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
// broken-cd————》SDHCI_QUIRK_BROKEN_CARD_DETECTION
// Controller has unreliable card detection,sdhci controller没有实现card检测 if (of_get_property(np, "no-1-8-v", NULL))
host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
// no-1-8-v————》SDHCI_QUIRK2_NO_1_8_V
// The system physically doesn't support 1.8v, even if the host does,不支持1.8V clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk)
pltfm_host->clock = be32_to_cpup(clk);
// clock-frequency————》pltfm_host->clock
// 获取时钟频率 if (of_find_property(np, "keep-power-in-suspend", NULL))
host->mmc->pm_caps |= MMC_PM_KEEP_POWER; if (of_find_property(np, "enable-sdio-wakeup", NULL))
host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
}
}

3、sdhci_pltfm_register

使用得比较少,简单了解下即可。

int sdhci_pltfm_register(struct platform_device *pdev,
const struct sdhci_pltfm_data *pdata)
{
struct sdhci_host *host;
int ret = 0; /* 调用sdhci_pltfm_init分配并初始化一个sdhci_host */
host = sdhci_pltfm_init(pdev, pdata);
if (IS_ERR(host))
return PTR_ERR(host); /* 调用sdhci_get_of_property解析dtsi属性并设置sdhci_host的部分成员 */
sdhci_get_of_property(pdev); /* 调用sdhci_add_host将该sdhci_host注册到sdhci core中 */
ret = sdhci_add_host(host);
if (ret)
sdhci_pltfm_free(pdev); return ret;
}

最新文章

  1. jquery兼容实验
  2. clean之后R文件消失
  3. 怎样分析java线程堆栈日志
  4. UVALive 7270 Osu! Master (阅读理解题)
  5. 【bzoj1053】反素数
  6. 解决:Ubuntu12.04下使用ping命令返回ping:icmp open socket: Operation not permitted的解决
  7. Swift 本地推送通知UILocalNotification
  8. VS查看工程项目代码行数
  9. Java API —— BigInteger类
  10. Linux进程调度与切换
  11. Python环境变量配置问题
  12. mybatis if test加筛选条件
  13. Selenium webdriver定位iframe里面元素两种方法
  14. 【DP】捡苹果
  15. React.js开发的基本配置(配了两天)
  16. dubbo框架初步学习
  17. lua io.read()
  18. Jmeter怎样打印日志
  19. 菜鸟webpack教程纠错
  20. mysql5.7主从复制--在线变更复制类型【转】

热门文章

  1. CSS 轻松搞定标签(元素)居中问题
  2. Windows远程桌面多用户登录的问题
  3. Centos7下安装配置keepalived
  4. KMP算法计算next值和nextVal值
  5. 二,java框架学习
  6. [C1] 线性回归(Linear Regression)
  7. C++ 标准库 std::remove
  8. Python Singleton Pattern(单例模式)
  9. centos6 升级Git版本
  10. Kubernetes Deployment(部署无状态应用)