linux i2c设备文件,Linux_I2C设备驱动文件操作接口

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

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

1 static int __init i2c_adap_s3c_init(void)

2 {

3 int ret;

4

5 ret = platform_driver_register(&s3c2410_i2c_driver);

6 if (ret == 0) {

7 ret = platform_driver_register(&s3c2440_i2c_driver);

8 if (ret)

9 platform_driver_unregister(&s3c2410_i2c_driver);

10 }

11

12 return ret;

13 }

14

15 static void __exit i2c_adap_s3c_exit(void)

16 {

17 platform_driver_unregister(&s3c2410_i2c_driver);

18 platform_driver_unregister(&s3c2440_i2c_driver);

19 }

20 module_init(i2c_adap_s3c_init);

21 module_exit(i2c_adap_s3c_exit);

platform_driver结构体包含了具体适配器的probe()函数、remove()函数、resume()函数指针等信息,它需要被定义和赋值,如代码清单15.26。

代码清单15.26 platform_driver结构体

1 static struct platform_driver s3c2410_i2c_driver = {

2 .probe = s3c24xx_i2c_probe,

3 .remove = s3c24xx_i2c_remove,

4 .resume = s3c24xx_i2c_resume,

5 .driver = {

6 .owner = THIS_MODULE,

7 .name = "s3c2410-i2c",

8 },

9 };

当 通过Linux内核源代码/drivers/base/platform.c文件中定义platform_driver_unregister()函数注 册platform_driver结构体时,其中probe指针指向的s3c24xx_i2c_probe()函数将被调用以初始化适配器硬件,如代码清 单15.27。

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

1 static int s3c24xx_i2c_probe(struct platform_device *pdev)

2 {

3 struct s3c24xx_i2c *i2c = &s3c24xx_i2c;

4 struct resource *res;

5 int ret;

6

7 /* 使能I2C的时钟 */

8 i2c->dev = &pdev->dev;

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

10 if (IS_ERR(i2c->clk)) {

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

12 ret = -ENOENT;

13 goto out;

14 }

15 clk_enable(i2c->clk);

16

17 /* 映射寄存器 */

18 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

19 if (res == NULL) {

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

21 ret = -ENOENT;

22 goto out;

23 }

24 i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,

25 pdev->name);

26 if (i2c->ioarea == NULL) {

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

28 ret = -ENXIO;

29 goto out;

30 }

31

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

33 if (i2c->regs == NULL) {

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

35 ret = -ENXIO;

36 goto out;

37 }

38

39 /* 设置I2C的信息块 */

40 i2c->adap.algo_data = i2c;

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

42

43 /* 初始化I2C控制器 */

44 ret = s3c24xx_i2c_init(i2c);

45 if (ret != 0)

46 goto out;

47

48 /* 申请中断 */

49 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

50 if (res == NULL) {

51 ret = -ENOENT;

52 goto out;

53 }

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

55 pdev->name, i2c);

56 if (ret != 0) {

57 goto out;

58 }

59 i2c->irq = res;

60

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

62 if (ret < 0) {

63 goto out;

64 }

65

66 platform_set_drvdata(pdev, i2c);

67

68 out:

69 if (ret < 0)

70 s3c24xx_i2c_free(i2c);

71 return ret;

72 }

上 述代码中的主体工作是使能硬件并申请I2C适配器使用的I/O地址、中断号等,在这些工作都完成无误后,通过I2C核心提供的 i2c_add_adapter()函数添加这个适配器。因为S3C2410内部集成I2C控制器,可以确定I2C适配器一定存在, s3c24xx_i2c_probe()函数虽然命名“探测”,但实际没有也不必进行任何探测工作,之所以这样命名完全是一种设计习惯。

与s3c24xx_i2c_probe ()函数完成相反功能的函数是s3c24xx_i2c_remove()函数,它在适配器模块卸载函数调用 platform_driver_unregister()函数时被通过platform_driver的remove指针方式调用。 xxx_i2c_remove()的设计模板见代码清单15.28。

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

1 static int s3c24xx_i2c_remove(struct platform_device *pdev)

2 {

3 struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);

4

5 if (i2c != NULL) {

6 s3c24xx_i2c_free(i2c);

7 platform_set_drvdata(pdev, NULL);

8 }

9

10 return 0;

11 }

