由於之后的觸摸屏驅動分析中使用到了GPIO子系統和i2c子系統,因此在分析觸摸屏驅動之前我准備把這兩個子系統進行簡單分析。
在讀者學習本章以及后續i2c相關章節之前,最好了解i2c通信方式,可以參考:i2c編程。
一、i2c框架分析
和總線設備驅動模型類似,i2c分為核心層、總線驅動層和設備驅動層。總線驅動層向核心層提供統一接口,設備驅動層實現底層設備操作。
核心層:drivers/i2c/i2c-core.c文件
總線驅動層:i2c總線驅動是i2c適配器的軟件實現,讓i2c適配器與從設備間完成數據通信
設備驅動層:用於實現設備的注冊和設備驅動的注冊
由於i2c也是使用總線,在此不再分析核心層框架,對於總線核心層讀者可以查看:總線設備驅動模型第三節。i2c核心層主要實現的有:
1. 注冊總線i2c_bus_type
2. 提供總線match()等函數。其中總線probe()會調用i2c_driver的probe(),這是因為之前說的:總線驅動層向核心層提供統一接口,設備驅動層實現底層設備操作
3. 向底層提供注冊函數
i2c框架如下圖:

在上圖中除去之前介紹的總線驅動和設備驅動,接下來我會分別介紹其余結構體。
1. i2c_client表示一個i2c設備
1 struct i2c_client { 2 unsigned short flags; /* i2c設備標志位 */ 3 unsigned short addr; /* i2c設備地址 */ 4 char name[I2C_NAME_SIZE]; /* 名字 */ 5 struct i2c_adapter *adapter; /* 指向與其對應的適配器 */ 6 struct i2c_driver *driver; /* 指向與其對應的設備驅動 */ 7 struct device dev; /* the device structure */ 8 int irq; /* irq issued by device */ 9 struct list_head detected; /* 作為節點掛接到i2c_driver鏈表中 */ 10 };
2. i2c_driver表示i2c設備驅動
1 struct i2c_driver { 2 unsigned int class; 3 4 /* attach_adapter()用於匹配適配器 */ 5 int (*attach_adapter)(struct i2c_adapter *) __deprecated; 6 int (*detach_adapter)(struct i2c_adapter *) __deprecated; 7 8 /* 設備驅動層的probe()和注銷函數 */ 9 int (*probe)(struct i2c_client *, const struct i2c_device_id *); 10 int (*remove)(struct i2c_client *); 11 12 /* 電源管理相關,暫時用不到 */ 13 /* driver model interfaces that don't relate to enumeration */ 14 void (*shutdown)(struct i2c_client *); 15 int (*suspend)(struct i2c_client *, pm_message_t mesg); 16 int (*resume)(struct i2c_client *); 17 18 /* Alert callback, for example for the SMBus alert protocol. 19 * The format and meaning of the data value depends on the protocol. 20 * For the SMBus alert protocol, there is a single bit of data passed 21 * as the alert response's low bit ("event flag"). 22 */ 23 void (*alert)(struct i2c_client *, unsigned int data); 24 25 /* a ioctl like command that can be used to perform specific functions 26 * with the device. 27 */ 28 int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); 29 30 struct device_driver driver; /* 設備驅動對應的device_driver */ 31 const struct i2c_device_id *id_table; /* 匹配設備驅動和設備的id_table */ 32 33 /* Device detection callback for automatic device creation */ 34 int (*detect)(struct i2c_client *, struct i2c_board_info *); 35 const unsigned short *address_list; /* 設備驅動支持的所有i2c設備的地址數組 */ 36 struct list_head clients; /* 用於掛接匹配成功的i2c_client的鏈表頭 */ 37 };
3. i2c_adapter表示i2c適配器,可以理解為是一個i2c主機
1 struct i2c_adapter { 2 struct module *owner; 3 unsigned int class; /* classes to allow probing for */ 4 const struct i2c_algorithm *algo; /* 適配器與設備的通信算法 */ 5 void *algo_data; 6 7 /* data fields that are valid for all devices */ 8 struct rt_mutex bus_lock; 9 10 int timeout; /* 超時時間,使用jiffies表示 */ 11 int retries; 12 struct device dev; /* 適配器對應的device */ 13 14 int nr; /* 適配器的編號 */ 15 char name[48]; /* 適配器名字 */ 16 struct completion dev_released; 17 18 struct mutex userspace_clients_lock; 19 struct list_head userspace_clients; /* 用於掛接i2c_client的鏈表頭 */ 20 };
4. i2c_algorithm是i2c數據通信的算法
1 struct i2c_algorithm { 2 /* 數據傳輸函數 */ 3 int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, 4 int num); 5 /* smbus協議傳輸函數,在i2c中使用不上 */ 6 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, 7 unsigned short flags, char read_write, 8 u8 command, int size, union i2c_smbus_data *data); 9 10 /* To determine what the adapter supports */ 11 u32 (*functionality) (struct i2c_adapter *); 12 };
代碼中第3行:struct i2c_msg定義如下:
struct i2c_msg { __u16 addr; /* i2c設備地址 */ __u16 flags; /* 讀/寫。一般1為讀,也就是I2C_M_RD,0為寫 */ #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ #define I2C_M_RD 0x0001 /* read data, from slave to master */ #define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */ #define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ __u16 len; /* msg length */ __u8 *buf; /* pointer to msg data */ };
由於適配器的參數根據芯片不同有所不同。因此i2c_adapter的初始化一般會在會在平台驅動初始化或probe()函數中配置。
i2c_algorithm在i2c_adapter中有指針定義,因此我們需要在配置i2c_adapter之前配置i2c_algorithm。
i2c_client由我們實現,主要需要設置它的地址。
i2c_driver也由我們實現,格式與platform_driver類似。
二、核心層提供的注冊函數
1. i2c_add_adapter()和i2c_add_numbered_adapter()用於注冊i2c_adapter
i2c_add_adapter()由系統給設備分配編號,i2c_add_numbered_adapter()由我們指定設備編號,如果設備編號被使用,會返回錯誤。
兩函數底層調用的都是i2_register_adapter():
1 static int i2c_register_adapter(struct i2c_adapter *adap) 2 { 3 int res = 0; 4 ... 5 rt_mutex_init(&adap->bus_lock); 6 mutex_init(&adap->userspace_clients_lock); 7 8 /* 初始化i2c_adapteruserspace_clients鏈表 */ 9 INIT_LIST_HEAD(&adap->userspace_clients); 10 11 /* Set default timeout to 1 second if not already set */ 12 if (adap->timeout == 0) 13 adap->timeout = HZ; 14 15 dev_set_name(&adap->dev, "i2c-%d", adap->nr); /* 設置adapter名字 */ 16 adap->dev.bus = &i2c_bus_type; /* 設置設備的總線類型 */ 17 adap->dev.type = &i2c_adapter_type; /* 設置設備的設備類型 */ 18 res = device_register(&adap->dev); /* 注冊設備/sys/devices/i2c-%d */ 19 ... 20 /* create pre-declared device nodes */ 21 if (adap->nr < __i2c_first_dynamic_bus_num) 22 i2c_scan_static_board_info(adap); /* 掃描並創建i2c設備 */ 23 24 /* Notify drivers */ 25 mutex_lock(&core_lock); 26 bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter); 27 mutex_unlock(&core_lock); 28 ... 29 return res; 30 }
現在我們繼續分析上面代碼中的第22行:i2c_scan_static_board_info(adap),它調用了i2c_new_device()函數來添加一個i2c設備。
1 static void i2c_scan_static_board_info(struct i2c_adapter *adapter) 2 { 3 struct i2c_devinfo *devinfo; 4 5 down_read(&__i2c_board_lock); 6 list_for_each_entry(devinfo, &__i2c_board_list, list) { 7 if (devinfo->busnum == adapter->nr 8 && !i2c_new_device(adapter, 9 &devinfo->board_info)) 10 dev_err(&adapter->dev, 11 "Can't create device at 0x%02x\n", 12 devinfo->board_info.addr); 13 } 14 up_read(&__i2c_board_lock); 15 }
2. i2c_new_device()用於注冊i2c_client
i2c_new_device()調用了device_register()來添加一個設備。關於device的注冊過程可以查看Linux驅動函數解讀第二節
1 struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) 2 { 3 struct i2c_client *client; 4 int status; 5 /* 設置i2c_client成員 */ 6 client = kzalloc(sizeof *client, GFP_KERNEL); 7 ... 8 client->adapter = adap; 9 10 client->dev.platform_data = info->platform_data; 11 12 if (info->archdata) 13 client->dev.archdata = *info->archdata; 14 15 client->flags = info->flags; 16 client->addr = info->addr; 17 client->irq = info->irq; 18 19 strlcpy(client->name, info->type, sizeof(client->name)); 20 21 /* 判斷地址的有效性 */ 22 status = i2c_check_client_addr_validity(client); 23 ... 24 /* Check for address business */ 25 status = i2c_check_addr_busy(adap, client->addr); 26 ... 27 client->dev.parent = &client->adapter->dev; /* 設置設備的適配器 */ 28 client->dev.bus = &i2c_bus_type; /* 設置所屬總線 */ 29 client->dev.type = &i2c_client_type; /* 設置設備類型 */ 30 client->dev.of_node = info->of_node; 31 32 /* For 10-bit clients, add an arbitrary offset to avoid collisions */ 33 dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), 34 client->addr | ((client->flags & I2C_CLIENT_TEN) 35 ? 0xa000 : 0)); 36 /* 注冊設備 */ 37 status = device_register(&client->dev); 38 ... 39 40 return client; 41 ... 42 }
i2c_new_device()函數的第二個傳入參數struct i2c_board_info涉及了i2_client的設置。該參數應該是我們注冊設備時傳入的,我們可以在內核中搜索static struct i2c_board_info來看看它的格式是什么:
1 static struct i2c_board_info i2c_board_info[] = { 2 { 3 /* "uda1380"為名字,0x18為設備地址 */ 4 I2C_BOARD_INFO("uda1380", 0x18), 5 /* 自己定義的結構體,在此不需要關心 */ 6 .platform_data = &uda1380_info, 7 }, 8 };
此處我們需要特別注意設備地址的定義。在uda1380的數據手冊中可以確定其i2c設備地址如下圖所示:
由於最后一位為讀寫位,因此地址為0x18而不是0x30。
3. i2c_add_driver()用於注冊i2c_device driver
i2c_add_driver()調用了i2c_register_driver()來注冊一個設備驅動。
1 int i2c_register_driver(struct module *owner, struct i2c_driver *driver) 2 { 3 int res; 4 5 /* Can't register until after driver model init */ 6 if (unlikely(WARN_ON(!i2c_bus_type.p))) 7 return -EAGAIN; 8 9 /* add the driver to the list of i2c drivers in the driver core */ 10 driver->driver.owner = owner; 11 driver->driver.bus = &i2c_bus_type; 12 13 /* 注冊設備驅動 */ 14 res = driver_register(&driver->driver); 15 ... 16 /* 初始化 i2c_driver->clients 鏈表 */ 17 INIT_LIST_HEAD(&driver->clients); 18 /* Walk the adapters that are already present */ 19 i2c_for_each_dev(driver, __process_new_driver); 20 21 return 0; 22 }
代碼中第14行:driver_register()函數調用過程和platform_driver_register()的driver_register()函數調用過程是一樣的。
driver_register(&drv->driver); -> bus_add_driver(drv); // 添加驅動到鏈表中 -> driver_attach(drv); -> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); -> __driver_attach() -> driver_match_device(drv, dev); // 調用driver的match() -> return drv->bus->match ? drv->bus->match(dev, drv) : 1; -> driver_probe_device(drv, dev); -> really_probe(dev, drv); -> drv->probe(dev); // 調用i2c_driver的probe()函數
通過前3點分析,可知i2c子系統內部存在着兩個匹配過程:
1. i2c_adapter與i2c_client之間,兩者通過適配器編號進行匹配
2. i2c總線下的i2c_client與i2c_driver之間,兩者通過設備驅動的id_table進行匹配
在第一節末尾,我提到了四個結構體的實現位置。在第三節,我會根據具體平台進行分析。
三、i2c-s3c2410.c文件分析
首先我們來查看probe()函數:
1 static int s3c24xx_i2c_probe(struct platform_device *pdev) 2 { 3 struct s3c24xx_i2c *i2c; 4 struct s3c2410_platform_i2c *pdata = NULL; 5 struct resource *res; 6 int ret; 7 ... 8 i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL); 9 ... 10 i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 11 ... 12 i2c->quirks = s3c24xx_get_device_quirks(pdev); 13 if (pdata) 14 memcpy(i2c->pdata, pdata, sizeof(*pdata)); 15 else 16 s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c); 17 /* 設置i2c_adapter */ 18 strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); 19 i2c->adap.owner = THIS_MODULE; 20 i2c->adap.algo = &s3c24xx_i2c_algorithm; /* 通信算法 */ 21 i2c->adap.retries = 2; 22 i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; 23 i2c->tx_setup = 50; 24 25 init_waitqueue_head(&i2c->wait); 26 27 /* find the clock and enable it */ 28 29 i2c->dev = &pdev->dev; 30 i2c->clk = clk_get(&pdev->dev, "i2c"); /* 獲取並使能時鍾 */ 31 ... 32 clk_enable(i2c->clk); 33 34 /* map the registers */ 35 36 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 37 ... 38 i2c->ioarea = request_mem_region(res->start, resource_size(res), pdev->name); 39 ... 40 i2c->regs = ioremap(res->start, resource_size(res)); 41 ... 42 i2c->adap.algo_data = i2c; 43 i2c->adap.dev.parent = &pdev->dev; 44 45 /* inititalise the i2c gpio lines */ 46 47 if (i2c->pdata->cfg_gpio) { 48 i2c->pdata->cfg_gpio(to_platform_device(i2c->dev)); 49 } 50 ... 51 ret = s3c24xx_i2c_init(i2c); /* 硬件初始化 */ 52 ... 53 i2c->irq = ret = platform_get_irq(pdev, 0); 54 ... 55 ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0, 56 dev_name(&pdev->dev), i2c); 57 ... 58 ret = s3c24xx_i2c_register_cpufreq(i2c); 59 ... 60 i2c->adap.nr = i2c->pdata->bus_num; 61 i2c->adap.dev.of_node = pdev->dev.of_node; 62 63 ret = i2c_add_numbered_adapter(&i2c->adap); /* 注冊i2c_adapter */ 64 ... 65 of_i2c_register_devices(&i2c->adap); 66 platform_set_drvdata(pdev, i2c); 67 ... 68 clk_disable(i2c->clk); 69 ... 70 return ret; 71 }
和我們預想的一致,probe()函數初始化並注冊了i2c_adapter和i2c_algorithm。
看完i2c_adapter之后,我們來看一下i2c_algorithm是如何定義的。
1 /* 底層寄存器操作 */ 2 static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, struct i2c_msg *msg) 3 { 4 unsigned int addr = (msg->addr & 0x7f) << 1; 5 unsigned long stat; 6 unsigned long iiccon; 7 8 stat = 0; 9 stat |= S3C2410_IICSTAT_TXRXEN; 10 11 if (msg->flags & I2C_M_RD) { 12 stat |= S3C2410_IICSTAT_MASTER_RX; 13 addr |= 1; 14 } else 15 stat |= S3C2410_IICSTAT_MASTER_TX; 16 17 if (msg->flags & I2C_M_REV_DIR_ADDR) 18 addr ^= 1; 19 20 /* todo - check for whether ack wanted or not */ 21 s3c24xx_i2c_enable_ack(i2c); 22 23 iiccon = readl(i2c->regs + S3C2410_IICCON); 24 writel(stat, i2c->regs + S3C2410_IICSTAT); 25 26 dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr); 27 writeb(addr, i2c->regs + S3C2410_IICDS); 28 29 /* delay here to ensure the data byte has gotten onto the bus 30 * before the transaction is started */ 31 32 ndelay(i2c->tx_setup); 33 34 dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon); 35 writel(iiccon, i2c->regs + S3C2410_IICCON); 36 37 stat |= S3C2410_IICSTAT_START; 38 writel(stat, i2c->regs + S3C2410_IICSTAT); 39 } 40 41 static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, 42 struct i2c_msg *msgs, int num) 43 { 44 unsigned long timeout; 45 int ret; 46 ... 47 ret = s3c24xx_i2c_set_master(i2c); 48 ... 49 i2c->msg = msgs; 50 i2c->msg_num = num; 51 i2c->msg_ptr = 0; 52 i2c->msg_idx = 0; 53 i2c->state = STATE_START; 54 55 s3c24xx_i2c_enable_irq(i2c); 56 s3c24xx_i2c_message_start(i2c, msgs); 57 58 timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); 59 60 ret = i2c->msg_idx; 61 ... 62 s3c24xx_i2c_wait_idle(i2c); 63 return ret; 64 } 65 66 static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, 67 struct i2c_msg *msgs, int num) 68 { 69 struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data; 70 int retry; 71 int ret; 72 73 pm_runtime_get_sync(&adap->dev); 74 clk_enable(i2c->clk); 75 76 for (retry = 0; retry < adap->retries; retry++) { 77 78 ret = s3c24xx_i2c_doxfer(i2c, msgs, num); 79 80 if (ret != -EAGAIN) { 81 clk_disable(i2c->clk); 82 pm_runtime_put_sync(&adap->dev); 83 return ret; 84 } 85 86 dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry); 87 88 udelay(100); 89 } 90 91 clk_disable(i2c->clk); 92 pm_runtime_put_sync(&adap->dev); 93 return -EREMOTEIO; 94 } 95 96 static u32 s3c24xx_i2c_func(struct i2c_adapter *adap) 97 { 98 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART | 99 I2C_FUNC_PROTOCOL_MANGLING; 100 } 101 102 static const struct i2c_algorithm s3c24xx_i2c_algorithm = { 103 .master_xfer = s3c24xx_i2c_xfer, 104 .functionality = s3c24xx_i2c_func, 105 };
代碼中底層操作是我們可能需要根據用戶手冊時序的屬性更改的部分;i2c_algorithm成員函數functionality定義的是adapter所具有的功能,如是否支持smbus協議。
四、設備驅動層程序編寫過程
我們在寫i2c設備驅動層時,需要獲取i2c_adapter,此時需要使用的函數是i2c_adapter *i2c_get_adapter(int nr)。
與i2c_get_adapter()對應的注銷使用函數是void i2c_put_adapter(struct i2c_adapter *adap)。
消息接收頂層使用的是int i2c_master_send(const struct i2c_client *client, const char *buf, int count)和int i2c_master_recv(const struct i2c_client *client, char *buf, int count)。兩函數底層調用都是i2c_transfer(),我們也可以直接調用i2c_transfer()。
i2c_get_adapter()函數參數nr為adapter的編號,如下圖,nr有0、1、3等。

