当前位置: 首页 > news >正文

SDIO三种触发枚举的方式

单独的cd-gpio

如果有单独的gpio来触发探测就会在mmc_gpiod_request_cd_irq注册中断处理函数,来探测一次,下述会通过sdhci_probe_config_dt来解析设备树里是否有cd-gpios

static int sdhci_probe(struct platform_device *pdev)
{ssdhci_alloc_hosttruct sdhci_host *host;struct resource *iomem;struct spear_sdhci *sdhci;struct device *dev;int ret;dev = pdev->dev.parent ? pdev->dev.parent : &pdev->dev;host = sdhci_alloc_host(dev, sizeof(*sdhci));if (IS_ERR(host)) {ret = PTR_ERR(host);dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n");goto err;}iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);host->ioaddr = devm_ioremap_resource(&pdev->dev, iomem);if (IS_ERR(host->ioaddr)) {ret = PTR_ERR(host->ioaddr);dev_dbg(&pdev->dev, "unable to map iomem: %d\n", ret);goto err_host;}host->hw_name = "sdhci";host->ops = &sdhci_pltfm_ops;host->irq = platform_get_irq(pdev, 0);host->quirks = SDHCI_QUIRK_BROKEN_ADMA;sdhci = sdhci_priv(host);/* clk enable */sdhci->clk = devm_clk_get(&pdev->dev, NULL);if (IS_ERR(sdhci->clk)) {ret = PTR_ERR(sdhci->clk);dev_dbg(&pdev->dev, "Error getting clock\n");goto err_host;}ret = clk_prepare_enable(sdhci->clk);if (ret) {dev_dbg(&pdev->dev, "Error enabling clock\n");goto err_host;}ret = clk_set_rate(sdhci->clk, 50000000);if (ret)dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",clk_get_rate(sdhci->clk));sdhci_probe_config_dt(pdev->dev.of_node, sdhci);/** It is optional to use GPIOs for sdhci card detection. If* sdhci->card_int_gpio < 0, then use original sdhci lines otherwise* GPIO lines. We use the built-in GPIO support for this.*/if (sdhci->card_int_gpio >= 0) {ret = mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0);if (ret < 0) {dev_dbg(&pdev->dev,"failed to request card-detect gpio%d\n",sdhci->card_int_gpio);goto disable_clk;}}ret = sdhci_add_host(host);if (ret) {dev_dbg(&pdev->dev, "error adding host\n");goto disable_clk;}platform_set_drvdata(pdev, host);return 0;disable_clk:clk_disable_unprepare(sdhci->clk);
err_host:sdhci_free_host(host);
err:dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret);return ret;
}

probe函数调用sdhci_probe_config_dt从设备树获取中断脚,并赋给   host->card_int_gpio = cd_gpio; 没有的话值为-1

static void sdhci_probe_config_dt(struct device_node *np,struct spear_sdhci *host)
{int cd_gpio;cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);if (!gpio_is_valid(cd_gpio))cd_gpio = -1;host->card_int_gpio = cd_gpio;
}

上述probe函数中会检测card_int_gpio ,大于等于0,有些cpu,gpio号可能为0,gpio控制器的base从0 开始的话,而不是从1024开始,就会为0

if (sdhci->card_int_gpio >= 0) {ret = mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0);if (ret < 0) {dev_dbg(&pdev->dev,"failed to request card-detect gpio%d\n",sdhci->card_int_gpio);goto disable_clk;}}

mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0);将cd脚设置成输入

int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,unsigned int debounce)
{struct mmc_gpio *ctx = host->slot.handler_priv;int ret;ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,ctx->cd_label);if (ret < 0)/** don't bother freeing memory. It might still get used by other* slot functions, in any case it will be freed, when the device* is destroyed.*/return ret;if (debounce) {ret = gpio_set_debounce(gpio, debounce);if (ret < 0)return ret;}ctx->override_cd_active_level = true;ctx->cd_gpio = gpio_to_desc(gpio);return 0;
}

