程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

linux驱动移植-I2C适配器驱动移植

Mini2440裸机开发之I2C(AT24C08)我们介绍了S3C2440这款SOC的I2C结构,其内部只有一个I2C控制器,其中SCL连接GPE14引脚,SDA连接GPE15引脚。

这一节我们将研究S3C2440的I2C适配器驱动,或者说 I2C 总线驱动、I2C 控制器驱动。

I2C适配器驱动是基于platform模型的,主要提供一个algorithm底层的I2C协议的收发函数。在platform driver中probe函数中:

  • 动态分配i2c_adapter,并进行成员初始化,包括设置algo;
  • 初始化I2C总线所使用的的GPIO功能复用为I2C;
  • 初始化S3C2440 I2C控制器相关的寄存器,设置从设备地址、以及I2C时钟预分频系数;
  • 获取资源信息,并注册I2C中断处理函数;
  • 最后将i2c_adapter注册到i2c_bus_type总线,并且注册时会调用i2c_scan_board_info,扫描并使用i2c_new_device注册I2C从设备。

一、 platform设备注册(s3c2410-i2c)

1.1 s3c_device_i2c0

向往常一样,我们依然是定位到arch/arm/mach-s3c24xx/mach-smdk2440.c文件,在该文我们可以找到platform设备s3c_device_i2c0变量,其定义在arch/arm/plat-samsung/devs.c文件:

复制代码
/* I2C */

static struct resource s3c_i2c0_resource[] = {
        [0] = DEFINE_RES_MEM(S3C_PA_IIC, SZ_4K),
        [1] = DEFINE_RES_IRQ(IRQ_IIC),
};

struct platform_device s3c_device_i2c0 = {   // platform设备信息
        .name           = "s3c2410-i2c",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(s3c_i2c0_resource),
        .resource       = s3c_i2c0_resource,
};

struct s3c2410_platform_i2c default_i2c_data __initdata = {  // 用于初始化s3c_device_i2c0.dev.platform_data 
        .flags          = 0,
        .slave_addr     = 0x10,                // 从设备地址
        .frequency      = 100*1000,            // 频率 100kb  
        .sda_delay      = 100,
};

void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)  // 用于绑定s3c_device_i2c0.dev.platform_data和default_i2c_data的关系
{
        struct s3c2410_platform_i2c *npd;

        if (!pd) {
                pd = &default_i2c_data;
                pd->bus_num = 0;
        }

        npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c0);  // s3c_device_i2c0.dev.platform_data = &default_i2c_data

        if (!npd->cfg_gpio):
                npd->cfg_gpio = s3c_i2c0_cfg_gpio;
}
复制代码

我们重点关注一下platform设备资源定义,这里定义了2个资源,第1个是内存资源、第2个是中断资源:

  • 第一个资源是IO内存资源,起始地址是I2C寄存器寄基地址,即0x54000000,大小为4Kb;
  • 第二个资源是中断资源,中断号位IRQ_IIC,即27;

我们已经定义了I2C控制器相关的platform_device设备s3c_device_i2c0,并进行了初始化,那platform设备啥时候注册的呢?

linux内核启动的时候会根据uboot中设置的机器id执行相应的初始化工作,比如.init_machine、.init_irq,我们首先定位到arch/arm/mach-s3c24xx/mach-smdk2440.c:

复制代码
MACHINE_START(S3C2440, "SMDK2440")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
        .atag_offset    = 0x100,

        .init_irq       = s3c2440_init_irq,
        .map_io         = smdk2440_map_io,
        .init_machine   = smdk2440_machine_init,
        .init_time      = smdk2440_init_time,
MACHINE_END
复制代码

重点关注init_machine,init_machine中保存的是开发板资源注册的初始化代码。

1.2 smdk2440_machine_init

static void __init smdk2440_machine_init(void)
{
        s3c24xx_fb_set_platdata(&smdk2440_fb_info);   
        s3c_i2c0_set_platdata(NULL);   // 初始化s3c_device_i2c0.dev.platform_data

        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));  // s3c2440若干个platform设备注册 usb host controller、lcd、wdt等
        smdk_machine_init();  // s3c24x0系列若干个platform设备注册(通用)
}

这里利用platform_add_devices进行若干个platform设备的注册,该函数通过调用platform_device_register实现platform设备注册。

static struct platform_device *smdk2440_devices[] __initdata = {
        &s3c_device_ohci,
        &s3c_device_lcd,
        &s3c_device_wdt,
        &s3c_device_i2c0,
        &s3c_device_iis,
        &smdk2440_device_eth,
};

platform设备s3c_device_i2c0是通过arch/arm/plat-samsung/include/plat/devs.h头文件引入的。

二、platform驱动注册(s3c2410-i2c)

I2C控制器platform驱动定义位于drivers/i2c/busses/i2c-s3c2410.c文件中。

