I2C总线驱动程序

I2C总线驱动程序

内核中 I2C 的处理已经做好了,我们只需要做设备驱动程序相关的内容。总线处理好了 I2C 协议,即总线知道如何收发数据,而不知道数据的含义,我们要做的只是设备相关层的代码。

I2C驱动分为两层:
总线层:

知道设备如何读写。芯片厂家会帮我们做好。操作寄存器。 drivers\i2c\busses

设备层驱动层:

知道数据的含义。 drivers\i2c\chips

总线层:

drivers\i2c\busses\i2c-s3c2410.c

static int __init i2c_adap_s3c_init(void)
{
    return platform_driver_register(&s3c24xx_i2c_driver);
}

注册一个平台设备,当内核中有同名“s3c2440-i2c”的平台设备时,“.probe = s3c24xx_i2c_probe,”就被调用。

static struct platform_driver s3c24xx_i2c_driver = {
    .probe      = s3c24xx_i2c_probe,
    .remove     = s3c24xx_i2c_remove,
    .suspend_late   = s3c24xx_i2c_suspend_late,
    .resume     = s3c24xx_i2c_resume,
    .id_table   = s3c24xx_driver_ids,
    .driver     = {
        .owner  = THIS_MODULE,
        .name   = "s3c-i2c",
    },
};

I2C总线驱动程序_第1张图片


1、分配结构体:i2c_adapter

struct i2c_adapter {
    struct module *owner;
    unsigned int id;
    unsigned int class;       /* classes to allow probing for */
    const struct i2c_algorithm *algo; /* the algorithm to access the bus */
    void *algo_data;

2,设置结构 i2c_adapter:

核心是设置“i2c_algorithm 算法结构”。
a,如何收发起始信号、数据、响应等.
b,i2c_adapter 结构中有 i2c_algorithm 算法结构。

static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
    .master_xfer        = s3c24xx_i2c_xfer,//传输函数
    .functionality      = s3c24xx_i2c_func,
};
2.1、probe中adapt及其他操作
int s3c24xx_i2c_probe(struct platform_device *pdev)
---->i2c->clk = clk_get(&pdev->dev, "i2c"); 使能I2C时钟。
---->I2C适配器结构“i2c_adapter”:
i2c->adap.owner   = THIS_MODULE;
i2c->adap.algo    = &s3c24xx_i2c_algorithm;  //算法
i2c->adap.retries = 2;
i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
i2c->tx_setup     = 50;

---->ret = s3c24xx_i2c_init(i2c); //硬件相关初始化。
---->request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED, pdev->name, i2c); //注册中断
---->i2c_add_adapter(&i2c->adap); //注册I2C适配器
---->i2c_register_adapter(adapter);
2.2、算法结构中“.master_xfer”是核心
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
            struct i2c_msg *msgs, int num)
{
    struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
    int retry;
    int ret;
    for (retry = 0; retry < adap->retries; retry++) {
        //执行传输
        ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
        if (ret != -EAGAIN)
            return ret;
        dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
        udelay(100);
    }
    return -EREMOTEIO;
}
2.3、执行传输:
int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num)
-->s3c24xx_i2c_enable_irq(i2c); 使能中断
-->s3c24xx_i2c_message_start(i2c, msgs); 起动传输,会产生各种中断。
-->wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); 等待事件完成。
2.4、起动传输:设置寄存器

寄存器:
S3C2410_IICCON :I2C控制寄存器
S3C2410_IICSTAT :I2C状态寄存器
S3C2410_IICADD :
S3C2410_IICDS :I2C DS寄存器
S3C2440_IICLC :

void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, struct i2c_msg *msg)
-->iiccon = readl(i2c->regs + S3C2410_IICCON);
-->writel(stat, i2c->regs + S3C2410_IICSTAT);
-->writeb(addr, i2c->regs + S3C2410_IICDS);

3、注册“i2c_adapter”

static int s3c24xx_i2c_probe(struct platform_device *pdev)
    ret = i2c_add_numbered_adapter(&i2c->adap);
    if (ret < 0) {
        dev_err(&pdev->dev, "failed to add bus to i2c core\n");
        goto err_cpufreq;
    }
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
    ---->i2c_register_adapter(adap);
    --------> device_register(&adap->dev);

drv

裸板程序中发现设备:
先发一个“STATT”信号,再发出 7bit 的设备地址,若设备存在,则在第 9 个时钟里,此存在的设备(从机)会把“SDA”信号线拉低作为 ACK 回应,这样主机就知道有相对应地址的设备存在

USB 总线会自动识别新接入的 USB 设备。但 I2C 总线不能。需要:
1,发出 START 信号
2,发出设备地址。
才能知道是否有此设备存在。
从“i2c_adapter”结构的“adapter”链表取出“i2c 总线”中的一个一个驱动程序
(称为“适配器”),使用里面的“.smbus_xfer”函数发“start”信号、发设备地址
(在 I2C 设备驱动的 i2c_driver 结构中,成员“.id”就是表示支持哪些 I2C 设备)、

static int __init pca9539_init(void)
{
    return i2c_add_driver(&pca9539_driver);
}
static struct i2c_driver pca9539_driver = {
    .driver = {
        .name   = "pca9539",
    },
    .probe      = pca9539_probe,
    .remove     = pca9539_remove,
    .id_table   = pca9539_id,

    .detect     = pca9539_detect,
    .address_data   = &addr_data,
};
static inline int i2c_add_driver(struct i2c_driver *driver)
{
    return i2c_register_driver(THIS_MODULE, driver);
}

对”adapters”链表里的每一个成员,调用”i2c_driver”结构里面的
attach_adapter()

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
--->driver->driver.bus = &i2c_bus_type; 总线是“i2c_bus_type”。
--->driver_register(&driver->driver); 注册一个“i2c_driver”结构体。
--->class_for_each_device(&i2c_adapter_class, NULL, driver,__attach_adapter);
static struct class i2c_adapter_class = {
    .owner          = THIS_MODULE,
    .name           = "i2c-adapter",
    .dev_attrs      = i2c_adapter_attrs,
};

你可能感兴趣的:(linux驱动)