OpenRisc-20-or1200下linux的i2c(二)

这段时间开始有点小忙了,但是还是坚持学习一下 linux ,至于上次记得是基于 linux 系统自带的 i2c-ocores.c 文件接口写了简单的测试程序,这次就基于opencores 社区上大虾写好的 i2c controller 总线驱动来做一下分析,这个总线驱动在 openrisc-3.1\drivers\i2c\busses 目录下 ~ 这个总线驱动是基于Richard Herveille编写的 i2c-master ipcore ,在 opencores 社区上可以下到这份 RTL 的代码,然后打开源码里面的 i2c_specs 说明文档看看这个 ipcores 的相关操作。

        openrisc-3.1\drivers\i2c\busses\i2c-ocores.c,好~Open之,

        然后回想一下之前blog里面写过的关于gpio字符驱动的内容,最后一步我们是把gpio的字符驱动封装成platform机制的,所以,照板煮碗,把代码拉到最后面就可以看到i2c-ocres.c也是同样的道理。


        First定义一个platform_driver结构

        Second初始化这个结构,指定其proberemove等函数,并初始化其中的driver变量

        Third实现其proberemove等函数

        以上是platform平台驱动的步骤。


        然后说明一下i2c总线驱动负责的工作是:

        First,申请i2c总线控制器所用到的硬件资源(IO、中断号、内存等等)。

        Second,向内核增加一个i2c_adapter数据结构表示这个总线驱动,并且实现i2c_adapter数据结构中的algo成员(即控制i2c控制器的代码)。


        所以总线驱动代码的综合效果就是将上面驱动负责的工作写入platform平台驱动,并注册完成i2c总线驱动。


        下面来分析一下~

        首先,例化关于i2c的平台驱动,这里编写的是对应i2c的总线驱动,所以在例化i2c总线驱动时的of_match_table列表要对应在DTS设备树文件中i2c的总线控制器的compatible,在module加载入kernel时才会按照名称搜索加载i2c的总线驱动。


        DTS设备树i2c描述:

  1. i2c0: ocores@93000000 {  
  2.              compatible = "opencores,i2c-ocores";  
  3.              reg = <0x93000000 0x8>;  
  4.              interrupts = <5>;  
  5.                
  6.              regstep = <1>;  
  7.              clock-frequency = <40000000>;  
  8.                
  9.              #address-cells = <1>;  
  10.              #size-cells = <0>;  
  11.              eeprom@54 {  
  12.                     compatible = "at24";  
  13.                     reg = <0x54>;  
  14.     };  
  15. };  
	i2c0: ocores@93000000 {
              compatible = "opencores,i2c-ocores";
              reg = <0x93000000 0x8>;
              interrupts = <5>;
              
              regstep = <1>;
              clock-frequency = <40000000>;
              
              #address-cells = <1>;
              #size-cells = <0>;
              eeprom@54 {
              		compatible = "at24";
              		reg = <0x54>;
		};
	};

        总线驱动注册代码:

  1. static struct of_device_id ocores_i2c_match[] = {  
  2.     { .compatible = "opencores,i2c-ocores", },  
  3.     {},  
  4. };  
  5. MODULE_DEVICE_TABLE(of, ocores_i2c_match);  
  6.   
  7. /* work with hotplug and coldplug */  
  8. MODULE_ALIAS("platform:ocores-i2c");  
  9.   
  10. static struct platform_driver ocores_i2c_driver = {  
  11.     .probe   = ocores_i2c_probe,  
  12.     .remove  = __devexit_p(ocores_i2c_remove),  
  13.     .suspend = ocores_i2c_suspend,  
  14.     .resume  = ocores_i2c_resume,  
  15.     .driver  = {  
  16.         .owner = THIS_MODULE,  
  17.         .name = "ocores-i2c",  
  18.         .of_match_table = ocores_i2c_match,  
  19.     },  
  20. };  
  21.   
  22. static int __init ocores_i2c_init(void)  
  23. {  
  24.     return platform_driver_register(&ocores_i2c_driver);  
  25. }  
  26.   
  27. static void __exit ocores_i2c_exit(void)  
  28. {  
  29.     platform_driver_unregister(&ocores_i2c_driver);  
  30. }  
  31.   
  32. module_init(ocores_i2c_init);  
  33. module_exit(ocores_i2c_exit);  