除上圖之外,我們也可以查看設備地址等信息。
查詢i2c設備地址:ls /sys/bus/i2c/devices/
設備和原理圖對應關系:3-0038 I2C_3_SCL(addr為0x38)
查詢i2c設備名稱:cat /sys/bus/i2c/devices/3-0038/name

現在我們來想象一下設備驅動層程序編寫過程:
對於i2c_client:
1. 設置struct i2c_board_info
2. 在初始化函數中,首先i2c_get_adapter()獲取adapter,之后通過i2c_new_device()和傳入參數adapter與struct i2c_board_info獲取struct i2c_client,最后i2c_put_adapter()釋放adapter
3. 在退出函數中,i2c_unregister_device()
對於i2c_driver:
1. 定義i2c_driver(定義與platform_driver類似,多個一個用於匹配i2c_client的id_table,也就是struct i2c_device_id)
2. 由於i2c也屬於字符設備,所以我們要在probe()函數中注冊cdev、file_operations、class和device
2. 在write()函數中調用i2c_master_send()
3. 在read()函數中調用i2c_master_recv()
4. 在初始化函數中,i2c_add_driver()
5. 在退出函數中,i2c_del_driver()
下一章我們來實現觸摸屏驅動程序。
下一章 15、電容觸摸屏驅動
