[RK3399][Android7.1] WiFi中的SDIO和电源框架

Platform: RK3399
OS: Android 7.1
Kernel: v4.4.83

框架:

引用网友一张框图,画得很不错
这里写图片描述

从硬件角度来看:
CPU -> SDIO -> AP6356S

从软件角度来看分:
电源/IO管理
SDIO通道(Host和Client)
WiFi驱动


电源/GPIO管理模块:

主要完成对电源、GPIO的初始化和控制等。

配置是在DTS中
rk3399-mid-818-android.dts:

wireless-wlan {
    compatible = "wlan-platdata";
    rockchip,grf = <&grf>;
    //AP6354和AP6356S兼容
    wifi_chip_type = "ap6354";  
    sdio_vref = <1800>;
    //WiFi中断脚,有些模组没有这个脚可以不配置
    WIFI,host_wake_irq = <&gpio0 3 GPIO_ACTIVE_HIGH>; /* GPIO0_a3 */
    status = "okay";
};

sdio_pwrseq: sdio-pwrseq {
    compatible = "mmc-pwrseq-simple";
    clocks = <&rk818 1>;
    clock-names = "ext_clock";
    pinctrl-names = "default";
    pinctrl-0 = <&wifi_enable_h>;

    /*
     * On the module itself this is one of these (depending
     * on the actual card populated):
     * - SDIO_RESET_L_WL_REG_ON
     * - PDN (power down when low)
     */
    //到rk3399上面,WL_REG_ON即对WiFi电源的控制是放在sdio模块中了。
    reset-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; /* GPIO0_B2 */
};

&sdio0 {
    cap-sdio-irq;
    mmc-pwrseq = <&sdio_pwrseq>;
};

解析配置的驱动在rfkill-wlan.c

static struct of_device_id wlan_platdata_of_match[] = {
    { .compatible = "wlan-platdata" },
    { }
};

static int wlan_platdata_parse_dt(struct device *dev,
                  struct rksdmmc_gpio_wifi_moudle *data)
{
    syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
    of_property_read_string(node, "wifi_chip_type", &strings);
    of_find_property(node, "keep_wifi_power_on", NULL)
    of_find_property(node, "power_ctrl_by_pmu", NULL)
    of_get_named_gpio_flags(node, "WIFI,poweren_gpio", 0, &flags);
    of_get_named_gpio_flags(node, "WIFI,reset_gpio", 0, &flags);
    of_get_named_gpio_flags(node, "WIFI,host_wake_irq", 0, &flags);
}

SDIO Host:

对应的是对CPU上的SDIO Host Controller的控制实现,不管是哪个平台,最终都是通过mmc_add_host()添加mmc框架的core层中去。
host驱动位于kernel/drivers/mmc/host目录,使用的是Synopsys DW(DesignWare)的ip核。

kris@eco:~/rk3399/kernel/drivers/mmc/host$ ls *.o
built-in.o  dw_mmc-pltfm.o     rk_sdmmc_ops.o  sdhci-of-arasan.o
dw_mmc.o    dw_mmc-rockchip.o  sdhci.o         sdhci-pltfm.o

dw_mmc.c:

static const struct mmc_host_ops dw_mci_ops = {
    .request        = dw_mci_request,
    .pre_req        = dw_mci_pre_req,
    .post_req       = dw_mci_post_req,
    .set_ios        = dw_mci_set_ios,
    .set_sdio_status    = dw_mci_set_sdio_status,
    .get_ro         = dw_mci_get_ro,
    .get_cd         = dw_mci_get_cd,
    .enable_sdio_irq    = dw_mci_enable_sdio_irq,
    .execute_tuning     = dw_mci_execute_tuning,
    .card_busy      = dw_mci_card_busy,
    .start_signal_voltage_switch = dw_mci_switch_voltage,
    .init_card      = dw_mci_init_card,
    .prepare_hs400_tuning   = dw_mci_prepare_hs400_tuning,
};

static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
{
    mmc->ops = &dw_mci_ops;
    dw_mci_slot_of_parse(slot);
    mmc_of_parse(mmc);
    mmc_add_host(mmc);
}

解析的配置位于sdio0节点中
rk3399-mid-818-android.dts
//板级配置

&sdio0 {
    clock-frequency = <150000000>;
    clock-freq-min-max = <200000 150000000>;
    supports-sdio;
    bus-width = <4>;
    disable-wp;
    cap-sd-highspeed;
    cap-sdio-irq;
    keep-power-in-suspend;
    mmc-pwrseq = <&sdio_pwrseq>;
    non-removable;
    num-slots = <1>;
    pinctrl-names = "default";
    pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
    sd-uhs-sdr104;
    status = "okay";
};

还有一部分配置在rk3399.dtsi中
//平台配置

sdio0: dwmmc@fe310000 {
    compatible = "rockchip,rk3399-dw-mshc",
             "rockchip,rk3288-dw-mshc";
    reg = <0x0 0xfe310000 0x0 0x4000>;
    interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH 0>;
    clock-freq-min-max = <400000 150000000>;
    clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
         <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
    clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
    fifo-depth = <0x100>;
    power-domains = <&power RK3399_PD_SDIOAUDIO>;
    status = "disabled";
};

SDIO Client:

对应的是对WiFi模组内部的SDIO控制器的控制实现,因此此模块代码也是集成于WiFi驱动中。
AP6356S用的是broadcom模组,驱动位于kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd目录下
SDIO注册调用流程如下:

rockchip_wifi_init_module_rkwifi -> dhd_linux.c
  wifi_init_thread ->
    dhd_module_init ->
      dhd_wifi_platform_register_drv ->
        dhd_wifi_platform_load ->
          dhd_wifi_platform_load_sdio ->
            dhd_bus_register ->
              bcmsdh_register ->
                bcmsdh_register_client_driver ->
                  sdio_register_driver 

对应sdio_driver:

static struct sdio_driver bcmsdh_sdmmc_driver = {
    .probe      = bcmsdh_sdmmc_probe,
    .remove     = bcmsdh_sdmmc_remove,
    .name       = "bcmsdh_sdmmc",
    .id_table   = bcmsdh_sdmmc_ids,
};

SDIO Client通过SDIO Host去控制WiFi模块。

WiFi驱动因为内容过多,后面再分析了。


参考:

WiFi驱动(1)框架解析

猜你喜欢

转载自blog.csdn.net/kris_fei/article/details/80923424