static struct of_device_id ocores_i2c_match[] = {
	{ .compatible = "opencores,i2c-ocores", },
	{},
};
MODULE_DEVICE_TABLE(of, ocores_i2c_match);

/* work with hotplug and coldplug */
MODULE_ALIAS("platform:ocores-i2c");

static struct platform_driver ocores_i2c_driver = {
	.probe   = ocores_i2c_probe,
	.remove  = __devexit_p(ocores_i2c_remove),
	.suspend = ocores_i2c_suspend,
	.resume  = ocores_i2c_resume,
	.driver  = {
		.owner = THIS_MODULE,
		.name = "ocores-i2c",
		.of_match_table = ocores_i2c_match,
	},
};

static int __init ocores_i2c_init(void)
{
	return platform_driver_register(&ocores_i2c_driver);
}

static void __exit ocores_i2c_exit(void)
{
	platform_driver_unregister(&ocores_i2c_driver);
}

module_init(ocores_i2c_init);
module_exit(ocores_i2c_exit);


        然后,要实现proberemove等函数

  1. static int __devinit ocores_i2c_probe(struct platform_device *pdev)  
  2. {  
  3.     struct ocores_i2c *i2c;  
  4.     struct ocores_i2c_platform_data *pdata;  
  5.     struct resource *res, *res2;  
  6.     int ret;  
  7.     int i;  
  8.   
  9.     //获取DTS文件中的IO资源(地址范围)  
  10.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  11.     if (!res)  
  12.         return -ENODEV;  
  13.   
  14.     //获取DTS文件中的中断号资源  
  15.     res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  
  16.     if (!res2)  
  17.         return -ENODEV;  
  18.   
  19.     //申请内存  
  20.     i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);  
  21.     if (!i2c)  
  22.         return -ENOMEM;  
  23.   
  24.     //检查是否有足够内存  
  25.     if (!devm_request_mem_region(&pdev->dev, res->start,  
  26.                      resource_size(res), pdev->name)) {  
  27.         dev_err(&pdev->dev, "Memory region busy\n");  
  28.         return -EBUSY;  
  29.     }  
  30.   
  31.     //i2c控制器wishbone总线物理地址映射到内核地址空间  
  32.     i2c->base = devm_ioremap_nocache(&pdev->dev, res->start,  
  33.                      resource_size(res));  
  34.     if (!i2c->base) {  
  35.         dev_err(&pdev->dev, "Unable to map registers\n");  
  36.         return -EIO;  
  37.     }  
  38.   
  39.     //例化一个指针指向platform_device的设备的私有数据域,这个数据从编译DTS文件时获取  
  40.     pdata = pdev->dev.platform_data;  
  41.     if (pdata) {  
  42.         i2c->regstep = pdata->regstep;  
  43.         i2c->clock_khz = pdata->clock_khz;  
  44.     } else {  
  45.         ret = ocores_i2c_of_probe(pdev, i2c);  
  46.         if (ret)  
  47.             return ret;  
  48.     }  
  49.   
  50.     //初始化i2c控制器,具体可参考i2c_specs  
  51.     ocores_init(i2c);  
  52.   
  53.     //初始化等待队列,目前我还没明白这个,水平有限  
  54.     init_waitqueue_head(&i2c->wait);  
  55.   
  56.     //申请设备使用的中断号,并注册中断函数  
  57.     ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0,  
  58.                    pdev->name, i2c);  
  59.     if (ret) {  
  60.         dev_err(&pdev->dev, "Cannot claim IRQ\n");  
  61.         return ret;  
  62.     }  
  63.   
  64.     /* hook up driver to tree */  
  65.     //将i2c保存到platform_device中dev成员的p成员的driver_data数据域中  
  66.     platform_set_drvdata(pdev, i2c);  
  67.     i2c->adap = ocores_adapter;  
  68.   
  69.     //将i2c保存到i2c_adapter中dev成员的p成员的driver_data数据域中  
  70.     i2c_set_adapdata(&i2c->adap, i2c);  
  71.     i2c->adap.dev.parent = &pdev->dev;  
  72.     i2c->adap.dev.of_node = pdev->dev.of_node;  
  73.   
  74.     /* add i2c adapter to i2c tree */  
  75.     //增加i2c adapter的数据结构  
  76.     ret = i2c_add_adapter(&i2c->adap);  
  77.     if (ret) {  
  78.         dev_err(&pdev->dev, "Failed to add adapter\n");  
  79.         return ret;  
  80.     }  
  81.   
  82.     /* add in known devices to the bus */  
  83.     //如果在DTS文件中有多个共享总线驱动的从设备便会枚举出来  
  84.     if (pdata) {  
  85.         for (i = 0; i < pdata->num_devices; i++)  
  86.             i2c_new_device(&i2c->adap, pdata->devices + i);  
  87.     }  
  88.   
  89.     return 0;  
  90. }  