代 码清单15.27和15.28中用到的s3c24xx_i2c结构体进行适配器所有信息的封装,类似于私有信息结构体,它与代码清单15.12给出的 xxx_i2c结构体模板对应。代码清单15.29给出了s3c24xx_i2c结构体的定义,以及驱动模块定义的一个s3c24xx_i2c结构体全局 实例。

代码清单15.29 s3c24xx_i2c结构体

1 struct s3c24xx_i2c {

2 spinlock_t lock;

3 wait_queue_head_t wait;

4 struct i2c_msg *msg;

5 unsigned int msg_num;

6 unsigned int msg_idx;

7 unsigned int msg_ptr;

8 enum s3c24xx_i2c_state state;

9 void __iomem *regs;

10 struct clk *clk;

11 struct device *dev;

12 struct resource *irq;

13 struct resource *ioarea;

14 struct i2c_adapter adap;

15 };

16

17 static struct s3c24xx_i2c s3c24xx_i2c = {

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

19 .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),/*等待队列初始化*/

20 .adap = {

21 .name = "s3c2410-i2c",

22 .owner = THIS_MODULE,

23 .algo = &s3c24xx_i2c_algorithm,

24 .retries = 2,

25 .class = I2C_CLASS_HWMON,

26 },

27 };

15.5.4 S3C2410 I2C总线通信方法

由代码清单15.29第23行可以看出,I2C适配器对应的i2c_algorithm结构体实例为s3c24xx_i2c_algorithm,代码清单15.30给出了s3c24xx_i2c_algorithm的定义。

代码清单15.30 S3C2410的i2c_algorithm结构体

1 static struct i2c_algorithm s3c24xx_i2c_algorithm = {

2 .master_xfer = s3c24xx_i2c_xfer,

3 .functionality = s3c24xx_i2c_func,

4 };

上 述代码第1行指定了S3C2410 I2C总线通信传输函数s3c24xx_i2c_xfer(),这个函数是如此的关键,所有I2C总线上对设备的访问最终应该由它来完成,代码清单 15.31给出了这个重要函数以及其依赖的s3c24xx_i2c_doxfer()函数和s3c24xx_i2c_message_start()函数 的源代码。

代码清单15.31 S3C2410 I2C总线驱动的master_xfer函数

1 static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,

2 struct i2c_msg *msgs, int num)

3 {

4 struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;

5 int retry;

6 int ret;

7

8 for (retry = 0; retry < adap->retries; retry++) {

9 ret = s3c24xx_i2c_doxfer(i2c, msgs, num);

10 if (ret != -EAGAIN)

11 return ret;

12 udelay(100);

13 }

14

15 return -EREMOTEIO;

16 }

17

18 static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num)

19 {

20 unsigned long timeout;

21 int ret;

22

23 ret = s3c24xx_i2c_set_master(i2c);

24 if (ret != 0) {

25 ret = -EAGAIN;

26 goto out;

27 }

28

29 spin_lock_irq(&i2c->lock);

30 i2c->msg = msgs;

31 i2c->msg_num = num;

32 i2c->msg_ptr = 0;

33 i2c->msg_idx = 0;

34 i2c->state = STATE_START;

35 s3c24xx_i2c_enable_irq(i2c);

36 s3c24xx_i2c_message_start(i2c, msgs);

37 spin_unlock_irq(&i2c->lock);

38

39 timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);

40

41 ret = i2c->msg_idx;

42

43 if (timeout == 0)

44 dev_dbg(i2c->dev, "timeout\n");

45 else if (ret != num)

46 dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);

47

48 msleep(1);/* 确保停止位已经被传递 */

49

50 out:

51 return ret;

52 }

53

54 static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,

55 struct i2c_msg *msg)

56 {

57 unsigned int addr = (msg->addr & 0x7f) << 1;

58 unsigned long stat;

59 unsigned long iiccon;

60

61 stat = 0;

62 stat |= S3C2410_IICSTAT_TXRXEN;

63

64 if (msg->flags & I2C_M_RD) {

65 stat |= S3C2410_IICSTAT_MASTER_RX;

66 addr |= 1;

67 } else

68 stat |= S3C2410_IICSTAT_MASTER_TX;

69 if (msg->flags & I2C_M_REV_DIR_ADDR)

70 addr ^= 1;

71

72 s3c24xx_i2c_enable_ack(i2c);/*如果要使能ACK,则使能*/

73

74 iiccon = readl(i2c->regs + S3C2410_IICCON);

75 writel(stat, i2c->regs + S3C2410_IICSTAT);

76 writeb(addr, i2c->regs + S3C2410_IICDS);

77

78 udelay(1);/*在发送新的开始位前延迟1位*/

79 writel(iiccon, i2c->regs + S3C2410_IICCON);

80 stat |= S3C2410_IICSTAT_START;

81 writel(stat, i2c->regs + S3C2410_IICSTAT);

82 }

