现在的位置: 首页 > 综合 > 正文

S3C2410 I2C 总线驱动实例

2013年07月03日 ⁄ 综合 ⁄ 共 4216字 ⁄ 字号 评论关闭

1.S3C2410I2C
控制器硬件描述


S3C2410处理器内部集成了一个I2C控制器,通过4个寄存器就可方便地对其进行控制,4个寄存器如下。


1 IICCON:I2C
控制寄存器。


2 IICSTAT:I2C
状态寄存器。


3 IICDS:I2C
收发数据移位寄存器。


4 IICADD:I2C
地址寄存器。


S3C2410处理器内部集成的I2C控制器可支持主、从两种模式,我们主要使用其主模式。通过对IICCONIICDSIICADD寄存器的操作,可在I2C总线上产生开始位、停止位、数据和地址,而传输的状态则通过IICSTAT寄存器获取。


2.S3C2410I2C
总线驱动总体分析

S3C2410I2C总线驱动设计主要要完成以下工作。

1 设计对应于i2c_adapter_xxx_init()模板的S3C2410的模块加载函数和对应于i2c_adapter_xxx_exit()函数模板的模块卸载函数。

2设计对应于i2c_adapter_xxx_xfer()模板的S3C2410适配器的通信方法函数。针对
S3C2410, functionality()
函数 只需 简单 地返 回I2C_FUNC_I2C|I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING
表明其支持的功能。内核 源代 码中 的/drivers/i2c/busses/i2c-s3c2410.c


1
给出了S3C2410驱动中的主要函数与模板函数的对应关系,由于实现通信方法的方式不一样,模板的一个函数可能对应与S3C2410I2C
总线驱动的多个函数。


1    I2C
总线驱动模板与S3C2410I2C
总线驱动的映射


3.S3C2410I2C
适配器驱动的模块加载与卸载


I2C适配器驱动被作为一个单独的模块加载进内核,在模块的加载和卸载函数中,只需注册和注销一个platform_driver结构体,如代码清单1.1所示

代码清单1.1 S3C2410 I2C
总线驱动的模块加载与卸载

static  int _ _init i2c_adap_s3c_init(void)

{

     int ret;

     ret= platform_driver_register(&s3c2410_i2c_driver);

     if(ret == 0)

        {

             ret= platform_driver_register(&s3c2440_i2c_driver);

             if(ret)

             platform_driver_unregister(&s3c2410_i2c_driver);

        }

     return  ret;

}


static  void _ _exit i2c_adap_s3c_exit(void)

{

      platform_driver_unregister(&s3c2410_i2c_driver);


      platform_driver_unregister(&s3c2440_i2c_driver);


}


module_init(i2c_adap_s3c_init);


module_exit(i2c_adap_s3c_exit);



platform_driver结构体包含了具体适配器的probe()函数、remove()函数、resume()


函数指针等信息,它需要被定义和赋值,如代码清单1.2所示。


代码清单1.2platform_driver
结构体



staticstruct platform_driver s3c2410_i2c_driver = {


.probe=s3c24xx_i2c_probe,


.remove=s3c24xx_i2c_remove,


.resume=s3c24xx_i2c_resume,


.driver={

.owner=THIS_MODULE,


.name="s3c2410-i2c",

},


};



当通 过Linux内核
源代 码
/drivers/base/platform.c文件 中定义platform_driver_unregister()函数注册platform_driver结构体时,

其中probe指针指向的

s3c24xx_i2c_probe()函数将被调用,以初始化适配器硬件,如代码清单1.3所示。


代码清单1.3 S3C2410 I2C
总线驱动中的s3c24xx_i2c_probe
函数




staticint s3c24xx_i2c_probe(struct platform_device *pdev)