static int __devinit ocores_i2c_probe(struct platform_device *pdev)
{
	struct ocores_i2c *i2c;
	struct ocores_i2c_platform_data *pdata;
	struct resource *res, *res2;
	int ret;
	int i;

	//获取DTS文件中的IO资源(地址范围)
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -ENODEV;

	//获取DTS文件中的中断号资源
	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res2)
		return -ENODEV;

	//申请内存
	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
	if (!i2c)
		return -ENOMEM;

	//检查是否有足够内存
	if (!devm_request_mem_region(&pdev->dev, res->start,
				     resource_size(res), pdev->name)) {
		dev_err(&pdev->dev, "Memory region busy\n");
		return -EBUSY;
	}

	//i2c控制器wishbone总线物理地址映射到内核地址空间
	i2c->base = devm_ioremap_nocache(&pdev->dev, res->start,
					 resource_size(res));
	if (!i2c->base) {
		dev_err(&pdev->dev, "Unable to map registers\n");
		return -EIO;
	}

	//例化一个指针指向platform_device的设备的私有数据域,这个数据从编译DTS文件时获取
	pdata = pdev->dev.platform_data;
	if (pdata) {
		i2c->regstep = pdata->regstep;
		i2c->clock_khz = pdata->clock_khz;
	} else {
		ret = ocores_i2c_of_probe(pdev, i2c);
		if (ret)
			return ret;
	}

	//初始化i2c控制器,具体可参考i2c_specs
	ocores_init(i2c);

	//初始化等待队列,目前我还没明白这个,水平有限
	init_waitqueue_head(&i2c->wait);

	//申请设备使用的中断号,并注册中断函数
	ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0,
			       pdev->name, i2c);
	if (ret) {
		dev_err(&pdev->dev, "Cannot claim IRQ\n");
		return ret;
	}

	/* hook up driver to tree */
	//将i2c保存到platform_device中dev成员的p成员的driver_data数据域中
	platform_set_drvdata(pdev, i2c);
	i2c->adap = ocores_adapter;

	//将i2c保存到i2c_adapter中dev成员的p成员的driver_data数据域中
	i2c_set_adapdata(&i2c->adap, i2c);
	i2c->adap.dev.parent = &pdev->dev;
	i2c->adap.dev.of_node = pdev->dev.of_node;

	/* add i2c adapter to i2c tree */
	//增加i2c adapter的数据结构
	ret = i2c_add_adapter(&i2c->adap);
	if (ret) {
		dev_err(&pdev->dev, "Failed to add adapter\n");
		return ret;
	}

	/* add in known devices to the bus */
	//如果在DTS文件中有多个共享总线驱动的从设备便会枚举出来
	if (pdata) {
		for (i = 0; i < pdata->num_devices; i++)
			i2c_new_device(&i2c->adap, pdata->devices + i);
	}

	return 0;
}


  1. static int __devexit ocores_i2c_remove(struct platform_device* pdev)  
  2. {  
  3.     //将之前保存在platform_device中dev成员的p成员的driver_data数据域中的数据取出  
  4.     struct ocores_i2c *i2c = platform_get_drvdata(pdev);  
  5.   
  6.     /* disable i2c logic */  
  7.     //无效i2c总线控制器  
  8.     oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)  
  9.           & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));  
  10.   
  11.     /* remove adapter & data */  
  12.     //删除完成注册的i2c_adapter  
  13.     i2c_del_adapter(&i2c->adap);  
  14.       
  15.     //删除platform_device中dev成员的p成员的driver_data  
  16.     platform_set_drvdata(pdev, NULL);  
  17.   
  18.     return 0;  
  19. }  