probe函数调用,sdhci_add_host调用mmc_start_host,通过mmc_gpiod_request_cd_irq将中断脚注册中断,并注册中断处理函数

oid mmc_gpiod_request_cd_irq(struct mmc_host *host)
{struct mmc_gpio *ctx = host->slot.handler_priv;int irq = -EINVAL;int ret;if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio)return;/** Do not use IRQ if the platform prefers to poll, e.g., because that* IRQ number is already used by another unit and cannot be shared.*/if (ctx->cd_irq >= 0)irq = ctx->cd_irq;else if (!(host->caps & MMC_CAP_NEEDS_POLL))irq = gpiod_to_irq(ctx->cd_gpio);if (irq >= 0) {if (!ctx->cd_gpio_isr)ctx->cd_gpio_isr = mmc_gpio_cd_irqt;ret = devm_request_threaded_irq(host->parent, irq,NULL, ctx->cd_gpio_isr,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,ctx->cd_label, host);if (ret < 0)irq = ret;}host->slot.cd_irq = irq;if (irq < 0)host->caps |= MMC_CAP_NEEDS_POLL;
}
EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);

POLL检测

dts设有broken-cd属性,就会走mmc_schedule_delayed_work来每秒调用mmc_rescan

                sdhci_alloc_hostmmc_alloc_hostINIT_DELAYED_WORK(&host->detect, mmc_rescan);mmc_rescan_try_freqmmc_attach_sdio/sd/mmcif (host->caps & MMC_CAP_NEEDS_POLL)mmc_schedule_delayed_work(&host->detect, HZ);sdhci_add_hostmmc_add_hostmmc_start_hostmmc_gpiod_request_cd_irqmmc_gpio_cd_irqtmmc_detect_change_mmc_detect_change_mmc_detect_changemmc_schedule_delayed_work(&host->detect, delay);

mmc_rescan调用mmc_rescan_try_freq来使用freqs里面的频率表来枚举,一般是400k,300k,200k,100k

void mmc_rescan(struct work_struct *work)
{struct mmc_host *host =container_of(work, struct mmc_host, detect.work);int i;if (host->rescan_disable)return;/* If there is a non-removable card registered, only scan once */if (!mmc_card_is_removable(host) && host->rescan_entered)return;host->rescan_entered = 1;if (host->trigger_card_event && host->ops->card_event) {mmc_claim_host(host);host->ops->card_event(host);mmc_release_host(host);host->trigger_card_event = false;}/* Verify a registered card to be functional, else remove it. */if (host->bus_ops)host->bus_ops->detect(host);host->detect_change = 0;/* if there still is a card present, stop here */if (host->bus_ops != NULL)goto out;mmc_claim_host(host);if (mmc_card_is_removable(host) && host->ops->get_cd &&host->ops->get_cd(host) == 0) {mmc_power_off(host);mmc_release_host(host);goto out;}/* If an SD express card is present, then leave it as is. */if (mmc_card_sd_express(host)) {mmc_release_host(host);goto out;}for (i = 0; i < ARRAY_SIZE(freqs); i++) {unsigned int freq = freqs[i];if (freq > host->f_max) {if (i + 1 < ARRAY_SIZE(freqs))continue;freq = host->f_max;}if (!mmc_rescan_try_freq(host, max(freq, host->f_min)))break;if (freqs[i] <= host->f_min)break;}/* A non-removable card should have been detected by now. */if (!mmc_card_is_removable(host) && !host->bus_ops)pr_info("%s: Failed to initialize a non-removable card",mmc_hostname(host));/** Ignore the command timeout errors observed during* the card init as those are excepted.*/host->err_stats[MMC_ERR_CMD_TIMEOUT] = 0;mmc_release_host(host);out:if (host->caps & MMC_CAP_NEEDS_POLL)mmc_schedule_delayed_work(&host->detect, HZ);
}

sdhci的intmask

cd脚跟sdio的数据脚等都是属于sdhci控制器控制,intmask是SDHCI_INT_CARD_INSERT或者SDHCI_INT_CARD_REMOVE就触发一次探测