{


structs3c24xx_i2c *i2c = &s3c24xx_i2c;



structresource *res;



intret;



/*使能I2C的时钟*/


i2c->dev= &pdev->dev;


i2c->clk= clk_get(&pdev->dev, "i2c");


if(IS_ERR(i2c->clk))

{


dev_err(&pdev->dev,"cannot get clock\n");



ret= -ENOENT;



gotoout;


}


clk_enable(i2c->clk);



/*映射寄存器*/


res= platform_get_resource(pdev, IORESOURCE_MEM, 0);


if(res == NULL)

{



dev_err(&pdev->dev,"cannot find IO resource\n");



ret= -ENOENT;



gotoout;


}


i2c->ioarea

=

request_mem_region(res->start,

(res->end-res->start)+1,


pdev->name);


if(i2c->ioarea == NULL)

{


dev_err(&pdev->dev,"cannot request IO\n");



ret= -ENXIO;


gotoout;


}




i2c->regs= ioremap(res->start, (res->end-res->start)+1);


if(i2c->regs == NULL)

{



dev_err(&pdev->dev,"cannot map IO\n");


ret= -ENXIO;



gotoout;


}

/*设置I2C的信息块*/


i2c->adap.algo_data= i2c;


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



/*初始化I2C控制器*/


ret= s3c24xx_i2c_init(i2c);


if(ret != 0)


goto out;



/*申请中断*/


res= platform_get_resource(pdev, IORESOURCE_IRQ, 0);


if(res == NULL)

{


ret= -ENOENT;


gotoout;


}


ret= request_irq(res->start, s3c24xx_i2c_irq, SA_INTERRUPT,

pdev->name,i2c);


if(ret != 0)

{



gotoout;


}


i2c->irq= res;



ret= i2c_add_adapter(&i2c->adap); /*添加i2c_adapter*/


if(ret < 0)

{



gotoout;


}



platform_set_drvdata(pdev,i2c);


out:


if(ret < 0)


s3c24xx_i2c_free(i2c);


returnret;

}


上述代码中的主体工作是使能硬件并申请I2C适配器使用的I/O地址、

在这些工作都完成无误后,通过IC
核心提供的i2c_add_adapter()函数添加这个适配

器。 因为
S3C2410内部 集成
I2C控制 器,可以
确定
I2C适配 器一 定存 在,

s3c24xx_i2c_probe()函数虽然命名“探测”

,但实际没有也不必进行任何探测工作,

所以这样命名完全是一种设计习惯。


s3c24xx_i2c_probe()函数完成相反功能的函数是s3c24xx_i2c_remove()函数,


在适 配器 模块 卸载 函数 调用platform_driver_unregister()函数
时所 示通 过

platform_driverremove指针方式被调用。xxx_i2c_remove()的设计模板如代码清单

1.4所示。



代码清单1.4S3C2410 I2C
总线驱动中的s3c24xx_i2c_remove函数


staticint s3c24xx_i2c_remove(struct platform_device *pdev)


{


structs3c24xx_i2c *i2c = platform_get_drvdata(pdev);


if(i2c != NULL)

{


s3c24xx_i2c_free(i2c);


platform_set_drvdata(pdev,NULL);


}


return 0;


}


代码清单1.3和代码清单1.4中用到的s3c24xx_i2c结构体进行适配器所有信

息的封装,类似于私有信息结构体,它与xxx_i2c结构体模板

对应。代码清单1.5所示s3c24xx_i2c结构体的定义,以及驱动模块定义的一个

s3c24xx_i2c结构体全局实例。


xxx_i2c结构体模板


structxxx_i2c


{


spinlock_t

lock;


wait_queue_head_twait;


structi2c_msg *msg;


unsignedint

msg_num;


unsignedint

msg_idx;


unsignedint

msg_ptr;


...


structi2c_adapter adap;


};



代码清单1.5s3c24xx_i2c
结构体


structs3c24xxx_i2c


{


spinlock_t

lock;


wait_queue_head_twait;


structi2c_msg *msg;


unsignedint

msg_num;


unsignedint

msg_idx;


unsignedint

msg_ptr;


enums3c24xx_i2c_state state;


void_ _iomem *regs;

structclk *clk;

structdevice *dev;

structresource *irq;


structresource *ioarea;


structi2c_adapter adap;


};


staticstruct s3c24xx_i2c s3c24xx_i2c = {


.lock= SPIN_LOCK_UNLOCKED, /*自旋锁未锁定

抱歉!评论已关闭.