s3c24xx_i2c_xfer()函数调用s3c24xx_i2c_doxfer()函数传输I2C消息,第8行的循环意味着最多可以重试adap->retries次。

s3c24xx_i2c_doxfer()首先将S3C2410的I2C适配器设置为I2C主设备,其后初始化s3c24xx_i2c结构体,使能I2C中断,并调用s3c24xx_i2c_message_start()函数启动I2C消息的传输。

s3c24xx_i2c_message_start()函数写S3C2410适配器对应的控制寄存器向I2C从设备传递开始位和从设备地址。

上 述代码只是启动了I2C消息数组的传输周期,并没有完整实现图15.3中给出的algorithm master_xfer流程。这个流程的完整实现需要借助I2C适配器上的中断来步步推进。代码清单15.32给出了S3C2410 I2C适配器中断处理函数以及其依赖的i2s_s3c_irq_nextbyte()函数的源代码。

代码清单15.32 S3C2410 I2C适配器中断处理函数

1 static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id,

2 struct pt_regs *regs)

3 {

4 struct s3c24xx_i2c *i2c = dev_id;

5 unsigned long status;

6 unsigned long tmp;

7

8 status = readl(i2c->regs + S3C2410_IICSTAT);

9 if (status & S3C2410_IICSTAT_ARBITR) {

10 ...

11 }

12

13 if (i2c->state == STATE_IDLE) {

14 tmp = readl(i2c->regs + S3C2410_IICCON);

15 tmp &= ~S3C2410_IICCON_IRQPEND;

16 writel(tmp, i2c->regs + S3C2410_IICCON);

17 goto out;

18 }

19

20 i2s_s3c_irq_nextbyte(i2c, status);/* 把传输工作进一步推进 */

21

22 out:

23 return IRQ_HANDLED;

24 }

25

26 static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)

