logo资料库

linux gpio 模拟I2C驱动.doc

第1页 / 共33页
第2页 / 共33页
第3页 / 共33页
第4页 / 共33页
第5页 / 共33页
第6页 / 共33页
第7页 / 共33页
第8页 / 共33页
资料共33页,剩余部分请下载后查看
在 drivers/i2c/busses 下包含各种 I2C 总线驱动,如 S3C2440 的 I2C 总线驱动 i2c-s3c2410.c,使用 GPIO 模拟 I2C 总线的驱动 i2c-gpio.c,这里只分析 i2c-gpio.c。 i2c-gpio.c 它是 gpio 模拟 I2C 总线的驱动,总线也是个设备,在这里将总线当作平台设备处理, 那驱动当然是平台设备驱动,看它的驱动注册和注销函数。 [html] view plaincopyprint? ret = platform_driver_register(&i2c_gpio_driver); if (ret) printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); int ret; 1. static int __init i2c_gpio_init(void) 2. { 3. 4. 5. 6. 7. 8. 9. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 10. } 11. 11. module_init(i2c_gpio_init); 12. 12. 13. 13. static void __exit i2c_gpio_exit(void) 14. 14. { 15. 15. 16. 16. } 17. 17. module_exit(i2c_gpio_exit); return ret; platform_driver_unregister(&i2c_gpio_driver); 没有什么好说的,它的初始化和注销函数就是注册和注销一个平台设备驱动,直接看它的 platform_driver 结构 i2c_gpio_driver [html] view plaincopyprint? .driver .name .owner = { = "i2c-gpio", = THIS_MODULE, 1. 1. static struct platform_driver i2c_gpio_driver = { 2. 2. 3. 3. 4. 4. 5. 5. 6. 6. 7. 7. 8. 8. }; = i2c_gpio_probe, = __devexit_p(i2c_gpio_remove), }, .probe .remove 平台驱动设备放在 arch/arm/mach-xxxx/board-xxx.c 中 [html] view plaincopyprint?
defined(CONFIG_I2C_GPIO_MODULE) .sda_pin = PINID_GPMI_D05, .scl_pin = PINID_GPMI_D04, .udelay = 5, //100KHz .timeout = 100, .sda_is_open_drain = 1, .scl_is_open_drain = 1, 1. #if defined(CONFIG_I2C_GPIO) | \ 2. 3. static struct i2c_gpio_platform_data i2c_gpio_adapter_data = { 4. 5. 6. 7. 8. 9. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 10. }; 11. 11. 12. 12. static struct platform_device i2c_gpio = { 13. 13. 14. 14. 15. 15. 16. 16. 17. 17. 18. 18. 19. 19. }; 20. 20. #endif .platform_data = &i2c_gpio_adapter_data, .release = mxs_nop_release, }, .name = "i2c-gpio", .id = 0, .dev = { 在这里 struct platform_device 结构中的 name 字段要和 struct platform_driver 中 driver 字段中 name 字段要相同,因为平台总线就是通过这个来判断设备和驱动是否匹配的。注意这里的 id 将它赋值了 0,至于到底有什么用,后面再来细看。这个结构里面还包含一个最重要的数 据 i2c_gpio_adapter_data,它 struct i2c_gpio_platform_data 结构类型变量,这个结构体类型定 义在 include/linux/i2c-gpio.h 中。 [html] view plaincopyprint? sda_pin; scl_pin; 1. 1. struct i2c_gpio_platform_data { 2. 2. 3. 3. 4. 4. 5. 5. 6. 6. 7. 7. 8. 8. 9. 9. }; unsigned int unsigned int int int unsigned int unsigned int unsigned int udelay; timeout; sda_is_open_drain:1; scl_is_open_drain:1; scl_is_output_only:1; 这个结构体主要描述 gpio 模拟 i2c 总线,sda_pin 和 scl_pin 表示使用哪两个 IO 管脚来模拟 I2C 总线,udelay 和 timeout 分别为它的时钟频率和超时时间,sda_is_open_drain 和 scl_is_open_drain 表示 sda、scl 这两个管脚是否是开漏(opendrain)电路,如果是设置为 1, scl_is_output_only 表示 scl 这个管脚是否只是作为输出,如果是设置为 1。
回到驱动中,看其中最重要的 i2c_gpio_probe。 [html] view plaincopyprint? struct i2c_gpio_platform_data *pdata; struct i2c_algo_bit_data *bit_data; struct i2c_adapter *adap; int ret; 1. static int __devinit i2c_gpio_probe(struct platform_device *pdev) 1. 2. { 2. 3. 3. 4. 4. 5. 5. 6. 6. 7. 7. 8. 8. 9. 9. 10. 10. 11. 11. 12. 12. 13. 13. 14. 14. 15. 15. 16. 16. ret = -ENOMEM; adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); if (!adap) pdata = pdev->dev.platform_data; if (!pdata) return -ENXIO; goto err_alloc_adap; bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL); 17. 17. 18. 18. 19. 19. 20. 20. 21. 21. 22. 22. 23. 23. 24. 24. 25. 25. 26. 26. 27. 27. 28. 28. 29. 29. 30. 30. 31. 31. 32. 32. 33. 33. 34. 34. 35. 35. 36. 36. 37. 37. 38. 38. 39. 39. 40. 40. if (!bit_data) goto err_alloc_bit_data; ret = gpio_request(pdata->sda_pin, "sda"); if (ret) goto err_request_sda; ret = gpio_request(pdata->scl_pin, "scl"); if (ret) goto err_request_scl; if (pdata->sda_is_open_drain) { gpio_direction_output(pdata->sda_pin, 1); bit_data->setsda = i2c_gpio_setsda_val; } else { gpio_direction_input(pdata->sda_pin); bit_data->setsda = i2c_gpio_setsda_dir; } if (pdata->scl_is_open_drain || pdata->scl_is_output_only) { gpio_direction_output(pdata->scl_pin, 1); bit_data->setscl = i2c_gpio_setscl_val; } else { gpio_direction_input(pdata->scl_pin); bit_data->setscl = i2c_gpio_setscl_dir;
41. 41. 42. 42. 43. 43. 44. 44. 45. 45. 46. 46. 47. 47. 48. 48. 49. 49. 50. 50. 51. 51. 52. 52. 53. 53. 54. 54. 55. 55. 56. 56. 57. 57. 58. 58. 59. 59. 60. 60. 61. 61. 62. 62. 63. 63. 64. 64. 65. 65. 66. 66. 67. 67. 68. 68. 69. 69. 70. 70. 71. 71. 72. 72. 73. 73. 74. 74. 75. 75. 76. 76. 77. 77. 78. 78. 79. 79. 80. 80. 81. 81. 82. 82. 83. 83. } if (!pdata->scl_is_output_only) bit_data->getscl = i2c_gpio_getscl; bit_data->getsda = i2c_gpio_getsda; if (pdata->udelay) bit_data->udelay = pdata->udelay; else if (pdata->scl_is_output_only) bit_data->udelay = 50; /* 10 kHz */ else bit_data->udelay = 5; /* 100 kHz */ if (pdata->timeout) bit_data->timeout = pdata->timeout; else bit_data->timeout = HZ / 10; /* 100 ms */ bit_data->data = pdata; adap->owner = THIS_MODULE; snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); adap->algo_data = bit_data; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->dev.parent = &pdev->dev; /* * If "dev->id" is negative we consider it as zero. * The reason to do so is to avoid sysfs names that only make * sense when there are multiple adapters. */ adap->nr = (pdev->id != -1) ? pdev->id : 0; ret = i2c_bit_add_numbered_bus(adap); if (ret) goto err_add_bus; platform_set_drvdata(pdev, adap); dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", pdata->sda_pin, pdata->scl_pin, pdata->scl_is_output_only ? ", no clock stretching" : "");
gpio_free(pdata->scl_pin); gpio_free(pdata->sda_pin); return 0; 84. 84. 85. 85. 86. 86. err_add_bus: 87. 87. 88. 88. err_request_scl: 89. 89. 90. 90. err_request_sda: 91. 91. kfree(bit_data); 92. 92. err_alloc_bit_data: 93. 93. kfree(adap); 94. 94. err_alloc_adap: 95. 95. return ret; 96. 96. } 从这句开始 pdata= pdev->dev.platform_data;这不正是我们在平台设备结构中定义的数据吗。 然后是使用 kzalloc 申请两段内存空间,一个是为结构 struct i2c_adapter 申请的,另一个是为 结构 structi2c_algo_bit_data 申请的。 struct i2c_adapter 结构定义在 include/linux/i2c.h 中 [html] view plaincopyprint? struct module *owner; unsigned int id; unsigned int class; const struct i2c_algorithm *algo; /* the algorithm to access the bus /* classes to allow probing for */ 1. 2. 3. 4. 5. void *algo_data; 1. struct i2c_adapter { 2. 3. 4. 5. */ 6. 6. 7. 7. 8. 8. 9. 9. 10. 10. 11. 11. 12. 12. 13. 13. 14. 14. 15. 15. 16. 16. 17. 17. 18. 18. 19. 19. }; int timeout; int retries; struct device dev; int nr; char name[48]; struct completion dev_released; /* data fields that are valid for all devices u8 level; struct mutex bus_lock; */ /* nesting level for lockdep */ /* in jiffies */ /* the adapter device */
在 I2C 子系统中,I2C 适配器使用结构 struct i2c_adapter 描述,代表一条实际的 I2C 总线。 struct i2c_algo_bit_data 结构定义在 include/linux/i2c-algo-bit.h 中 [html] view plaincopyprint? /* private data for lowlevel routines */ void *data; void (*setsda) (void *data, int state); void (*setscl) (void *data, int state); int int (*getsda) (void *data); (*getscl) (void *data); 1. struct i2c_algo_bit_data { 1. 2. 2. 3. 3. 4. 4. 5. 5. 6. 6. 7. 7. 8. 8. 9. 9. 10. 10. 11. 11. 12. 12. 13. 13. 14. 14. }; /* local settings */ int udelay; int timeout; /* half clock cycle time in us, minimum 2 us for fast-mode I2C, minimum 5 us for standard-mode I2C and SMBus, maximum 50 us for SMBus */ /* in jiffies */ 这个结构主要用来定义对 GPIO 管脚的一些操作,还是回到 probe 中 接下来使用 gpio_request 去申请这个两个 GPIO 管脚,申请的目的是为了防止重复使用管脚。 然后是根据 struct i2c_gpio_platform_data 结构中定义的后面三个数据对 struct i2c_algo_bit_data 结构中的函数指针做一些赋值操作。接下来是 I2C 时钟频率和超时设置, 如果在 struct i2c_gpio_platform_data 结构中定义了值,那么就采用定义的值,否则就采用默 认的值。然后是对 struct i2c_adapter 结构的一些赋值操作,比如指定它的父设备为这里的平 台设备,前面在平台设备中定义了一个 id,这里用到了,赋给了 struct i2c_adapter 中的 nr 成员,这个值表示总线号,这里的总线号和硬件无关,只是在软件上的区分。然后到了最后 的主角 i2c_bit_add_numbered_bus,这个函数定义在 drivers/i2c/algos/i2c-algo-bit.c 中 [html] view plaincopyprint? int err; 1. 1. int i2c_bit_add_numbered_bus(struct i2c_adapter *adap) 2. 2. { 3. 3. 4. 4. 5. 5. 6. 6. 7. 7. 8. 8. 9. 9. 10. 0. } err = i2c_bit_prepare_bus(adap); if (err) return i2c_add_numbered_adapter(adap); return err;
先看 i2c_bit_prepare_bus 函数 [html] view plaincopyprint? if (bit_test) { struct i2c_algo_bit_data *bit_adap = adap->algo_data; int ret = test_bus(bit_adap, adap->name); if (ret < 0) 1. static int i2c_bit_prepare_bus(struct i2c_adapter *adap) 1. 2. { 2. 3. 3. 4. 4. 5. 5. 6. 6. 7. 7. 8. 8. 9. 9. 10. 10. 11. 11. 12. 12. 13. 13. 14. 14. 15. 15. 16. 16. } /* register new adapter to i2c module... */ adap->algo = &i2c_bit_algo; adap->retries = 3; return -ENODEV; } return 0; bit_test 为模块参数,这里不管它,看这样一句 adap->algo= &i2c_bit_algo; 来看这个结构定义 [html] view plaincopyprint? 1. 1. static const struct i2c_algorithm i2c_bit_algo = { 2. 2. 3. 3. 4. 4. }; .master_xfer .functionality = bit_xfer, = bit_func, 先看这个结构类型在哪里定义的 include/linux/i2c.h [html] view plaincopyprint? 1. 2. 3. 4. 5. 6. 7. 8. 1. struct i2c_algorithm { 2. r 3. 4. 5. 6. 7. 8. int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, /* If an adapter algorithm can't do I2C-level access, set master_xfe to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages */ /* master_xfer should return the number of messages successfully processed, or a negative value on error */
9. 9. 10. 10. 11. 11. 12. 12. 13. 13. 14. 14. 15. 15. 16. 16. }; int num); int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); /* To determine what the adapter supports */ u32 (*functionality) (struct i2c_adapter *); 其实也没什么,就三个函数指针外加一长串注释 这个结构的 master_xfer 指针为主机的数据传输,具体来看 bit_xfer 这个函数,这个函数和 I2C 协议相关,I2C 协议规定要先发送起始信号,才能开始进行数据的传输,最后数据传输完成 后发送停止信号,看接下来代码对 I2C 协议要熟悉,所以这里的关键点是 I2C 协议。 { struct i2c_msg *pmsg; struct i2c_algo_bit_data *adap = i2c_adap->algo_data; int i, ret; unsigned short nak_ok; struct i2c_msg msgs[], int num) 1. static int bit_xfer(struct i2c_adapter *i2c_adap, 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. } ret = bit_doAddress(i2c_adap, pmsg); if ((ret != 0) && !nak_ok) { if (i) { bit_dbg(3, &i2c_adap->dev, "emitting " "repeated start condition\n"); i2c_repstart(adap); bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); /*发送起始信号*/ i2c_start(adap); for (i = 0; i < num; i++) { pmsg = &msgs[i]; nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; if (!(pmsg->flags & I2C_M_NOSTART)) { bit_dbg(1, &i2c_adap->dev, "NAK from "
分享到:
收藏