Chinaunix首页 | 论坛 | 博客
  • 博客访问: 258640
  • 博文数量: 86
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 640
  • 用 户 组: 普通用户
  • 注册时间: 2018-10-15 14:13
个人简介

搭建一个和linux开发者知识共享和学习的平台

文章分类

全部博文(86)

文章存档

2023年(24)

2022年(27)

2019年(8)

2018年(27)

分类: LINUX

2022-12-16 11:31:35

 SDIO Wi-Fi 配置




Wi-Fi/BT硬件管脚的配置主要有以下几点:
切记一定要对照原理图进行配置,且确保使用的dts/dtsi里面包含以下节点!
SDIO 接口Wi-Fi:WL_REG_ON由sdio_pwrseq节点进行管理控制,不需要在wireless-wlan节点下面重复
添加WIFI,poweren_gpio配置;




/* SDIO接口Wi-Fi专用配置: WIFI_REG_ON: Wi-Fi的电源使能PIN脚 */
sdio_pwrseq: sdio-pwrseq 
{
compatible = "mmc-pwrseq-simple";
pinctrl-names = "default";
pinctrl-0 = <&wifi_enable_h>;
/* 特别注意:WIFI_REG_ON GPIO_ACTIVE 配置跟使能状态恰好是相反的,
* 高有效为LOW,低有效则为HIGH
* 切记:这个配置跟下面的WIFI,poweren_gpio是互斥的,不能同时配置!!!
*/
reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>;
};




