Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
LINUX I2C DEVICE DRIVER
在Raspberry Pi 上面學 Linux 驅動程式開發
1
I2C 簡介
24LC02 EEPROM 簡介
Linux I2C Driver Framework
I2C Client Driver FOR 24LC02
I2c Host Controller (Master Driver)
User S...
它是一種半雙工的串列式 bus
它是一種廣播式的 bus
三種通訊速度
1. Standard is 100 Kbps
2. Fast-mode is 400 Kbps
3. high-speed mode supports speeds up...
4
硬體接線
5
硬體訊號
6
Start and Stop conditions
•
7
Data format
• Every byte put on the SDA line must be 8-bits long.
• Each byte has to be followed by an acknowledge bit.
8
Link level protocol
艾鍗Raspberry Pi I/O 上的 Serial EEPROM
24C02
2Kbit size (256x8bit) serial EEPROM
I2C interface
32 pages of 8 bytes each
SOIC-8
Serial EEPROM 規格與線路
24C02 Write OPERATION
Page write operations are limited to writing bytes within a single physical page
Physical page bound...
12
24C02 READ OPERATION
Two groups of eight addresses (0000XXX and 1111XXX) are reserved for
the purposes
Linux I2C Driver Framework
14
Software stack
User Applications
/sys
i2c-dev
i2c Driver
i2c Client Device
i2c Bus
User space
Kernel space
Hardware
/sy...
drivers/i2c – i2c的根目錄
1. busses – i2c adapter的驅動程式 (handle i2c bus)
2. i2c-core.c: i2c bus 通訊軟體層, 提供了client <-> adapter 通訊...
I2C Client Driver FOR 24LC02
I2C Client Driver in Kernel
I2C Client
.type=“at24”
.address
=0x50
I2C Driver
static struct i2c_driver at24_driver = {
.dr...
id_table 主要是讓一個Driver 可以同時支援多個
設備驅動
.driver_data : 允許每個設備有不同的參數
• 和void * platform_data有異曲同工之處
.id_table
struct i2c_device...
加入到 /arm/mach-bcm2708/bcm2708.c
新增I2C Device for EEPROM
//------ADD EEPROM AT24 Device------------------
static void eepro...
i2c_add_driver()
註冊 I2C Driver for i2c client
i2c-bus interface Header 定義:
include/linux/i2c.h
I2C Client device
i2c-bus interface Header 定義:
include/linux/i2c.h
struct i2c_driver — represent an I2C device driver
struct i2c_client — re...
每一次的START就要包裝成一個i2c message, 然後用i2c_transfer()去送,
i2c_transfer()送完後就是STOP狀態
I2c Message Format
Example for write command
a...
i2c_transfer()
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
{
if (adap->algo->master_xfer) {...
#include <linux/i2c.h>
struct i2c_msg for read example
static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, ...
Low-Level Sysfs Operations for EEPROM
Low-Level Sysfs Operations
struct at24_data {
struct at24_platform_data chip;
struct mutex lock;
......
struct bin_attribu...
ls –l /sys/bus/i2c/devices
User Applications 使用/sys
長出eerpom的bin檔案
先修改 /arm/mach-bcm2708/bcm2708.c, 加
入I2C client Device (i2c board info)
範例程式:
cd Pi_driver11_I2C_eerpom
make
insmod at24.ko...
EEPROM就像檔案一樣操作
> echo "ittraining" > eeprom
> hexedit eeprom
> cd /sys/bus/i2c/devices/1-0050
> dd if=/dev/zero of=eeprom ...
I2C Message & Ioctl
i2c-bus driver, char device interface
• open (“/dev/i2c-1”)
/dev/i2c
#include <linux/i2c-dev.h >
i2c-dev.h
Example: see eeprom-i2c.c
進入Pi_driver範例程式
1. cd Pi_driver/11_I2C_eerpom/i2c-dev
2. make
3. insmod i2c-dev.ko 產生 /dev/i2c-1
4. gcc eeprom-i2c.c –o e...
i2cdetect -y 1
EEPROM read/write using i2cset/i2cget
Using i2c-tools
37
Using i2c-tools
I2c Host Controller (Master Driver)
I2C Bus Driver (I2C Adapter driver)
Declare a
Platform Device
(describe BSC1)
Register a
Platform Driver
drivers/i2c/buses...
arch/arm/mach-bcm2708/bcm2708.c
Platform Device Register
static struct platform_device bcm2708_bsc1_device = {
.name = "bc...
• struct i2c_adapter;
• struct algorithm;
• int i2c_add_numbered_adapter(struct i2c_adapter *adap);
• int i2c_del_adapter(...
42
struct i2c_adapter
/*adapter number for a specific adapter*/
43
struct i2c_algorithm
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2...
arch/arm/mach-bcm2708/bcm2708.c
註冊 Platform Device for I2C Host
static struct platform_device bcm2708_bsc0_device = {
.nam...
static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static struc...
Bus transfer function (i2c-bcm2708.c)
static int bcm2708_i2c_master_xfer( struct i2c_adapter *adap, struct i2c_msg *msgs, ...
I2C Adapter-Specific Code
See BCM2835 ARM
Peripherals
BSC (Broadcom Serial
Controller) p.28~p.37
I2C Adapter-Specific Code
See BCM2835 ARM
Peripherals
BSC (Broadcom Serial
Controller) p.28~p.37
cd Pi_driver/11_I2C_eerpom/bus-master
make
insmod i2c-bcm2708.ko
dmesg -c
Exercise
gcc eeprom-i2c.c –o eep
Lab : using LA to analyze the protocol
./eep w 0x50 0x10 0x55
./eep r 0x50 0x10
BCM2835 ARM Peripherals Manual
24C02C Datasheet
Kernel Documentation/ Linux I2C
Framework
References
Upcoming SlideShare
Loading in …5
×

用Raspberry Pi 學Linux I2C Driver

25,387 views

Published on

用Raspberry Pi 學Linux I2C Driver

http://www.ittraining.com.tw/ittraining/course/embedded/devicedriver

Published in: Engineering
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

用Raspberry Pi 學Linux I2C Driver

  1. 1. LINUX I2C DEVICE DRIVER 在Raspberry Pi 上面學 Linux 驅動程式開發 1
  2. 2. I2C 簡介 24LC02 EEPROM 簡介 Linux I2C Driver Framework I2C Client Driver FOR 24LC02 I2c Host Controller (Master Driver) User Space Driver Low-Level Sysfs Operations Outline
  3. 3. 它是一種半雙工的串列式 bus 它是一種廣播式的 bus 三種通訊速度 1. Standard is 100 Kbps 2. Fast-mode is 400 Kbps 3. high-speed mode supports speeds up to 3.4 Mbps supports 7-bit and 10-bit address Master-slave communication 3 What is I2C (Inter-IC) ?
  4. 4. 4 硬體接線
  5. 5. 5 硬體訊號
  6. 6. 6 Start and Stop conditions •
  7. 7. 7 Data format • Every byte put on the SDA line must be 8-bits long. • Each byte has to be followed by an acknowledge bit.
  8. 8. 8 Link level protocol
  9. 9. 艾鍗Raspberry Pi I/O 上的 Serial EEPROM
  10. 10. 24C02 2Kbit size (256x8bit) serial EEPROM I2C interface 32 pages of 8 bytes each SOIC-8 Serial EEPROM 規格與線路
  11. 11. 24C02 Write OPERATION Page write operations are limited to writing bytes within a single physical page Physical page boundaries start at addresses that are integer multiples of the page buffer size (or ‘page size’) and end at addresses that are integer multiples of [page size – 1].
  12. 12. 12 24C02 READ OPERATION Two groups of eight addresses (0000XXX and 1111XXX) are reserved for the purposes
  13. 13. Linux I2C Driver Framework
  14. 14. 14 Software stack User Applications /sys i2c-dev i2c Driver i2c Client Device i2c Bus User space Kernel space Hardware /sys/device/platform/ i2c /dev/i2c-0, /dev/i2c-1 i2c User space driver i2c Client Device i2c Driver i2c-core adapter- Specific code adapter- Specific code i2c adapter i2c algorithm i2c Host Controller (adpter)
  15. 15. drivers/i2c – i2c的根目錄 1. busses – i2c adapter的驅動程式 (handle i2c bus) 2. i2c-core.c: i2c bus 通訊軟體層, 提供了client <-> adapter 通訊 3. I2c-dev.c 通用的 user space client driver for /dev/i2c-x 4. algos 實現了一些I2C adapter的algorithm, algorithm 完成不同底層傳送控制方式, 如 I2C-Bus bit-banging algorithm (alog/i2c-algo-bit.c) 15 Linux i2C 程式檔案結構
  16. 16. I2C Client Driver FOR 24LC02
  17. 17. I2C Client Driver in Kernel I2C Client .type=“at24” .address =0x50 I2C Driver static struct i2c_driver at24_driver = { .driver = { .name = “at24-eeprom", // name string only .owner = THIS_MODULE, }, .probe = at24_probe, .remove = at24_remove, //List of I2C devices supported by this driver .id_table = at24_ids, }; i2c_add_driver(&at24_driver);//i2c driver的註冊 … 一旦i2c_add_driver註冊成功, kernel call probe()函式(即 at24_probe) at24_probe(struct i2c_client *client, const struct i2c_device_id *id) client : 表示找到的I2C Client 裝置 (即原註冊的i2c_board_info ) id : 表示在 .id_table 表格中找到對應的那一筆 .probe i2c_add_driver(struct i2c_driver * ) struct i2c_device_id *id I2C Adapter SCL SDA I2C Host 負責底層i2c bus通訊 static struct i2c_board_info at24lc16[ ] = { { I2C_BOARD_INFO("at24", 0x50), .platform_data = &bcm2708_eeprom_info, .irq=xx }, }; struct i2c_client *client I2C Client .type=“xxxx” .address =0x?? I2C Bus static const struct i2c_device_id at24_ids[] = { { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) }, { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) }, .... { "at24", 0 }, }; i2c_register_board_info(bus , i2c_board_info, )
  18. 18. id_table 主要是讓一個Driver 可以同時支援多個 設備驅動 .driver_data : 允許每個設備有不同的參數 • 和void * platform_data有異曲同工之處 .id_table struct i2c_device_id { char name[I2C_NAME_SIZE]; kernel_ulong_t driver_data /* data private to the driver */ __attribute__((aligned(sizeof(kernel_ulong_t)))); };
  19. 19. 加入到 /arm/mach-bcm2708/bcm2708.c 新增I2C Device for EEPROM //------ADD EEPROM AT24 Device------------------ static void eeprom_init_setup(struct memory_accessor *mem_acc , void *context) { dprint("nDo init work for EEPROMn"); } static struct at24_platform_data bcm2708_eeprom_info = { // EEPROM chip capability .byte_len = (2*1024)/8, // 256byte (24LC02) .page_size = 8, // page write 8 byte; see chip datasheet (15) .setup = eeprom_init_setup, .context = (void*)NULL, }; static struct i2c_board_info __initdata at24lc16[] = { { I2C_BOARD_INFO("at24", 0x50), //name of device as well as slave addr. .platform_data = &bcm2708_eeprom_info, }, }; i2c_register_board_info(1,at24lc16, ARRAY_SIZE(at24lc16));
  20. 20. i2c_add_driver() 註冊 I2C Driver for i2c client
  21. 21. i2c-bus interface Header 定義: include/linux/i2c.h I2C Client device
  22. 22. i2c-bus interface Header 定義: include/linux/i2c.h struct i2c_driver — represent an I2C device driver struct i2c_client — represent an I2C slave device struct i2c_board_info — template for device creation I2C_BOARD_INFO — macro used to list an i2c device and its address i2c_register_board_info — statically declare I2C devices struct i2c_msg — an I2C transaction segment beginning with START i2c_transfer — execute a single or combined I2C message i2c_add_driver — unregister I2C driver i2c_del_driver — unregister I2C driver void i2c_set_clientdata(struct i2c_client *dev, void *data) void *i2c_get_clientdata(const struct i2c_client *dev) Kernel API for I2C Driver static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) { dev_set_drvdata(&dev->dev, data); } 同platform_set_drvdata 及 platform_get_drvdata
  23. 23. 每一次的START就要包裝成一個i2c message, 然後用i2c_transfer()去送, i2c_transfer()送完後就是STOP狀態 I2c Message Format Example for write command addr flags
  24. 24. i2c_transfer() int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) { if (adap->algo->master_xfer) { …….. ret = __i2c_transfer(adap, msgs, num); …. } else { dev_dbg(&adap->dev, "I2C level transfers not supportedn"); return -EOPNOTSUPP; } } It depends on the implementation of bus driver ……. (we will discuss later)
  25. 25. #include <linux/i2c.h> struct i2c_msg for read example static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, unsigned offset, size_t count) { struct i2c_msg msg[2]; u8 msgbuf[2]; memset(msg, 0, sizeof(msg)); msgbuf[0] = offset; msg[0].addr = client->addr; msg[0].buf = msgbuf; msg[0].len = 1; msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; msg[1].buf = buf; msg[1].len = count; status = i2c_transfer(client->adapter, msg, 2); if (status == 2) status = count; ….. }
  26. 26. Low-Level Sysfs Operations for EEPROM
  27. 27. Low-Level Sysfs Operations struct at24_data { struct at24_platform_data chip; struct mutex lock; ...... struct bin_attribute bin; ...... }; static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) { …………….. sysfs_bin_attr_init(&at24->bin); at24->bin.attr.name = “eeprom”; //file name at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR; at24->bin.read = at24_bin_read; // function pointer to read operation at24->bin.size = chip.byte_len; //256byte at24->bin.write = at24_bin_write; ; // function pointer to write operation at24->bin.attr.mode |= S_IWUSR; ……… err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin); } struct attribute { char *name; struct module *owner; mode_t mode; }; struct bin_attribute { struct attribute attr; size_t size; ssize_t (*read)(struct kobject *kobj, char *buffer, loff_t pos, size_t size); ssize_t (*write)(struct kobject *kobj, char *buffer, loff_t pos, size_t size); };
  28. 28. ls –l /sys/bus/i2c/devices User Applications 使用/sys 長出eerpom的bin檔案
  29. 29. 先修改 /arm/mach-bcm2708/bcm2708.c, 加 入I2C client Device (i2c board info) 範例程式: cd Pi_driver11_I2C_eerpom make insmod at24.ko ls –l /sys/bus/i2c/drivers, 顯示註冊的i2c driver 的名稱 “at24” Hands on
  30. 30. EEPROM就像檔案一樣操作 > echo "ittraining" > eeprom > hexedit eeprom > cd /sys/bus/i2c/devices/1-0050 > dd if=/dev/zero of=eeprom count=256
  31. 31. I2C Message & Ioctl
  32. 32. i2c-bus driver, char device interface • open (“/dev/i2c-1”) /dev/i2c
  33. 33. #include <linux/i2c-dev.h > i2c-dev.h
  34. 34. Example: see eeprom-i2c.c
  35. 35. 進入Pi_driver範例程式 1. cd Pi_driver/11_I2C_eerpom/i2c-dev 2. make 3. insmod i2c-dev.ko 產生 /dev/i2c-1 4. gcc eeprom-i2c.c –o eep 5. Execute ‘eep’ to read/write EEPROM Hands on
  36. 36. i2cdetect -y 1 EEPROM read/write using i2cset/i2cget Using i2c-tools
  37. 37. 37 Using i2c-tools
  38. 38. I2c Host Controller (Master Driver)
  39. 39. I2C Bus Driver (I2C Adapter driver) Declare a Platform Device (describe BSC1) Register a Platform Driver drivers/i2c/buses/i2c-bcm2708.c int bcm2708_i2c_probe(struct platform_device *pdev) { ………. struct i2c_adapter *adap; struct bcm2708_i2c *bi; /*platform_get_resource & get_irq* / /*set pin to i2C function SDA &SCL* / …….. bi = kzalloc(sizeof(*bi), GFP_KERNEL); adap = &bi->adapter; adap->class = I2C_CLASS_HWMON | I2C_CLASS_DDC; adap->algo = &bcm2708_i2c_algorithm; adap->algo_data = bi; adap->dev.parent = &pdev->dev; adap->nr = pdev->id; strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); /* ioremap & request_irq */ /* haredware init */ …….. //declare i2c adapter, use static bus number i2c_add_numbered_adapter (adap); } adapter-Specific code 註冊一個 i2c adapter i2c algorithm arch/arm/mach-bcm2708/bcm2708.c struct platform_device *pdev Probe Linux I2C subsystem
  40. 40. arch/arm/mach-bcm2708/bcm2708.c Platform Device Register static struct platform_device bcm2708_bsc1_device = { .name = "bcm2708_i2c", .id = 1, .num_resources = ARRAY_SIZE(bcm2708_bsc1_resources), .resource = bcm2708_bsc1_resources }; static struct resource bcm2708_bsc1_resources[] = { { .start = BSC1_BASE, .end = BSC1_BASE + SZ_256 - 1, .flags = IORESOURCE_MEM, }, { .start = INTERRUPT_I2C, .end = INTERRUPT_I2C, .flags = IORESOURCE_IRQ, } }; BCM2835 有3個I2C Host controller platform_device_register(&bcm2708_bsc1_device);
  41. 41. • struct i2c_adapter; • struct algorithm; • int i2c_add_numbered_adapter(struct i2c_adapter *adap); • int i2c_del_adapter(struct i2c_adapter *adap)’ 41 Kernel API for I2C Adapter (master)
  42. 42. 42 struct i2c_adapter /*adapter number for a specific adapter*/
  43. 43. 43 struct i2c_algorithm
  44. 44. #define I2C_FUNC_I2C 0x00000001 #define I2C_FUNC_10BIT_ADDR 0x00000002 #define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ #define I2C_FUNC_SMBUS_PEC 0x00000008 #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_QUICK 0x00010000 #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 #define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 #define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 #define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 #define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 #define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 #define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 #define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 #define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ #define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */ #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */ #define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC 44 I2C Functionality List
  45. 45. arch/arm/mach-bcm2708/bcm2708.c 註冊 Platform Device for I2C Host static struct platform_device bcm2708_bsc0_device = { .name = "bcm2708_i2c", .id = 0, // i2c-0 .num_resources = ARRAY_SIZE(bcm2708_bsc0_resources), .resource = bcm2708_bsc0_resources }; static struct resource bcm2708_bsc0_resources[] = { { .start = BSC0_BASE, .end = BSC0_BASE + SZ_256 - 1, .flags = IORESOURCE_MEM, }, { .start = INTERRUPT_I2C, .end = INTERRUPT_I2C, .flags = IORESOURCE_IRQ, } }; platform_device_register(&bcm2708_bsc0_device);
  46. 46. static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static struct i2c_algorithm bcm2708_i2c_algorithm = { .master_xfer = bcm2708_i2c_master_xfer, // implement bus transfer function .functionality = bcm2708_i2c_functionality, };
  47. 47. Bus transfer function (i2c-bcm2708.c) static int bcm2708_i2c_master_xfer( struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct bcm2708_i2c *bi = adap->algo_data; // chip register control spin_lock_irqsave(&bi->lock, flags); INIT_COMPLETION(bi->done); bi->msg = msgs; bi->pos = 0; bi->nmsgs = num; bi->error = false; bcm2708_bsc_setup(bi); // active chip to do i2c transfer and then wait for its completion /* unlockig _after_ the setup to avoid races with the interrupt routine */ spin_unlock_irqrestore(&bi->lock, flags); ret = wait_for_completion_timeout(&bi->done, msecs_to_jiffies(I2C_TIMEOUT_MS)); if (ret == 0) { dev_err(&adap->dev, "transfer timed outn"); spin_lock_irqsave(&bi->lock, flags); bcm2708_bsc_reset(bi); spin_unlock_irqrestore(&bi->lock, flags); return -ETIMEDOUT; } return bi->error ? -EIO : num; }
  48. 48. I2C Adapter-Specific Code See BCM2835 ARM Peripherals BSC (Broadcom Serial Controller) p.28~p.37
  49. 49. I2C Adapter-Specific Code See BCM2835 ARM Peripherals BSC (Broadcom Serial Controller) p.28~p.37
  50. 50. cd Pi_driver/11_I2C_eerpom/bus-master make insmod i2c-bcm2708.ko dmesg -c Exercise
  51. 51. gcc eeprom-i2c.c –o eep Lab : using LA to analyze the protocol ./eep w 0x50 0x10 0x55 ./eep r 0x50 0x10
  52. 52. BCM2835 ARM Peripherals Manual 24C02C Datasheet Kernel Documentation/ Linux I2C Framework References

×