S5PV210芯片I2C适配器驱动分析(i2c

阅读: 评论:0

S5PV210芯片I2C适配器驱动分析(i2c

S5PV210芯片I2C适配器驱动分析(i2c

1、什么是适配器驱动

(1)适配器驱动就是用来控制Soc上的I2C控制器的,封装I2C控制器的通信方式;
(2)适配器驱动会向I2C核心层注册,I2C核心层会管理内核中所有注册的适配器驱动,每一个注册的适配器驱动就代表Soc中的一个I2C控制器;
(3)I2C接口设备的驱动会通过I2C总线匹配上对应的适配器,然后调用适配器提供的数据收发接口进行通信;

2、适配器驱动怎么和Soc上的I2C控制器对应

/*********gslX680.c**************/
#define GSLX680_I2C_NAME 	"gslX680"static struct i2c_driver gsl_ts_driver = {.driver = {.name = GSLX680_I2C_NAME,.owner = THIS_MODULE,},
#ifndef CONFIG_HAS_EARLYSUSPEND.suspend	= gsl_ts_suspend,.resume	= gsl_ts_resume,
#endif.probe		= gsl_ts_probe,.remove		= __devexit_p(gsl_ts_remove),.id_table	= gsl_ts_id,
};//函数调用关系
gsl_ts_init()	//驱动加载函数i2c_add_driver(&gsl_ts_driver);	//向I2C总线注册gslX680驱动gsl_ts_probe()	//当gslX680驱动在I2C总线上匹配上struct i2c_client时就会调用probe方法/*********内核注册i2c_board_info信息************/
static struct i2c_board_info i2c_devs1[] __initdata = {{I2C_BOARD_INFO("gslX680", 0x40),	//gslX680是用来和驱动匹配的名字,0x40是设备在I2C总线上的地址},};smdkc110_machine_init()	//struct machine_desc->init_machine()i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));	//向编号是1的适配器注册i2c_board_info信息

(1)上面是gslX680触摸屏驱动代码和在I2C总线上的匹配相关部分的代码;
(2)struct i2c_board_info结构体:会用来构成struct i2c_client结构体,将来I2C接口设备的驱动在I2C总线上匹配设备时,就会用名字来进行匹配,哪一个适配器上有该驱动的名字就会和哪个适配器匹配成功,并且还会把struct i2c_board_info结构体里的信息传给I2C驱动,比如:设备地址、中断号;
(3)每个适配器都会注册struct i2c_board_info结构体信息,将来struct i2c_board_info结构体里的名字会和I2C驱动的名字进行匹配, I2C驱动和适配器匹配上,将来I2C驱动通信就通过匹配上的适配器,也就是硬件上I2C接口设备接在哪一个I2C控制器;

3、适配器驱动的加载过程

static struct platform_device_id s3c24xx_driver_ids[] = {{.name		= "s3c2410-i2c",.driver_data	= TYPE_S3C2410,}, {.name		= "s3c2440-i2c",.driver_data	= TYPE_S3C2440,}, { },
};static struct platform_driver s3c24xx_i2c_driver = {.probe		= s3c24xx_i2c_probe,.remove		= s3c24xx_i2c_remove,.id_table	= s3c24xx_driver_ids,	//在platform总线上匹配设备时使用.driver		= {.owner	= THIS_MODULE,.name	= "s3c-i2c",.pm	= S3C24XX_DEV_PM_OPS,},
};i2c_adap_s3c_init()	//驱动加载函数platform_driver_register(&s3c24xx_i2c_driver);	//利用平台总线进行注册s3c24xx_i2c_probe()	//在平台总线上匹配上设备后调用probe函数i2c_add_numbered_adapter(&i2c->adap);	//利用platform_device传过来的数据构建适配器结构体,并向I2C核心层注册

(1) 在内核的struct machine_desc->init_machine()函数中会注册plat_device,会有多个plat_device和platform总线驱动s3c24xx_i2c_driver匹配上,基本上是Soc有几个I2C控制器就匹配上几次,也就是会向I2C核心层注册多个适配器;
(2)虽然被匹配上多次,但是每次plat_device传过来的数据都是不同的,包括I2C控制器的寄存器物理地址、中断号、适配器编号等;

4、I2C总线驱动描述结构体

struct s3c24xx_i2c {spinlock_t		lock;wait_queue_head_t	wait;	//为了实现同步,使i2c->algorithm->master_xfer函数能在中断中的传输过程完成时返回unsigned int		suspended:1;//记录待传输数据的信息struct i2c_msg		*msg;	//消息队列unsigned int		msg_num;	//消息队列中的消息数unsigned int		msg_idx;	//当前传输的消息是序列中的第几条unsigned int		msg_ptr;	//传输的是当前的第几个字节unsigned int		tx_setup;	//传输建立延时unsigned int		irq;	//使用的中断号enum s3c24xx_i2c_state	state;	//当前传输的状态,进行到哪一步unsigned long		clkrate;void __iomem		*regs;	//用于访问内核IO内存的实际地址struct clk		*clk;struct device		*dev;struct resource		*ioarea;	//IO内存资源struct i2c_adapter	adap;	//对应的适配器
};

5、适配器驱动的probe方法实现

static int s3c24xx_i2c_probe(struct platform_device *pdev)
{struct s3c24xx_i2c *i2c;struct s3c2410_platform_i2c *pdata;struct resource *res;int ret;//解析处platform总线设备传递的信息pdata = pdev->dev.platform_data;i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);//设置适配器的名字strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));//构建适配器结构体adapi2c->adap.owner   = THIS_MODULE;i2c->adap.algo    = &s3c24xx_i2c_algorithm;	//设置适配器的通信方法i2c-&ies = 2;						//重发次数是2i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;i2c->tx_setup     = 50;//初始化自旋锁和等待队列spin_lock_init(&i2c->lock);init_waitqueue_head(&i2c->wait);/* 获取I2C控制器的时钟并使能 */i2c->dev = &pdev->dev;i2c->clk = clk_get(&pdev->dev, "i2c");	//获取时钟系统给I2C控制器的提供的时钟频率clk_enable(i2c->clk);	//使能时钟/* 获取I2C控制器的IO地址资源 */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));//在master_xfer等方法中就能通过适配器的algo_data获取对应的i2c对象i2c->adap.algo_data = i2c;i2c->adap.dev.parent = &pdev->dev;//初始化芯片的I2C控制器:使能中断、ACK使能、设置对应的GPIO、初始化时钟等ret = s3c24xx_i2c_init(i2c);if (ret != 0)goto err_iomap;//获取中断号资源i2c->irq = ret = platform_get_irq(pdev, 0);if (ret <= 0) {dev_err(&pdev->dev, "cannot find IRQn");goto err_iomap;}//申请中断号并绑定中断处理程序s3c24xx_i2c_irqret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,dev_name(&pdev->dev), i2c);//利用内核通知链机制,当CPU频率变化时,时I2C时钟设置能做出调整ret = s3c24xx_i2c_register_cpufreq(i2c);if (ret < 0) {dev_err(&pdev->dev, "failed to register cpufreq notifiern");goto err_irq;}//从platform总线设备获得适配器的总线编号i2c-& = pdata->bus_num;//向I2C核心层注册适配器ret = i2c_add_numbered_adapter(&i2c->adap);if (ret < 0) {dev_err(&pdev->dev, "failed to add bus to i2c coren");goto err_cpufreq;}//将i2c保存到pdev->dev->p->driver_dataplatform_set_drvdata(pdev, i2c);clk_disable(i2c->clk);dev_info(&pdev->dev, "%s: S3C I2C adaptern", dev_name(&i2c->adap.dev));return 0;······
}

6、I2C总线通信方法

6.1、适配器的通信方法

static const struct i2c_algorithm s3c24xx_i2c_algorithm = {.master_xfer		= s3c24xx_i2c_xfer,.functionality		= s3c24xx_i2c_func,
};

6.2、数据通信的函数调用关系

s3c24xx_i2c_xfer() //adap->algo->master_xfers3c24xx_i2c_doxfer()s3c24xx_i2c_set_master()	//确保当前I2C控制器处于空闲,才继续下面的操作s3c24xx_i2c_enable_irq()	//使能i2C-Bus的Tx/Rx中断s3c24xx_i2c_message_start()	//开启I2C通信wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);	//发送函数进入等待,直到消息发送完成或者超过5s返回在中断程序中唤醒等待队列:s3c24xx_i2c_irq()	//适配器绑定的中断处理函数i2c_s3c_irq_nextbyte()	//发送数据s3c24xx_i2c_stop()	//当数据收发完成或者通信出错时停止本次传输s3c24xx_i2c_master_complete()	//本次传输完成wake_up(&i2c->wait);	//唤醒等待队列

(1)I2C适配器描述结构体struct i2c_adapter中algo变量是适配器的通信方法,在驱动程序的prob函数中赋值;
(2)通信是以消息(struct i2c_msg)为单位进行的,消息描述结构体会指明要发送的设备的地址、数据传输方向等;

6.3、通信过程

(1)首先是I2C设备驱动调用适配器的adap->algo->master_xfer进行发送消息,master_xfer方法在进行一些初始化后,开启本次I2C通信,然后就进入等待队列,直到消息发送完成或者5秒超时后返回;
(2)具体的发送是在probe方法绑定了中断函数中进行,这个中断函数是I2C控制器的中断处理函数,在发送完数据或者出错后,就会唤醒之前在等待s3c24xx_i2c_doxfer()函数;

本文发布于:2024-01-30 06:12:54,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170656637619801.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:适配器   芯片   i2c   I2C
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23