2.1 入口和出口函数

我们在i2c-s3c2410.c文件定位到驱动模块的入口和出口:

复制代码
static const struct platform_device_id s3c24xx_driver_ids[] = {
        {
                .name           = "s3c2410-i2c",
                .driver_data    = 0,
        }, {
                .name           = "s3c2440-i2c",
                .driver_data    = QUIRK_S3C2440,
        }, {
                .name           = "s3c2440-hdmiphy-i2c",
                .driver_data    = QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO,
        }, { },
};


static const struct of_device_id s3c24xx_i2c_match[] = {   // 设备树匹配时使用
        { .compatible = "samsung,s3c2410-i2c", .data = (void *)0 },
        { .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 },
        { .compatible = "samsung,s3c2440-hdmiphy-i2c",
          .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) },
        { .compatible = "samsung,exynos5-sata-phy-i2c",
          .data = (void *)(QUIRK_S3C2440 | QUIRK_POLL | QUIRK_NO_GPIO) },
        {},
};


static struct platform_driver s3c24xx_i2c_driver = {
        .probe          = s3c24xx_i2c_probe,
        .remove         = s3c24xx_i2c_remove,
        .id_table       = s3c24xx_driver_ids,
        .driver         = {
                .name   = "s3c-i2c",
                .pm     = S3C24XX_DEV_PM_OPS,
                .of_match_table = of_match_ptr(s3c24xx_i2c_match),
        },
};

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

static void __exit i2c_adap_s3c_exit(void)
{
        platform_driver_unregister(&s3c24xx_i2c_driver);
}
module_exit(i2c_adap_s3c_exit);
复制代码

在plaftrom总线设备驱动模型中,我们知道当内核中有platform设备platform驱动匹配,会调用到platform_driver里的成员.probe,在这里就是s3c24xx_i2c_probe函数。

2.2 I2C相关数据结构

2.2.1 s3c24xx_i2c

在介绍s3c24xx_i2c_probe之前,先来看一下s3c24xx_i2c结构体定义,其定义在drivers/i2c/busses/i2c-s3c2410.c文件:

复制代码
struct s3c24xx_i2c {  // 用来表示SOC的一个I2C控制器
        wait_queue_head_t       wait;   // 等待队列
        kernel_ulong_t          quirks;  // I2C控制器的一些特殊行为

        struct i2c_msg          *msg;     // 存放要发送的I2C数据包
        unsigned int            msg_num;  // 数据包个数  实际只有1个
        unsigned int            msg_idx;  // 当前发送的数据包索引 
        unsigned int            msg_ptr;  // 当前传输的字节在数据包的索引

        unsigned int            tx_setup;  // 用来延时,等待SCL被释放
        unsigned int            irq;       // 中断号

        enum s3c24xx_i2c_state  state;     // I2C传输状态  STATE_START、STATE_IDEL、STATE_STOP、STATE_WRITE、STATE_READ
        unsigned long           clkrate;

        void __iomem            *regs;
        struct clk              *clk;     // 时钟 
        struct device           *dev;     // 存储platform设备的dev成员    
        struct i2c_adapter      adap;     // 描述该I2C控制器的适配器

        struct s3c2410_platform_i2c     *pdata;  // 私有数据 默认初始化为&default_i2c_data
        int                     gpios[2];
        struct pinctrl          *pctrl;
#if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
        struct notifier_block   freq_transition;
#endif
        struct regmap           *sysreg;
        unsigned int            sys_i2c_cfg;
};
复制代码
2.2.2 s3c2410_platform_i2c

s3c2410_platform_i2c定义在include/linux/platform_data/i2c-s3c2410.h文件:

复制代码
/**
 *      struct s3c2410_platform_i2c - Platform data for s3c I2C.
 *      @bus_num: The bus number to use (if possible).
 *      @flags: Any flags for the I2C bus (E.g. S3C_IICFLK_FILTER).
 *      @slave_addr: The I2C address for the slave device (if enabled).
 *      @frequency: The desired frequency in Hz of the bus.  This is
 *                  guaranteed to not be exceeded.  If the caller does
 *                  not care, use zero and the driver will select a
 *                  useful default.
 *      @sda_delay: The delay (in ns) applied to SDA edges.
 *      @cfg_gpio: A callback to configure the pins for I2C operation.
 */
struct s3c2410_platform_i2c {
        int             bus_num;    // I2C控制器编号
        unsigned int    flags;
        unsigned int    slave_addr;  // 从设备地址 
        unsigned long   frequency;   // 时钟频率 
        unsigned int    sda_delay;

        void    (*cfg_gpio)(struct platform_device *dev);  // 初始化gpio口 功能复用I2C
};
复制代码

2.3 s3c24xx_i2c_probe

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(235)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示