/* SDIO接口Wi-Fi专用配置:WIFI_REG_ON脚的pinctrl的配置 */
&pinctrl {
sdio-pwrseq {
wifi_enable_h: wifi-enable-h {
rockchip,pins =
/* 对应上面的WIFI_REG_ON,关掉上下拉,防止不能拉高或拉低 */
<0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};




/* SDIO接口Wi-Fi专用配置:SDIO接口节点 */
&sdio {
max-frequency = <150000000>; /* sdio接口的{BANNED}最佳大频率,可调整 */
bus-width = <4>; /* 4线模式,可调整1线模式 */
sd-uhs-sdr104; /* 支持SDIO3.0 */
… …
status = "okay";
};




/* Wi-Fi节点 */
wireless-wlan {
compatible = "wlan-platdata";
rockchip,grf = <&grf>;




/* 注意:如果排查发现Wi-Fi模块没有32.768K波形,且硬件上是有
* RK PMU供给的,则打开下面的clock属性,按照实际使用的PMU型号填写,
* 否在SDIO/Wi-Fi无法使用.
*/
clocks = <&rk809 1>; //如果使用RK809,只能配置一个
clocks = <&hym8563>; //如果使用hym8563,只能配置一个
clock-names = "ext_clock";
/* 按实际名字填写 */
wifi_chip_type = "ap6255";
/* WIFI_WAKE_HOST: Wi-Fi中断通知主控的PIN脚。
* 特别注意:确认下这个Wi-Fi pin脚跟主控的pin的
* 硬件连接关系,直连的话就是GPIO_ACTIVE_HIGH;
* 如果中间加了一个反向管就要改成低电平GPIO_ACTIVE_LOW触发
*/
WIFI,host_wake_irq = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
//SDIO Wi-Fi 无需此配置,除非有动态加载协助驱动ko的需求,参考11.8章节
//WIFI,poweren_gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>;
status = "okay";
};




/* WIFI_WAKE_HOST脚的pinctrl的配置 */
wireless-wlan {
/omit-if-no-ref/
wifi_wake_host: wifi-wake-host {
/* 注意一般Wi-Fi的wake host pin都是高电平触发,
* 所以默认这里要配置为下拉; 如果客户的硬件设计
* 是反向的则要改为上拉,总之要初始化为与触发电平
* 相反的状态
*/
rockchip,pins = <0 RK_PA0 0 &pcfg_pull_down>;
};
}






rk3326的SDIO控制器驱动

drivers/mmc/host/dw_mmc-rockchip.c


ap6265驱动


drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd






drivers\mmc\host\dw_mmc-rockchip.c
dw_mci_rockchip_probe(struct platform_device *pdev)
--> dw_mci_pltfm_register(pdev, drv_data); //解析设备树信息,用来构造一个dw_mci *host;
--> dw_mci_probe(dw_mci *host); //将上面构造好的dw_mci *host结构体传参进来;
--> setup_timer(&host->cmd11_timer,dw_mci_cmd11_timer, (unsigned long)host); //设置一些定时器,定时发送一些命令
--> host->dma_ops = host->pdata->dma_ops;
--> ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
//这个dw_mci_interrupt中断函数会被注册两次,一次是emmc(irq=25),一次是sd卡(irq=26),所以源码虽然只注册了一次,但是实际上注册了两次,用的都是同一个中断处理函数
//这个是mci寄存器的中断,我们的这款soc可以根据这个寄存器来判断发送,接收,SD卡热拔插的行为,都会触发这个中断,在这个中断处理函数里面再细分是什么操作触发的中断,进行处理,比如热拔插:
--> dw_mci_init_slot(dw_mci *host, i); // 定义了mmc_host *mmc;,用我们封装了一层的dw_mci *host去填充注册他
--> mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
--> INIT_DELAYED_WORK(&host->detect, mmc_rescan); //初始化工作队列,里面有扫描SD卡的函数
--> mmc->ops = &dw_mci_ops; //mmc_host_ops类型的变量,用于定义本mmc_host的操作接口(包括与mmc card通信的接口request、卡检测相关的接口等)
--> mmc_add_host(mmc);
--> mmc_start_host(mmc_host *host);
--> mmc_schedule_delayed_work(&host->detect, delay); //上电添加mmc_host的时候,先主动执行一次mmc_rescan函数
--> dw_mci_enable_cd(host); //cd = card detect ≠ sdmmc_cd 引脚中断,主要看函数内容,像这款soc就是在里面开启mci寄存器的SD卡热拔插中断
--> temp = mci_readl(host, INTMASK); temp  |= SDMMC_INT_CD; mci_writel(host, INTMASK, temp); //开启mci寄存器的SD卡热拔插中断






dw_mci_interrupt()
if (pending & SDMMC_INT_CD)
dw_mci_handle_cd(dw_mci *host);
--> mmc_detect_change(slot->mmc,msecs_to_jiffies(host->pdata->detect_delay_ms));
--> _mmc_detect_change(host, delay, true);
--> mmc_schedule_delayed_work(&host->detect, delay); //开启工作队列
--> mmc_rescan() //{BANNED}最佳终会调用此函数
 
重点看看mmc_rescan检测SD卡热拔插的函数,我们在设备树中的SD卡定义了 supports-sd 所以:
drivers\mmc\core\host.c 
mmc_of_parse
if (of_property_read_bool(np, "supports-sd"))
host->restrict_caps |= RESTRICT_CARD_TYPE_SD; 
 
mmc_rescan()
if (host->bus_ops && !host->bus_dead && !(host->caps & MMC_CAP_NONREMOVABLE)) //上电{BANNED}中国第一次调用这个函数时候,还没有设置host->bus_ops,所以会执行后面的语句来设置host->bus_ops
host->bus_ops->detect(host);
--> mmc_rescan_try_freq(host, max(freqs[i], host->f_min)) //以各种频率给host发,选择{BANNED}最佳合适的频率
if ((host->restrict_caps & RESTRICT_CARD_TYPE_SD) && !mmc_attach_sd(host)) return 0; 所以就会调用mmc_attach_sd
--> mmc_attach_sd(host)
--> mmc_attach_bus(host, &mmc_sd_ops);
--> host->bus_ops = ops; //这里的ops就是上面的mmc_ops参数
--> mmc_sd_init_card(host, rocr, NULL);
--> card = mmc_alloc_card(host, &sd_type);
--> mmc_add_card(host->card);
--> device_add(&card->dev);
--> bus_add_device(dev); //Add the device to its bus's list of devices, 会给mmc_bus注册一个devices,会和系统自动注册的mmc_driver匹配,调用它的probe函数
                        ......
                        --> mmc_driver->probe
                        --> mmc_blk_probe() //如上分析的,会读取SD卡的寄存器获取分区信息,根据分区信息注册block等。






Mmc card: 
①host完成mmc_card与mmc_host的绑定;
②dev完成将该mmc_card与系统中的设备、总线、驱动的关联(即完成与系统设备驱动总线的关联与绑定操作);
③卡类型与卡状态记录
④卡相关的寄存器信息记录(主要从mmc card中读取),包括cid、csd、scr、ssr等内容
⑤Mmc card的分区信息,主要完成块设备的创建(由mmc driver实现)若为sdio设备,则有cccr、cis等(关于sdio的部分,请参考sdio协议相关的文档)






mmc_ios:
该结构体主要定义mmc总线相关的参数,主要包括时钟频率、电源、总线模式、电源状态、总线带宽、支持的信号电压值等等这些参数的设置可通过mmc_host_ops->set_ios实现。


mmc_host_ops:
该数据结构定义了mmc_host的操作方法


mmc_bus_ops:
该接口主要是针对mmc card的sleep/awake的操作,因mmc card也需要进行sleep/awake等接口,这些接口类似于设备驱动的电源管理(suspend/resume)相关的接口。该结构体中的成员,不需要我们进行实现,mmc子系统已经完成,mmc子系统根据mmc各协议版本针对sleep/awake的支持情况,实现对应的操作。










wifi调试


查看rk3326的sdio属性
cat /sys/kernel/debug/mmc2/ios




阅读(857) | 评论(0) | 转发(0) |
0

上一篇:Linux内存管理:memblock

下一篇:BuildRoot详解

给主人留下些什么吧!~~