static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
{struct sdhci_host *host = dev_id;struct mmc_command *cmd;unsigned long flags;u32 isr;while (!sdhci_request_done(host));spin_lock_irqsave(&host->lock, flags);isr = host->thread_isr;host->thread_isr = 0;cmd = host->deferred_cmd;if (cmd && !sdhci_send_command_retry(host, cmd, flags))sdhci_finish_mrq(host, cmd->mrq);spin_unlock_irqrestore(&host->lock, flags);if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {struct mmc_host *mmc = host->mmc;mmc->ops->card_event(mmc);mmc_detect_change(mmc, msecs_to_jiffies(200));}return IRQ_HANDLED;
}

MMC驱动pr_debug开启方法

CONFIG_DYNAMIC_DEBUG为第一优先级,开了直接通过debugfs打开对应文件日志

DEBUG为第二优先级,CONFIG_DYNAMIC_DEBUG没开的话,在对应文件,或文件的Makefile中加DEBUG宏,可让pr_debug替换成printk

/include/linux/printk.h#if defined(CONFIG_DYNAMIC_DEBUG) || \(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
#include <linux/dynamic_debug.h>/*** pr_debug - Print a debug-level message conditionally* @fmt: format string* @...: arguments for the format string** This macro expands to dynamic_pr_debug() if CONFIG_DYNAMIC_DEBUG is* set. Otherwise, if DEBUG is defined, it's equivalent to a printk with* KERN_DEBUG loglevel. If DEBUG is not defined it does nothing.** It uses pr_fmt() to generate the format string (dynamic_pr_debug() uses* pr_fmt() internally).*/
#define pr_debug(fmt, ...)			\dynamic_pr_debug(fmt, ##__VA_ARGS__)
#elif defined(DEBUG)
#define pr_debug(fmt, ...) \printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_debug(fmt, ...) \no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endifdrivers/mmc/Makefile
subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUGshell
echo 8 4 1 7 >  /proc/sys/kernel/printk

http://www.dtcms.com/a/318625.html

相关文章:

  • Python高级排序技术:非原生可比对象的自定义排序策略详解
  • 第14届蓝桥杯Scratch选拔赛初级及中级(STEMA)真题2022年11月27日
  • Java面试宝典:类加载器分层设计与核心机制解析
  • 栈与队列的基本逻辑
  • ToonMe:将照片转换为卡通风格的艺术作品
  • docker run 入门到进阶:容器启动背后的门道
  • 嵌入式开发入门—电感器
  • CASA模型原理详细解析
  • 【unity 中的RectTransform组件中的`RectTransform.sizeDelta理解】
  • Unity3D水下场景与游泳系统开发指南
  • ubuntu18.04在fstab文件中挂载硬盘失败,系统进入紧急模式的解决方法
  • js 从 json 中取 key 的值
  • 云平台托管集群:EKS、GKE、AKS 深度解析与选型指南-第一章
  • 磁悬浮转子变转速工况下的振动抑制全解析
  • 什么是「回调函数」 Callback Function ?
  • Linux(17)——Linux进程信号(上)
  • 28.(vue3.x+vite)el-pagination中文设置(兼容其他elementPlus组件)
  • PaddleOCR 多线程并发问题
  • K8S命令记录
  • 利用多线程设计群ping工具
  • 5G随身WiFi怎么选?实测延迟/网速/续航,中兴V50适合商务,格行MT700适合短租、户外党~避坑指南+适用场景全解析
  • 无监督学习之K-means算法
  • 古多倍体化对被子植物适应性进化的遗传贡献--文献精度154
  • 本地部署 SQLite 数据库管理工具 SQLite Browser ( Web ) 并实现外部访问
  • 根据经纬度(从nc格式环境数据文件中)提取环境因子
  • RabbitMQ面试精讲 Day 12:镜像队列与Quorum队列对比
  • PCL 平面特征点提取
  • 2 SpringBoot项目对接单点登录说明
  • C语言控制语句练习题3
  • 数据结构与算法