高通apq8098平台sd卡总结

高通apq8098平台sd卡总结

目录

参考链接:
https://blog.csdn.net/lsn946803746/article/details/52311654

msm8998-mtp.dtsi中,设备树的定义如下:

&sdhc_2 {
vdd-supply = <&pm8998_l21>;
qcom,vdd-voltage-level = <2950000 2960000>;
qcom,vdd-current-level = <200 800000>;

vdd-io-supply = <&pm8998_l13>;
qcom,vdd-io-voltage-level = <1808000 2960000>;
qcom,vdd-io-current-level = <200 22000>;

pinctrl-names = "active", "sleep";
pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;

qcom,clk-rates = <400000 20000000 25000000
            50000000 100000000 200000000>;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";

cd-gpios = <&tlmm 95 0x1>;

status = "ok";

};

sd的插入是通过gpio95去检测,然后产生中断,中断处理函数及申请函数如下:

void mmc_gpiod_request_cd_irq(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
int ret, irq;

if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio)
    return;

irq = gpiod_to_irq(ctx->cd_gpio);

/*
 * Even if gpiod_to_irq() returns a valid IRQ number, the platform might
 * still prefer to poll, e.g., because that IRQ number is already used
 * by another unit and cannot be shared.
 */
if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
    irq = -EINVAL;

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);

static irqreturn_t mmc_gpio_cd_irqt(int irq, void dev_id)
{
/
Schedule a card detection after a debounce timeout */
struct mmc_host *host = dev_id;

host->trigger_card_event = true;
mmc_detect_change(host, msecs_to_jiffies(200));

return IRQ_HANDLED;

}

void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
_mmc_detect_change(host, delay, true);
}
EXPORT_SYMBOL(mmc_detect_change);

static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
bool cd_irq)
{

mmc_schedule_delayed_work(&host->detect, delay);
}

mmc_schedule_delayed_work是调度一个延时队列,是在core.c实现的。
也就是当sd card 的插拔都会触发中断,加入延时工作队列
workqueue是在一开始就初始化好的,
workqueue = alloc_ordered_workqueue(“kmmcd”, 0);
初始化时,走如下流程:
sdhci-msm.c中
static int sdhci_msm_probe(struct platform_device *pdev)
{

host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);

ret = sdhci_add_host(host);
}
sdhci-pltfm.c中的
struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
const struct sdhci_pltfm_data *pdata,
size_t priv_size)
{

host = sdhci_alloc_host(&pdev->dev,
sizeof(struct sdhci_pltfm_host) + priv_size);
}

struct sdhci_host *sdhci_alloc_host(struct device *dev,
size_t priv_size)
{

mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev);

struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
int err;
struct mmc_host *host;

host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
if (!host)
	return NULL;

/* scanning will be enabled when we're ready */
host->rescan_disable = 1;
idr_preload(GFP_KERNEL);
spin_lock(&mmc_host_lock);
err = idr_alloc(&mmc_host_idr, host, 0, 0, GFP_NOWAIT);
if (err >= 0)
	host->index = err;
spin_unlock(&mmc_host_lock);
idr_preload_end();
if (err < 0) {
	kfree(host);
	return NULL;
}

dev_set_name(&host->class_dev, "mmc%d", host->index);

host->parent = dev;
host->class_dev.parent = dev;
host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev);

if (mmc_gpio_alloc(host)) {
	put_device(&host->class_dev);
	return NULL;
}

mmc_host_clk_init(host);

spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);

#ifdef CONFIG_PM
host->pm_notify.notifier_call = mmc_pm_notify;
#endif
setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);

/*
 * By default, hosts do not support SGIO or large requests.
 * They have to set these according to their abilities.
 */
host->max_segs = 1;
host->max_seg_size = PAGE_CACHE_SIZE;

host->max_req_size = PAGE_CACHE_SIZE;
host->max_blk_size = 512;
host->max_blk_count = PAGE_CACHE_SIZE / 512;

return host;

}

void mmc_rescan(struct work_struct *work)
{

mmc_rescan_try_freq(host, host->f_min);
}

int sdhci_add_host(struct sdhci_host *host)
{

ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
IRQF_SHARED, mmc_hostname(mmc), host);
}

kernel层上报sd卡插入事件的流程如下:
sdhci_thread_irq—>mmc_detect_change—>_mmc_detect_change—>mmc_schedule_delayed_work—>mmc_rescan—>mmc_rescan_try_freq() —>mmc_attach_sd—>mmc_add_card—>device_add

kernel层上报sd卡拔出事件的流程如下:
sdhci_thread_irq—>mmc_detect_change—>_mmc_detect_change—>mmc_schedule_delayed_work—>mmc_rescan—>mmc_sd_detect—>mmc_remove_card—>device_del

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值