27 {

28 unsigned long tmp;

29 unsigned char byte;

30 int ret = 0;

31

32 switch (i2c->state) {

33 case STATE_IDLE:

34 goto out;

35 break;

36 case STATE_STOP:

37 s3c24xx_i2c_disable_irq(i2c);

38 goto out_ack;

39 case STATE_START:

40 /* 我们最近做的一件事是启动一个新I2C消息*/

41 if (iicstat & S3C2410_IICSTAT_LASTBIT &&

42 !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {

43 /* 没有收到ACK */

44 s3c24xx_i2c_stop(i2c, -EREMOTEIO);

45 goto out_ack;

46 }

47

48 if (i2c->msg->flags & I2C_M_RD)

49 i2c->state = STATE_READ;

50 else

51 i2c->state = STATE_WRITE;

52

53 /* 仅一条消息,而且长度为0(主要用于适配器探测),发送停止位*/

54 if (is_lastmsg(i2c) && i2c->msg->len == 0) {

55 s3c24xx_i2c_stop(i2c, 0);

56 goto out_ack;

57 }

58

59 if (i2c->state == STATE_READ)

60 goto prepare_read;

61 /* 进入写状态 */

62 case STATE_WRITE:

63 retry_write:

64 if (!is_msgend(i2c)) {

65 byte = i2c->msg->buf[i2c->msg_ptr++];

66 writeb(byte, i2c->regs + S3C2410_IICDS);

67

68 } else if (!is_lastmsg(i2c)) {

69 /* 推进到下一条消息 */

70 i2c->msg_ptr = 0;

71 i2c->msg_idx ++;

72 i2c->msg++;

73

74 /* 检查是否要为该消息产生开始位 */

75 if (i2c->msg->flags & I2C_M_NOSTART) {

76 if (i2c->msg->flags & I2C_M_RD) {

77 s3c24xx_i2c_stop(i2c, -EINVAL);

78 }

79 goto retry_write;

80 } else {

81 /* 发送新的开始位 */

82 s3c24xx_i2c_message_start(i2c, i2c->msg);

83 i2c->state = STATE_START;

84 }

85 } else {

86 s3c24xx_i2c_stop(i2c, 0);/* send stop */

87 }

88 break;

89 case STATE_READ:

90 /* 有一个字节可读,看是否还有消息要处理 */

91 if (!(i2c->msg->flags & I2C_M_IGNORE_NAK) &&

92 !(is_msglast(i2c) && is_lastmsg(i2c))) {

93

94 if (iicstat & S3C2410_IICSTAT_LASTBIT) {

95 dev_dbg(i2c->dev, "READ: No Ack\n");

96

97 s3c24xx_i2c_stop(i2c, -ECONNREFUSED);

98 goto out_ack;

99 }

100 }

101 byte = readb(i2c->regs + S3C2410_IICDS);

102 i2c->msg->buf[i2c->msg_ptr++] = byte;

103

104 prepare_read:

105 if (is_msglast(i2c)) {/* last byte of buffer */

106 if (is_lastmsg(i2c))

107 s3c24xx_i2c_disable_ack(i2c);

108

109 } else if (is_msgend(i2c)) {

110 /* 还有消息要处理吗? */

111 if (is_lastmsg(i2c)) {

112 s3c24xx_i2c_stop(i2c, 0);/* last message, send stop and complete */

113 } else {

114 /* 推进到下一条消息 */

115 i2c->msg_ptr = 0;

116 i2c->msg_idx++;

117 i2c->msg++;

118 }

119 }

120 break;

121 }

122

123 /* irq清除 */

124 out_ack:

125 tmp = readl(i2c->regs + S3C2410_IICCON);

126 tmp &= ~S3C2410_IICCON_IRQPEND;

127 writel(tmp, i2c->regs + S3C2410_IICCON);

128 out:

129 return ret;

130 }

中 断处理函数s3c24xx_i2c_irq()主要通过调用i2s_s3c_irq_nextbyte()函数进行传输工作的进一步推进。 i2s_s3c_irq_nextbyte()函数通过switch(i2c->state)语句分成i2c->state的不同状态进行处 理,在每种状态下,先检查i2c->state的状态与硬件寄存器应该处于的状态是否一致,如果不一致,则证明有误,直接返回。当I2C处于读状态 STATE_READ或写状态STATE_WRITE时,通过is_lastmsg()函数判断是否传输的是最后一条I2C消息,如果是,则产生停止位, 否则通过i2c->msg_idx++、i2c->msg++推进到下一条消息。

15.6 实例:SAA7113H视频AD芯片I2C设备驱动

15.6.1 SAA7113H视频AD芯片硬件描述

如图15.9,SAA7113H是飞利浦半导体推出的9位视频AD芯片,它可以选择4路视频输入中的1路,并采样为9位的数字信号。

图15.9 SAA7113H输入、输出与I2C接口

对SAA7113H 输入通道的选择以及采样方式的设置都需通过其I2C接口进行,以0x4A地址可读SAA7113H寄存器,以0x4B可写SAA7113H寄存器。 SAA7113H的I2C接口连接在S3C2410的I2C控制器上,作为S3C2410 I2C控制器的从设备。SAA7113H的写时序与图15.7给出的写时序是一致的,但是读时序则需通过2条I2C消息解决,在第1条消息中应该给 SAA7113H写入寄存器子地址,如图15.10。

图15.10 SAA7113H读时序

15.6.2 SAA7113H视频AD芯片驱动模块加载与卸载

由于不需要给SAA7113H实现文件操作接口,在设备驱动模块的加载和卸载函数中均不再需要注册和注销字符设备的操作,代码清单15.33给出了SAA7113H设备驱动模块加载和卸载的源代码。

代码清单15.33 SAA7113H设备驱动模块加载和卸载函数

1 static int __init saa711x_init (void)

2 {

3 return i2c_add_driver(&i2c_driver_saa711x); //注册i2c_driver

4 }

5

6 static void __exit saa711x_exit (void)

7 {

8 i2c_del_driver(&i2c_driver_saa711x); //注销i2c_driver

9 }

10

11 module_init(saa711x_init);

12 module_exit(saa711x_exit);

15.6.3 SAA7113H设备驱动i2c_driver成员函数

如 代码清单15.34,SAA7113H设备驱动模块加载和卸载中添加和删除的i2c_driver_saa711x结构体的attach_adapter 指针被赋值为saa711x_attach_adapter,detach_client指针被赋值为saa711x_detach_client,而 command指针被赋值为saa711x_command,代码清单15.35给出了这3个函数的实现。

代码清单15.34 SAA7113H设备驱动i2c_driver结构体

1 static struct i2c_driver i2c_driver_saa711x = {

2 .driver = {

3 .name = "saa711x",

4 },

5 .id = I2C_DRIVERID_SAA711X,

6 /* 成员函数 */

7 .attach_adapter = saa711x_attach_adapter,

8 .detach_client = saa711x_detach_client,

9 .command = saa711x_command,

10 };

代码清单15.35 SAA7113H设备驱动i2c_driver成员函数

1 saa711x_attach_adapter (struct i2c_adapter *adapter)

2 {

3 dprintk(1, KERN_INFO "saa711x.c: starting probe for adapter %s (0x%x)\n",

4 I2C_NAME(adapter), adapter->id);

5

6 return i2c_probe(adapter, &addr_data, &saa711x_detect_client);

7 //saa711x_detect_client会调用i2c_set_clientdata()、i2c_attach_client()

8 }

9

10 static int saa711x_detach_client (struct i2c_client *client)

11 {

12 struct saa711x *decoder = i2c_get_clientdata(client);

13 int err;

14

15 err = i2c_detach_client(client);

16 if (err) {

17 return err;

18 }

19

20 kfree(decoder);

21 kfree(client);

22

23 return 0;

24 }

25

26 static int saa711x_command(struct i2c_client *client, unsigned int cmd, void

27 *arg)

28 {

29 struct saa711x *decoder = i2c_get_clientdata(client);

30

31 switch (cmd) //处理不同的命令

32 {

33 case 0:

34 case DECODER_INIT:

35 ...

36 case DECODER_DUMP:

37 ...

38 case DECODER_GET_CAPABILITIES:

39 ...

40 case DECODER_GET_STATUS:

41 ...

42 case DECODER_SET_VBI_BYPASS:

43 ...

44 case DECODER_SET_NORM:

45 ...

46 case DECODER_SET_INPUT:

47 {

48 int *iarg = arg;

49 if (*iarg < 0 || *iarg > 9)

50 {

51 return - EINVAL;

52 }

53 if (decoder->input != *iarg)

54 {

55 decoder->input = *iarg;

56 saa711x_write(client, 0x02, (decoder->reg[0x02] &0xf0) | decoder

57 ->input);

58 saa711x_write(client, 0x09, (decoder->reg[0x09] &0x7f) | ((decoder

59 ->input > 3) ? 0x80 : 0));

60 }

61 }

62 break;

63

64 case DECODER_SET_OUTPUT:

65 ...

66 case DECODER_ENABLE_OUTPUT:

67 ...

68 case DECODER_SET_PICTURE:

69 ...

70 default:

71 return - EINVAL;

72 }

73

74 return 0;

75 }

15.8本章小结

Linux I2C驱动体系结构有相当的复杂度,它主要由3部分组成,即I2C核心、I2C总线驱动和I2C设备驱动。I2C核心是I2C总线驱动和I2C设备驱动的 中间枢纽,它以通用的、与平台无关的接口实现了I2C中设备与适配器的沟通。I2C总线驱动填充i2c_adapter和i2c_algorithm结构 体,I2C设备驱动填充i2c_driver和i2c_client结构体。

另外,系统中i2c-dev.c文件定义的主设备号为89的设备可以方便地给应用程序提供读写I2C设备寄存器的能力,使得工程师大多数时候并不需要为具体的I2C设备驱动定义文件操作接口。

最后,工程师在设计I2C设备驱动的程序,并不是一定要遵守Linux I2C驱动的体系结构,完全可以把它当作一个普通的字符设备处理,如果不考虑融入Linux现有的I2C框架的话。

图15.4 I2C设备驱动模块加载连锁反应

图15.4 I2C设备驱动模块加载连锁反应

图15.5 I2C设备驱动模块卸载连锁反应

图15.5 I2C设备驱动模块卸载连锁反应

图15.6 I2C设备读写完整流程

图15.6 I2C设备读写完整流程

图15.7 i2cdev_read和i2cdev_write函数对应时序

图15.7 i2cdev_read和i2cdev_write函数对应时序

图15.8 RepStart模式

图15.8 RepStart模式

SAA7113H输入、输出与I2C接口

SAA7113H输入、输出与I2C接口

展开阅读全文

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值