linux之i2c子系统架构---总线驱动

发布时间:2024-07-19  

 

 

编写i2c设备驱动(从设备)一般有两种方式:

1.用户自己编写独立的从设备驱动,应用程序直接使用即可。

2.linux内核内部已经实现了一个通用的设备驱动,利用通用设备驱动编写一个应用程序(用户态驱动),在应用程序中用到大量设备驱动提供的接口,通过应用程序来控制从设备。


总线驱动

4.1 概述

I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和master_xfer的实现函数。

I2C总线驱动由i2c_adapter和i2c_algorithm来描述

 

4.2 S3c2440I2C控制器的硬件描述

S3c2440处理器内部集成了一个I2C控制器,通过四个寄存器来进行控制:

IICCON     I2C控制寄存器

IICSTAT     I2C状态寄存器

IICDS       I2C收发数据移位寄存器

IICADD     I2C地址寄存器

通过IICCON,IICDS,IICADD寄存器操作,可在I2C总线上产生开始位、停止位、数据和地址,而传输的状态则通过IICSTAT寄存器来获取。

 

4.3 i2c-s3c2410总线驱动分析(platform_driver)

I2C总线驱动代码在drivers/i2c/busses/i2c-s3c2410.c,这个代码同样支持s3c2410,s3c6410,s5pc110等Samsung 系列的芯片。


初始化模块和卸载模块


static int __init i2c_adap_s3c_init(void)  

{  

         returnplatform_driver_register(&s3c24xx_i2c_driver);  

}  

   

static void __exit i2c_adap_s3c_exit(void)  

{  

         platform_driver_unregister(&s3c24xx_i2c_driver);  

}  

总线驱动是基于platform来实现的,很符合设备驱动模型的思想。


static struct platform_drivers3c24xx_i2c_driver = {  

         .probe                = s3c24xx_i2c_probe,  

         .remove            = s3c24xx_i2c_remove,  

         .id_table  = s3c24xx_driver_ids,  

         .driver                = {  

                   .owner     = THIS_MODULE,  

                   .name       = "s3c-i2c",  

                   .pm  = S3C24XX_DEV_PM_OPS,  

                   .of_match_table= s3c24xx_i2c_match,  

         },  

};  

s3c24xx_i2c_probe函数


当调用platform_driver_register函数注册platform_driver结构体时,如果platformdevice 和 platform driver匹配成功后,会调用probe函数,来初始化适配器硬件。


static int s3c24xx_i2c_probe(structplatform_device *pdev)  

{  

         ……  

         /*初始化适配器信息 */  

         strlcpy(i2c->adap.name,"s3c2410-i2c", sizeof(i2c->adap.name));  

         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;  

   

         /*初始化自旋锁和等待队列头 */  

         spin_lock_init(&i2c->lock);  

         init_waitqueue_head(&i2c->wait);  

   

         /*映射寄存器 */  

         res= platform_get_resource(pdev, IORESOURCE_MEM, 0);  

         i2c->ioarea= request_mem_region(res->start, resource_size(res),  

                                                pdev->name);  

         i2c->regs= ioremap(res->start, resource_size(res));  

   

         /*设置I2C核心需要的信息 */  

         i2c->adap.algo_data= i2c;  

         i2c->adap.dev.parent= &pdev->dev;  

   

         /*初始化I2C控制器 */  

         ret= s3c24xx_i2c_init(i2c);  

   

         /*申请中断 */  

         i2c->irq= ret = platform_get_irq(pdev, 0);  

         ret= request_irq(i2c->irq, s3c24xx_i2c_irq, 0,  

                              dev_name(&pdev->dev), i2c);  

   

   /* 注册I2C适配器 */  

         ret= i2c_add_numbered_adapter(&i2c->adap);  

         ……  

}  

Probe主要工作是时能硬件并申请I2C适配器使用的IO地址,中断号等,然后向I2C核心添加这个适配器。I2c_adapter注册过程i2c_add_numbered_adapter->i2c_register_adapter


 


I2C总线通信方法


static const struct i2c_algorithms3c24xx_i2c_algorithm = {  

         .master_xfer             = s3c24xx_i2c_xfer,  

         .functionality             = s3c24xx_i2c_func,  

};  

s3c24xx_i2c_xfer函数是总线通信方式的具体实现,依赖于s3c24xx_i2c_doxfer和s3c24xx_i2c_message_start两个函数;


static int s3c24xx_i2c_doxfer(structs3c24xx_i2c *i2c,  

                                  struct i2c_msg *msgs, int num)  

{  

         ret =s3c24xx_i2c_set_master(i2c);  

   

         i2c->msg     = msgs;  

         i2c->msg_num= num;  

         i2c->msg_ptr= 0;  

         i2c->msg_idx= 0;  

         i2c->state   = STATE_START;  

   

         s3c24xx_i2c_message_start(i2c,msgs);  

}  

首先设置s3c I2C设备器为主设备,然后调用s3c24xx_i2c_message_start函数启动I2C消息传输。


s3c24xx_i2c_func函数返回适配器所支持的通信功能。


 


4.4 适配器的设备资源(platform_device)


S3c2440的I2C总线驱动是基于platform来实现,前面我们分析了platformdriver部分,再来看下platform device部分。


在arch/arm/plat-samsung/dev-i2c0.c文件中定义了platform_device结构体以及I2C控制器的资源信息:


static struct resource s3c_i2c_resource[] ={  

         [0]= {  

                   .start= S3C_PA_IIC,  

                   .end   = S3C_PA_IIC + SZ_4K - 1,  

                   .flags= IORESOURCE_MEM,  

         },  

         [1]= {  

                   .start= IRQ_IIC,  

                  .end  = IRQ_IIC,  

                   .flags= IORESOURCE_IRQ,  

         },  

};  

   

struct platform_device s3c_device_i2c0 = {  

         .name                 = "s3c2410-i2c",   /* 设备名 */  

#ifdef CONFIG_S3C_DEV_I2C1  

         .id               = 0,  

#else  

         .id               = -1,  

#endif  

         .num_resources         =ARRAY_SIZE(s3c_i2c_resource),  

         .resource   =s3c_i2c_resource,  

};  

   

struct s3c2410_platform_i2cdefault_i2c_data __initdata = {  

         .flags                  = 0,  

         .slave_addr      = 0x10,  /* I2C适配器的地址 */  

         .frequency        = 100*1000,  /* 总线频率 */  

         .sda_delay        = 100,   /* SDA边沿延迟时间ns */  

};  

   

void __init s3c_i2c0_set_platdata(structs3c2410_platform_i2c *pd)  

{  

         structs3c2410_platform_i2c *npd;  

   

         if(!pd)  

                   pd= &default_i2c_data;  

   

         npd= s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c),  

                                   &s3c_device_i2c0);  

   

         if(!npd->cfg_gpio)  

                   npd->cfg_gpio= s3c_i2c0_cfg_gpio;  

}  

在板文件中把platform_device注册进内核:


static struct platform_device*mini2440_devices[] __initdata = {  

         ……  

         &s3c_device_i2c0,  

……  

};  

调用s3c_i2c0_set_platdata 函数把适配器具体的数据赋值给dev.platform_data:


static void __init mini2440_init(void)  

{  

         ……  

s3c_i2c0_set_platdata(NULL);  

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>