static int __devexit ocores_i2c_remove(struct platform_device* pdev)
{
	//将之前保存在platform_device中dev成员的p成员的driver_data数据域中的数据取出
	struct ocores_i2c *i2c = platform_get_drvdata(pdev);

	/* disable i2c logic */
	//无效i2c总线控制器
	oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)
		  & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));

	/* remove adapter & data */
	//删除完成注册的i2c_adapter
	i2c_del_adapter(&i2c->adap);
	
	//删除platform_device中dev成员的p成员的driver_data
	platform_set_drvdata(pdev, NULL);

	return 0;
}

        至于有关电源管理的suspendresume暂且忽略,内核配置中暂时不去实现。


        这样就注册好平台设备驱动。

        接下去就在源码中去结合注释和i2c-specs的文档好好看看通信算法处理函数,这也是我们从新开发总线驱动的时候必须去编写的代码~

        首先是定义i2c_adapter和其成员变量的algo算法

  1. static u32 ocores_func(struct i2c_adapter *adap)  
  2. {  
  3.     return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;  
  4. }  
  5.   
  6. //定义一个i2c_algorithm的数据结构,其中实现控制器通信算法master_xfer  
  7. //和functionality(master_xfer通信算法支持的协议)  
  8. static const struct i2c_algorithm ocores_algorithm = {  
  9.     .master_xfer    = ocores_xfer,  
  10.     .functionality  = ocores_func,  
  11. };  
  12.   
  13. //定义一个i2c_adapter,完成总线控制器的描述,并在probe中向内核注册  
  14. static struct i2c_adapter ocores_adapter = {  
  15.     .owner      = THIS_MODULE,  
  16.     .name       = "i2c-ocores",  
  17.     .class      = I2C_CLASS_HWMON | I2C_CLASS_SPD,  
  18.     .algo       = &ocores_algorithm,  
  19. };  
static u32 ocores_func(struct i2c_adapter *adap)
{
	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}

//定义一个i2c_algorithm的数据结构,其中实现控制器通信算法master_xfer
//和functionality(master_xfer通信算法支持的协议)
static const struct i2c_algorithm ocores_algorithm = {
	.master_xfer	= ocores_xfer,
	.functionality	= ocores_func,
};

//定义一个i2c_adapter,完成总线控制器的描述,并在probe中向内核注册
static struct i2c_adapter ocores_adapter = {
	.owner		= THIS_MODULE,
	.name		= "i2c-ocores",
	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
	.algo		= &ocores_algorithm,
};


        其中由于这个驱动是基于中断架构的收发,结合源码继续往下看。

        首先看看在probe中调用的ocores_init(),完成的是总线控制器的初始化

  1. //根据i2c-specs文档初始化总线控制器  
  2. //对比文档中的寄存器进行操作  
  3. static void ocores_init(struct ocores_i2c *i2c)  
  4. {  
  5.     int prescale;  
  6.   
  7.     //取出Control register寄存器的值,在i2c-specs中有说明~  
  8.     u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);  
  9.   
  10.     /* make sure the device is disabled */  
  11.     //i2c cores禁止中断和无效总线控制器  
  12.     oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));  
  13.   
  14.     //设置i2c总线控制器的通信速率,在i2c-specs文档有计算公式  
  15.     prescale = (i2c->clock_khz / (5*100)) - 1;  
  16.   
  17.     //将速率写入PRERlo和PRERhi寄存器  
  18.     oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);  
  19.     oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);  
  20.   
  21.     /* Init the device */  
  22.     //清除中断标志位,使能总线控制器的中断和使能总线控制器  
  23.     oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);  
  24.     oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);  
  25. }  
