PCI device about MMC/SD host controller

本文详细解析了PCI SDHCI驱动的工作原理,包括pci_device_id结构体定义、设备ID宏定义、pci驱动注册流程、设备探测函数及主机操作结构体等核心内容。特别关注了Ricoh SDHCI控制器的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

include/linux/mod_devicetable.h

#ifdef __KERNEL__
#include <linux/types.h>
typedef unsigned long kernel_ulong_t;
#endif

#define PCI_ANY_ID (~0)

struct pci_device_id {
        __u32 vendor, device;           /* Vendor and device ID or PCI_ANY_ID*/
        __u32 subvendor, subdevice;     /* Subsystem ID's or PCI_ANY_ID */
        __u32 class, class_mask;        /* (class,subclass,prog-if) triplet */
        kernel_ulong_t driver_data;     /* Data private to the driver */
};

===========================================================

device/mmc/host/sdhci-pci.c

static const struct pci_device_id pci_ids[] __devinitdata = {
        {
                .vendor         = PCI_VENDOR_ID_RICOH,
                .device         = PCI_DEVICE_ID_RICOH_R5C822,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
                .driver_data    = (kernel_ulong_t)&sdhci_ricoh,
        },

 

static struct pci_driver sdhci_driver = {
        .name =         "sdhci-pci",
        .id_table =     pci_ids,
        .probe =        sdhci_pci_probe,
        .remove =       __devexit_p(sdhci_pci_remove),
        .driver =       {
                .pm =   &sdhci_pci_pm_ops
        },
};
============================================================

include/linux/pci_ids.h定义了vendor和device的ID。

#define PCI_VENDOR_ID_RICOH             0x1180
#define PCI_DEVICE_ID_RICOH_RL5C465     0x0465
#define PCI_DEVICE_ID_RICOH_RL5C466     0x0466
#define PCI_DEVICE_ID_RICOH_RL5C475     0x0475
#define PCI_DEVICE_ID_RICOH_RL5C476     0x0476
#define PCI_DEVICE_ID_RICOH_RL5C478     0x0478
#define PCI_DEVICE_ID_RICOH_R5C822      0x0822
#define PCI_DEVICE_ID_RICOH_R5CE823     0xe823
#define PCI_DEVICE_ID_RICOH_R5C832      0x0832
#define PCI_DEVICE_ID_RICOH_R5C843      0x0843

=============================================================================

struct sdhci_pci_chip {
        struct pci_dev          *pdev;

        unsigned int            quirks;
        unsigned int            quirks2;
        bool                    allow_runtime_pm;
        const struct sdhci_pci_fixes *fixes;

        int                     num_slots;      /* Slots on controller */
        struct sdhci_pci_slot   *slots[MAX_SLOTS]; /* Pointers to host slots */
};

======

 

static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot()device探测函数。

1. 从PCI配置空间中0x40处读取SLOT 信息。

     其中bit[0-2]是first bar address register number;

             bit[4-6]slot的个数。

 2. 接下来激活这个设备 pci_enable_device().

3.  申请一段内存给struct sdhci_pci_chip;并给其pci_dev 赋值。chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
              if (chip->fixes) {
                chip->quirks = chip->fixes->quirks;
                chip->quirks2 = chip->fixes->quirks2;
                chip->allow_runtime_pm = chip->fixes->allow_runtime_pm;
        }
     这个是各个pci不同设备特有的,每个都不同。

     chip->num_slots = slots;

pci_set_drvdata(pdev, chip);


chip->fixes->probe(chip);


 slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);

chip->slots[i] = slot;

=====================================================

static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot()

1. struct sdhci_host *host;

     host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot));

2.         slot = sdhci_priv(host);

        slot->chip = chip;
        slot->host = host;
        slot->pci_bar = bar;
        slot->rst_n_gpio = -EINVAL;
        slot->cd_gpio = -EINVAL;

3.     host->hw_name = "PCI";
        host->ops = &sdhci_pci_ops;
        host->quirks = chip->quirks;
        host->quirks2 = chip->quirks2;

        host->irq = pdev->irq;  //host controller 中断获取

        ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc));      //region IO port by request_region();

        host->ioaddr = pci_ioremap_bar(pdev, bar);     //map io memory.

        if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) {
            gpio_direction_output(slot->rst_n_gpio, 1);
            slot->host->mmc->caps |= MMC_CAP_HW_RESET;

        ret = sdhci_add_host(host);

   sdhci_pci_add_own_cd(slot);

====================================

static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
{
    struct sdhci_pci_slot *slot = dev_id;
    struct sdhci_host *host = slot->host;

    mmc_detect_change(host->mmc, msecs_to_jiffies(200));
    return IRQ_HANDLED;
}

static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
{
    int err, irq, gpio = slot->cd_gpio;

    slot->cd_gpio = -EINVAL;
    slot->cd_irq = -EINVAL;

    if (!gpio_is_valid(gpio))
        return;

    err = gpio_request(gpio, "sd_cd");
    if (err < 0)
        goto out;

    err = gpio_direction_input(gpio);
    if (err < 0)
        goto out_free;

    irq = gpio_to_irq(gpio);
    if (irq < 0)
        goto out_free;

    err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING |
              IRQF_TRIGGER_FALLING, "sd_cd", slot);
    if (err)
        goto out_free;

    slot->cd_gpio = gpio;
    slot->cd_irq = irq;

    return;

out_free:
    gpio_free(gpio);
out:
    dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n");
}

===========================================================

struct sdhci_pci_slot {
    struct sdhci_pci_chip    *chip;
    struct sdhci_host    *host;
    struct sdhci_pci_data    *data;

    int            pci_bar;
    int            rst_n_gpio;                    //putput pin to reset eMMC
    int            cd_gpio;                        //input pin to detect card inset/remove
    int            cd_irq;                           //gpio pin to irq num
};

The ops is sdhci_host ops:

static struct sdhci_ops sdhci_pci_ops = {
    .enable_dma    = sdhci_pci_enable_dma,
    .platform_8bit_width    = sdhci_pci_8bit_width,
    .hw_reset        = sdhci_pci_hw_reset,
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值