摘要
本文详细介绍如何将博通(Broadcom)BK7236 Wi-Fi模块成功适配到君正半导体(Ingenic)T32嵌入式平台,介绍了如何在 君正 T32 平台 上通过内核补丁适配 BK7236 Wi-Fi 模块。补丁内容基于 Linux Kernel 3.10.14,对 GPIO、MMC/SDIO、Wi-Fi 模块初始化及驱动符号导出等部分进行了修改,以实现 BK7236 模块在 SDIO 接口下的稳定运行。
一、引言
- 背景介绍:物联网设备对Wi-Fi连接的需求日益增长,君正T32作为低功耗嵌入式平台,适配高性能BK7236模块可提升应用灵活性。
- 目标与意义:实现稳定、高效的Wi-Fi通信,降低开发门槛,适用于智能家居、工业控制等场景。
- 文章结构概述:从硬件到软件逐步解析适配过程,提供实用指南。
二、硬件平台基础介绍
- 君正T32芯片特性
- 处理器架构(如MIPS或RISC-V核心)、主频、功耗范围。
- 外设接口支持:SPI、UART、I2C等关键通信接口。
- BK7236 Wi-Fi模块特性
- 无线标准(802.11 b/g/n)、传输速率、工作频段。
- 硬件接口要求:SPI或SDIO连接方式,电源管理设计。
- 适配需求分析
- 兼容性检查:T32接口与BK7236的匹配性。
- 应用场景:数据传输速率、距离和功耗要求。
三、软件开发环境搭建
- 开发工具链
- 君正T32 SDK安装:基于Linux或RTOS的环境配置。
- 交叉编译工具链设置(如GCC for MIPS)。
- BK7236驱动集成
- 驱动源码获取:从博通官方或开源社区下载。
- SDK集成步骤:修改Makefile、添加驱动文件。
- 初始配置与编译
- 编译命令示例:参考T32 SDK编译。
- 常见错误解决:依赖库缺失处理。
四、软件驱动开发与代码实现
T32 平台适配 BK7236基于MMC驱动的基础上新增几条指令,因此所需修改软件如下:
-
board.h 文件改动
修改内容,MMC 电源引脚使能信号从 低电平有效 修改为 高电平有效,Wi-Fi 模块的 唤醒主控引脚 和 电源使能引脚 设置为 -1,即不再由 GPIO 控制,改为外部固定电源。#define GPIO_MMC_PWR_LEVEL HIGH_ENABLE #define WL_WAKE_HOST -1 //GPIO_PB(7) #define WL_REG_EN -1 //GPIO_PC(9) -
mmc.c 文件改动
去掉 MMC_CAP_NONREMOVABLE,避免热插拔逻辑冲突,启用高速支持:MMC_CAP_MMC_HIGHSPEED 和 MMC_CAP_SD_HIGHSPEED,注释掉 cd_type 等卡检测相关字段,因为 BK7236 模块是焊接式模块无需卡检测,支持外部电源 GPIO 设置。#ifdef CONFIG_MMC_SDHCI_MMC1 struct jz_sdhci_platdata jz_mmc1_pdata = { + //.cd_type = JZ_SDHCI_CD_GPIO, + //.ext_cd_gpio = GPIO_MMC_CD_N, + //.ext_cd_gpio_invert = GPIO_MMC_CD_N_LEVEL, + .ext_pwr_gpio = GPIO_MMC_PWR, + .ext_pwr_gpio_invert = GPIO_MMC_PWR_LEVEL, .max_width = 4, - .host_caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ | MMC_CAP_NONREMOVABLE), + .host_caps = (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), + //.capacity = MMC_CAP_SDIO_IRQ | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_NONREMOVABLE, .pm_flags = MMC_PM_IGNORE_PM_NOTIFY, #ifdef CONFIG_MMC1_PIO_MODE .pio_mode = 1, -
gpio.c 文件改动
将 jz_gpio_set_func 函数导出为全局符号,允许 Wi-Fi 驱动或外部模块调用此接口动态配置 GPIO 功能。EXPORT_SYMBOL_GPL(jz_gpio_set_func); -
block.c 文件改动
取消对 mmc_blk_alloc_part 的 #if 0 屏蔽,启用 MMC 多分区逻辑支持;为 mmc_blk_alloc_parts 添加 idx 变量,避免局部未定义错误,此改动可确保 BK7236 Wi-Fi 模块固件或驱动分区在 MMC 中可正确访问。
-#if 0
+
static int mmc_blk_alloc_part(struct mmc_card *card,
struct mmc_blk_data *md,
unsigned int part_type,
@@ -2135,7 +2135,7 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
mmc_card_name(card), part_md->part_type, cap_str);
return 0;
}
-#endif
+
/* MMC Physical partitions consist of two boot partitions and
* up to four general purpose partitions.
* For each partition enabled in EXT_CSD a block device will be allocatedi
@@ -2144,7 +2144,7 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
{
- int ret = 0;
+ int idx, ret = 0;
if (!mmc_card_mmc(card))
return 0;
static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
{
int idx, ret = 0;
...
}
- core.c文件改动
增加对mmc1 BK7236对应模块的特殊模式的初始化,并添加workqueue的处理逻辑方式。
-static struct workqueue_struct *workqueue;
+#define CUSTOMED_HOST_NUM 3
+static struct workqueue_struct *workqueue[CUSTOMED_HOST_NUM] = { NULL };
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
/*
@@ -88,15 +89,18 @@ MODULE_PARM_DESC(
static int mmc_schedule_delayed_work(struct delayed_work *work,
unsigned long delay)
{
- return queue_delayed_work(workqueue, work, delay);
+ struct mmc_host *host =
+ container_of(work, struct mmc_host, detect);
+
+ return queue_delayed_work(workqueue[host->index], work, delay);
}
/*
* Internal function. Flush all scheduled work from the MMC work queue.
*/
-static void mmc_flush_scheduled_work(void)
+static void mmc_flush_scheduled_work(int index)
{
- flush_workqueue(workqueue);
+ flush_workqueue(workqueue[index]);
}
#ifdef CONFIG_FAIL_MMC_REQUEST
@@ -136,6 +140,23 @@ static inline void mmc_should_fail_request(struct mmc_host *host,
#endif /* CONFIG_FAIL_MMC_REQUEST */
+/*
+ * mmc_wait_data_done() - done callback for data request
+ * @mrq: done data request
+ *
+ * Wakes up mmc context, passed as a callback to host controller driver
+ */
+static void mmc_wait_data_done(struct mmc_request *mrq)
+{
+ mrq->host->context_info.is_done_rcv = true;
+ wake_up_interruptible(&mrq->host->context_info.wait);
+}
+
+static void mmc_wait_done(struct mmc_request *mrq)
+{
+ complete(&mrq->completion);
+}
+
/**
* mmc_request_done - finish processing an MMC request
* @host: MMC host which completed request
@@ -159,7 +180,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
* Request starter must handle retries - see
* mmc_wait_for_req_done().
*/
- if (mrq->done)
+ if (mrq->done == mmc_wait_data_done || mrq->done == mmc_wait_done)
mrq->done(mrq);
} else {
mmc_should_fail_request(host, mrq);
@@ -186,7 +207,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->resp[2], mrq->stop->resp[3]);
}
- if (mrq->done)
+ if (mrq->done == mmc_wait_data_done || mrq->done == mmc_wait_done)
mrq->done(mrq);
mmc_host_clk_release(host);
@@ -323,23 +344,6 @@ out:
}
EXPORT_SYMBOL(mmc_start_bkops);
-/*
- * mmc_wait_data_done() - done callback for data request
- * @mrq: done data request
- *
- * Wakes up mmc context, passed as a callback to host controller driver
- */
-static void mmc_wait_data_done(struct mmc_request *mrq)
-{
- mrq->host->context_info.is_done_rcv = true;
- wake_up_interruptible(&mrq->host->context_info.wait);
-}
-
-static void mmc_wait_done(struct mmc_request *mrq)
-{
- complete(&mrq->completion);
-}
-
/*
*__mmc_start_data_req() - starts data request
* @host: MMC host to start the request
@@ -2314,12 +2318,26 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
mmc_send_if_cond(host, host->ocr_avail);
/* Order's important: probe SDIO, then SD, then MMC */
+#ifdef CONFIG_BK7236_EN
+ if (!(host->caps2 & MMC_CAP2_NO_SDIO))
+ if (!mmc_attach_sdio(host))
+ return 0;
+
+ if (!(host->caps2 & MMC_CAP2_NO_SD))
+ if (!mmc_attach_sd(host))
+ return 0;
+
+ if (!(host->caps2 & MMC_CAP2_NO_MMC))
+ if (!mmc_attach_mmc(host))
+ return 0;
+#else
if (!mmc_attach_sdio(host))
return 0;
if (!mmc_attach_sd(host))
return 0;
if (!mmc_attach_mmc(host))
return 0;
+#endif
mmc_power_off(host);
return -EIO;
@@ -2500,7 +2518,7 @@ void mmc_stop_host(struct mmc_host *host)
host->rescan_disable = 1;
if (cancel_delayed_work_sync(&host->detect))
wake_unlock(&host->detect_wake_lock);
- mmc_flush_scheduled_work();
+ mmc_flush_scheduled_work(host->index);
/* clear pm flags now and let card drivers set them as needed */
host->pm_flags = 0;
@@ -2699,7 +2717,7 @@ int mmc_suspend_host(struct mmc_host *host)
if (cancel_delayed_work(&host->detect))
wake_unlock(&host->detect_wake_lock);
- mmc_flush_scheduled_work();
+ mmc_flush_scheduled_work(host->index);
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
@@ -2892,12 +2910,14 @@ EXPORT_SYMBOL(mmc_set_embedded_sdio_data);
static int __init mmc_init(void)
{
- int ret;
-
- workqueue = alloc_ordered_workqueue("kmmcd", 0);
- if (!workqueue)
- return -ENOMEM;
-
+ int ret, i;
+ for (i = 0; i < CUSTOMED_HOST_NUM; i++) {
+ char qname[8];
+ sprintf(qname, "kmmcd-%d", i);
+ workqueue[i] = alloc_ordered_workqueue(qname, 0);
+ if (!workqueue[i])
+ return -ENOMEM;
+ }
ret = mmc_register_bus();
if (ret)
goto destroy_workqueue;
@@ -2917,17 +2937,28 @@ unregister_host_class:
unregister_bus:
mmc_unregister_bus();
destroy_workqueue:
- destroy_workqueue(workqueue);
-
+ for (i = 0; i < CUSTOMED_HOST_NUM; i++) {
+ if (workqueue[i]) {
+ destroy_workqueue(workqueue[i]);
+ workqueue[i] = NULL;
+ }
+ }
return ret;
}
static void __exit mmc_exit(void)
{
+ int i;
+
sdio_unregister_bus();
mmc_unregister_host_class();
mmc_unregister_bus();
- destroy_workqueue(workqueue);
+ for (i = 0; i < CUSTOMED_HOST_NUM; i++) {
+ if (workqueue[i]) {
+ destroy_workqueue(workqueue[i]);
+ workqueue[i] = NULL;
+ }
+ }
}
subsys_initcall(mmc_init);
以上除此之外还需要对sd.c ,sd_ops.c ,sdio.c,sdio_ops.c,jzmmc_v12.c等等文件进行修改,本章就不在这里一一详细说明了,详细参考补丁文件: http://blog.tomgzhe.com/wp-content/uploads/2025/09/wireless_drv_mmc1_20250701-3.7z
五、测试、验证与优化
- 功能测试方法
- 基础测试:Wi-Fi扫描、连接稳定性测试。
- 数据传输测试:TCP/UDP吞吐量测量(如iperf工具)。
- 性能优化策略
- 功耗优化:睡眠模式配置、动态频率调整。
- 延迟优化:中断优先级设置、缓冲区管理。
- 问题诊断与日志
- 常见错误:连接超时、数据丢包分析。
- 日志工具使用:串口输出调试信息。
版权声明
内容来源及使用限制
欢迎访问 TomgZHE研习社(网址:https://blog.tomgzhe.com)。本网站部分文章内容源自网络,仅作学习交流与参考分享;若您发现有内容涉嫌侵权,请立即联系 tomgzhe@qq.com,我们将在接到通知后的 48 小时内核实并删除相关侵权内容。
软件资源相关规定
本网站为个人非盈利性质的站点,所有软件资源均来自网络。这些资源仅用于个人学习、研究和参考,严禁用于任何商业用途。您下载和使用本网站软件资源即表示您同意仅将其用于学习目的,若因违反此规定导致任何法律纠纷或损失,责任由您自行承担。
原创版权
本网站上的原创内容,包括但不限于文字作品、自行设计的图片、独家制作的音频视频等,其版权均归本网站所有。未经本网站书面授权,任何组织或个人不得擅自复制、转载、摘编、传播或以其他任何方式使用这些原创内容。如需使用,请提前与我们联系并获得书面许可,同时需在显著位置注明出处及作者信息。
转载与引用规范
若您需转载本网站文章,务必注明文章来源为 “[],原文链接:[ https://blog.tomgzhe.com/index.php/2025/09/12/t32_wifi_bk7236/ ]”;对于有明确作者署名的文章,还需完整保留作者姓名。在引用本网站内容时,请确保内容准确无误,并遵循学术及行业的引用规范。
微信扫一扫打赏
支付宝扫一扫打赏