//根据i2c-specs文档初始化总线控制器
//对比文档中的寄存器进行操作
static void ocores_init(struct ocores_i2c *i2c)
{
	int prescale;

	//取出Control register寄存器的值,在i2c-specs中有说明~
	u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);

	/* make sure the device is disabled */
	//i2c cores禁止中断和无效总线控制器
	oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));

	//设置i2c总线控制器的通信速率,在i2c-specs文档有计算公式
	prescale = (i2c->clock_khz / (5*100)) - 1;

	//将速率写入PRERlo和PRERhi寄存器
	oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
	oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);

	/* Init the device */
	//清除中断标志位,使能总线控制器的中断和使能总线控制器
	oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
	oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
}

        然后程序调用通信算法时会hold住,在中断中处理数据,然后等待事件集到来,完成通信。

  1. //发送和接收调用的总线通信算法函数  
  2. static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)  
  3. {  
  4.     //在ocores_i2c中有i2c_adapter成员,而i2c_adapter成员在probe进行时  
  5.     //已经由i2c_set_adapdata()保存到i2c_adapter中,所以这里取出保存在  
  6.     //i2c_adapter中dev成员的p成员的driver_data数据域  
  7.     struct ocores_i2c *i2c = i2c_get_adapdata(adap);  
  8.   
  9.     //获取由应用层传入的i2c message  
  10.     i2c->msg = msgs;  
  11.     i2c->pos = 0;  
  12.     i2c->nmsgs = num;  
  13.     i2c->state = STATE_START;  
  14.   
  15.     //根据i2c message类型是读还是写进行器件地址选择和设置LSB的读写位  
  16.     oc_setreg(i2c, OCI2C_DATA,  
  17.             (i2c->msg->addr << 1) |  
  18.             ((i2c->msg->flags & I2C_M_RD) ? 1:0));  
  19.   
  20.     //根据i2c协议第一次是写器件地址和读写位的组合  
  21.     oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);  
  22.   
  23.     //等待事件集到来,???操作系统没学过,现在恶补  
  24.     if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||  
  25.                    (i2c->state == STATE_DONE), HZ))  
  26.         return (i2c->state == STATE_DONE) ? num : -EIO;  
  27.     else  
  28.         return -ETIMEDOUT;  
  29. }  
//发送和接收调用的总线通信算法函数
static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
	//在ocores_i2c中有i2c_adapter成员,而i2c_adapter成员在probe进行时
	//已经由i2c_set_adapdata()保存到i2c_adapter中,所以这里取出保存在
	//i2c_adapter中dev成员的p成员的driver_data数据域
	struct ocores_i2c *i2c = i2c_get_adapdata(adap);

	//获取由应用层传入的i2c message
	i2c->msg = msgs;
	i2c->pos = 0;
	i2c->nmsgs = num;
	i2c->state = STATE_START;

	//根据i2c message类型是读还是写进行器件地址选择和设置LSB的读写位
	oc_setreg(i2c, OCI2C_DATA,
			(i2c->msg->addr << 1) |
			((i2c->msg->flags & I2C_M_RD) ? 1:0));

	//根据i2c协议第一次是写器件地址和读写位的组合
	oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);

	//等待事件集到来,???操作系统没学过,现在恶补
	if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
			       (i2c->state == STATE_DONE), HZ))
		return (i2c->state == STATE_DONE) ? num : -EIO;
	else
		return -ETIMEDOUT;
}

  1. //当总线控制器完成一个byte发送和接收时调用的中断函数  
  2. //因为这个驱动采用了中断的方式收发数据  
  3. static irqreturn_t ocores_isr(int irq, void *dev_id)  
  4. {  
  5.     struct ocores_i2c *i2c = dev_id;  
  6.   
  7.     ocores_process(i2c);  
  8.   
  9.     return IRQ_HANDLED;  
  10. }  
//当总线控制器完成一个byte发送和接收时调用的中断函数
//因为这个驱动采用了中断的方式收发数据
static irqreturn_t ocores_isr(int irq, void *dev_id)
{
	struct ocores_i2c *i2c = dev_id;

	ocores_process(i2c);

	return IRQ_HANDLED;
}

  1. //中断处理函数的处理过程,目前没认真整理过,根据i2c通信协议再好好看看  
  2. //然后有时间再总结出来  
  3. static void ocores_process(struct ocores_i2c *i2c)  
  4. {  
  5.     struct i2c_msg *msg = i2c->msg;  
  6.     u8 stat = oc_getreg(i2c, OCI2C_STATUS);  
  7.   
  8.     if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {  
  9.         /* stop has been sent */  
  10.         oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);  
  11.         wake_up(&i2c->wait);  
  12.         return;  
  13.     }  
  14.   
  15.     /* error? */  
  16.     if (stat & OCI2C_STAT_ARBLOST) {  
  17.         i2c->state = STATE_ERROR;  
  18.         oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);  
  19.         return;  
  20.     }  
  21.   
  22.     if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {  
  23.         i2c->state =  
  24.             (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;  
  25.   
  26.         if (stat & OCI2C_STAT_NACK) {  
  27.             i2c->state = STATE_ERROR;  
  28.             oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);  
  29.             return;  
  30.         }  
  31.     } else  
  32.         msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);  
  33.   
  34.     /* end of msg? */  
  35.     if (i2c->pos == msg->len) {  
  36.         i2c->nmsgs--;  
  37.         i2c->msg++;  
  38.         i2c->pos = 0;  
  39.         msg = i2c->msg;  
  40.   
  41.         if (i2c->nmsgs) {    /* end? */  
  42.             /* send start? */  
  43.             if (!(msg->flags & I2C_M_NOSTART)) {  
  44.                 u8 addr = (msg->addr << 1);  
  45.   
  46.                 if (msg->flags & I2C_M_RD)  
  47.                     addr |= 1;  
  48.   
  49.                 i2c->state = STATE_START;  
  50.   
  51.                 oc_setreg(i2c, OCI2C_DATA, addr);  
  52.                 oc_setreg(i2c, OCI2C_CMD,  OCI2C_CMD_START);  
  53.                 return;  
  54.             } else  
  55.                 i2c->state = (msg->flags & I2C_M_RD)  
  56.                     ? STATE_READ : STATE_WRITE;  
  57.         } else {  
  58.             i2c->state = STATE_DONE;  
  59.             oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);  
  60.             return;  
  61.         }  
  62.     }  
  63.   
  64.     if (i2c->state == STATE_READ) {  
  65.         oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ?  
  66.               OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);  
  67.     } else {  
  68.         oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);  
  69.         oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);  
  70.     }  
  71. }  
//中断处理函数的处理过程,目前没认真整理过,根据i2c通信协议再好好看看
//然后有时间再总结出来
static void ocores_process(struct ocores_i2c *i2c)
{
	struct i2c_msg *msg = i2c->msg;
	u8 stat = oc_getreg(i2c, OCI2C_STATUS);

	if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
		/* stop has been sent */
		oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
		wake_up(&i2c->wait);
		return;
	}

	/* error? */
	if (stat & OCI2C_STAT_ARBLOST) {
		i2c->state = STATE_ERROR;
		oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
		return;
	}

	if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
		i2c->state =
			(msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;

		if (stat & OCI2C_STAT_NACK) {
			i2c->state = STATE_ERROR;
			oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
			return;
		}
	} else
		msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);

	/* end of msg? */
	if (i2c->pos == msg->len) {
		i2c->nmsgs--;
		i2c->msg++;
		i2c->pos = 0;
		msg = i2c->msg;

		if (i2c->nmsgs) {	/* end? */
			/* send start? */
			if (!(msg->flags & I2C_M_NOSTART)) {
				u8 addr = (msg->addr << 1);

				if (msg->flags & I2C_M_RD)
					addr |= 1;

				i2c->state = STATE_START;

				oc_setreg(i2c, OCI2C_DATA, addr);
				oc_setreg(i2c, OCI2C_CMD,  OCI2C_CMD_START);
				return;
			} else
				i2c->state = (msg->flags & I2C_M_RD)
					? STATE_READ : STATE_WRITE;
		} else {
			i2c->state = STATE_DONE;
			oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
			return;
		}
	}

	if (i2c->state == STATE_READ) {
		oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ?
			  OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
	} else {
		oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
		oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
	}
}

        另外还有两个读写寄存器的函数,相信聪明你的绝对是看得明白的~不解释了~

  1. //这两个函数没什么好解释的了,大家都能看得懂的了  
  2. //至于regstep在DTS文件中定义(寄存器的步长),对应的i2c-specs中寄存器步长为1  
  3. static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)  
  4. {  
  5.     iowrite8(value, i2c->base + reg * i2c->regstep);  
  6. }  
  7.   
  8. static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)  
  9. {  
  10.     return ioread8(i2c->base + reg * i2c->regstep);  
  11. }  
//这两个函数没什么好解释的了,大家都能看得懂的了
//至于regstep在DTS文件中定义(寄存器的步长),对应的i2c-specs中寄存器步长为1
static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
{
	iowrite8(value, i2c->base + reg * i2c->regstep);
}

static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
{
	return ioread8(i2c->base + reg * i2c->regstep);
}

        先到这里了,至于文章中我觉得没说明白的地方在有时间的时候会补齐的~今天要把食梦者第3季给追完啦~谢谢各位捧场啦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值