"./drivers/i2c/busses/i2c-s3c2410.c"是3.14.0內(nèi)核中三星SoC的i2c控制器驅(qū)動(dòng)程序, 本文試圖通過(guò)對(duì)這個(gè)程序的分析, 剝離繁復(fù)的細(xì)節(jié), 總結(jié)一套編寫(xiě)i2c主機(jī)控制器驅(qū)動(dòng)的框架以及一個(gè)分析內(nèi)核驅(qū)動(dòng)的流程.
匹配之前
1287 static int __init i2c_adap_s3c_init(void)
1288 {
1289 return platform_driver_register(&s3c24xx_i2c_driver);
1290 }
1291 subsys_initcall(i2c_adap_s3c_init);
--1291-->將主機(jī)控制器驅(qū)動(dòng)在系統(tǒng)啟動(dòng)的時(shí)候就注冊(cè)好
--1289-->這個(gè)驅(qū)動(dòng)是基于platform總線的, 設(shè)備信息的部分在板級(jí)文件i2c_board_info中描述并作為platform_device隨內(nèi)核啟動(dòng)被注冊(cè), 所以控制器驅(qū)動(dòng)在系統(tǒng)啟動(dòng)的時(shí)候就可以工作了
1275 static struct platform_driver s3c24xx_i2c_driver = {
1276 .probe = s3c24xx_i2c_probe,
1277 .remove = s3c24xx_i2c_remove,
1278 .id_table = s3c24xx_driver_ids,
1279 .driver = {
1280 .owner = THIS_MODULE,
1281 .name = "s3c-i2c",
1282 .pm = S3C24XX_DEV_PM_OPS,
1283 .of_match_table = of_match_ptr(s3c24xx_i2c_match),
1284 },
1285 };
既然是遵循的platform編寫(xiě), 那么所有的信息都要在一個(gè)platform_driver中描述, 分析也是圍繞這個(gè)對(duì)象展開(kāi)
--1276-->probe函數(shù), 最重要的函數(shù)
--1278-->用于匹配的id表, 由于是平臺(tái)文件編寫(xiě)的設(shè)備信息, 所以會(huì)使用這個(gè)域作為匹配的依據(jù), 如下
132 static struct platform_device_id s3c24xx_driver_ids[] = {
133 {
134 .name = "s3c2410-i2c",
135 .driver_data = 0,
136 }, {
137 .name = "s3c2440-i2c",
138 .driver_data = QUIRK_S3C2440,
139 }, {
140 .name = "s3c2440-hdmiphy-i2c",
141 .driver_data = QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO,
142 }, { },
143 };
我們可以在"arch/arm/plat-samsung"中找到相應(yīng)的設(shè)備信息
485 struct platform_device s3c_device_i2c0 = {
486 .name = "s3c2410-i2c",
487 .id = 0,
488 .num_resources = ARRAY_SIZE(s3c_i2c0_resource),
489 .resource = s3c_i2c0_resource,
490 };
二者一匹配, probe就執(zhí)行!
匹配之后
一旦匹配上, 分析流程就會(huì)有點(diǎn)變化, 驅(qū)動(dòng)開(kāi)發(fā)都是基于面向?qū)ο蟮乃枷氲? 內(nèi)核雖然給我們封裝了很多"類(lèi)", 但當(dāng)我們開(kāi)發(fā)一個(gè)具體的驅(qū)動(dòng)的時(shí)候, 還是要對(duì)其進(jìn)行"繼承", 進(jìn)而創(chuàng)建針對(duì)具體設(shè)備的資源對(duì)象, 資源對(duì)象管理著驅(qū)動(dòng)中諸多函數(shù)的共用資源, 是整個(gè)驅(qū)動(dòng)運(yùn)行過(guò)程中資源管理者與橋梁, 主要包括:內(nèi)核類(lèi)+資源(io, irq,時(shí)鐘, 寄存器)+狀態(tài)表示+其他,所以, 設(shè)計(jì)驅(qū)動(dòng)的工作中很重要的一個(gè)工作就是"設(shè)計(jì)資源類(lèi)". 下面就是三星設(shè)計(jì)的類(lèi), 我把次要的部分剔除了
資源類(lèi)
資源對(duì)象是整個(gè)驅(qū)動(dòng)運(yùn)作的核心, 所有的方法需要的資源都是對(duì)這個(gè)對(duì)象的操作, 它的設(shè)計(jì)是迭代的過(guò)程, 但當(dāng)整個(gè)框架搭起來(lái)之后, 不應(yīng)該有大的變化
103 struct s3c24xx_i2c {
104 wait_queue_head_t wait;
108 struct i2c_msg *msg;
109 unsigned int msg_num;
110 unsigned int msg_idx;
111 unsigned int msg_ptr;
113 unsigned int tx_setup;
114 unsigned int irq;
116 enum s3c24xx_i2c_state state;
117 unsigned long clkrate;
119 void __iomem *regs;
120 struct clk *clk;
121 struct device *dev;
122 struct i2c_adapter adap;
124 struct s3c2410_platform_i2c *pdata;
125 int gpios[2];
130 };
struct s3c24xx_i2c
--108-->收到的i2c-core.c發(fā)送過(guò)來(lái)的i2c_msg對(duì)象數(shù)組首地址
--109-->i2c_msg數(shù)組的元素個(gè)數(shù)
--110-->i2c_msg數(shù)組元素的索引
--114-->使用的中斷號(hào)
--116-->當(dāng)前控制器的狀態(tài), 用枚舉量表示STATE_IDLE, STATE_START,STATE_READ,STATE_WRITE,STATE_STOP
--117-->時(shí)鐘頻率
--120-->時(shí)鐘
--121-->屬于device, 按照device來(lái)管理
--122-->構(gòu)造并使用的i2c_adapter對(duì)象, 和上一篇的框架圖對(duì)應(yīng)
--124-->封裝的平臺(tái)信息, 是一個(gè)數(shù)組首地址, 每一個(gè)元素包括從機(jī)地址, 標(biāo)志位, 總線編號(hào)等
probe
probe主要負(fù)責(zé)"申請(qǐng)資源+初始化+提供接口", 通過(guò)對(duì)probe的分析, 就可以對(duì)整個(gè)驅(qū)動(dòng)的構(gòu)建有一個(gè)
提綱挈領(lǐng)的理解
1072 static int s3c24xx_i2c_probe(struct platform_device *pdev)
1073 {
1074 struct s3c24xx_i2c *i2c;
1075 struct s3c2410_platform_i2c *pdata = NULL;
1076 struct resource *res;
1077 int ret;
1078
1079 if (!pdev->dev.of_node) {
1080 pdata = dev_get_platdata(&pdev->dev);
1085 }
1086
1087 i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
1092
1093 i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1098
1099 i2c->quirks = s3c24xx_get_device_quirks(pdev);
1100 if (pdata)
1101 memcpy(i2c->pdata, pdata, sizeof(*pdata));
1102 else
1103 s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
1104
1105 strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
1106 i2c->adap.owner = THIS_MODULE;
1107 i2c->adap.algo = &s3c24xx_i2c_algorithm;
1108 i2c->adap.retries = 2;
1109 i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
1110 i2c->tx_setup = 50;
1111
1112 init_waitqueue_head(&i2c->wait);
1113
1114 /* find the clock and enable it */
1116 i2c->dev = &pdev->dev;
1117 i2c->clk = devm_clk_get(&pdev->dev, "i2c");
1124
1126 /* map the registers */
1128 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1129 i2c->regs = devm_ioremap_resource(&pdev->dev, res);
1136
1137 /* setup info block for the i2c core */
1139 i2c->adap.algo_data = i2c;
1140 i2c->adap.dev.parent = &pdev->dev;
1141
1142 i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);
1143
1144 /* inititalise the i2c gpio lines */
1146 if (i2c->pdata->cfg_gpio) {
1147 i2c->pdata->cfg_gpio(to_platform_device(i2c->dev));
1148 } else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) {
1149 return -EINVAL;
1150 }
1151
1152 /* initialise the i2c controller */
1154 clk_prepare_enable(i2c->clk);
1155 ret = s3c24xx_i2c_init(i2c);
1156 clk_disable_unprepare(i2c->clk);
1161 /* find the IRQ for this unit (note, this relies on the init call to
1162 * ensure no current IRQs pending
1163 */
1165 if (!(i2c->quirks & QUIRK_POLL)) {
1166 i2c->irq = ret = platform_get_irq(pdev, 0);
1171
1172 ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
1173 dev_name(&pdev->dev), i2c);
1179 }
1180
1181 ret = s3c24xx_i2c_register_cpufreq(i2c);
1192
1193 i2c->adap.nr = i2c->pdata->bus_num;
1194 i2c->adap.dev.of_node = pdev->dev.of_node;
1196 ret = i2c_add_numbered_adapter(&i2c->adap);
1202
1203 platform_set_drvdata(pdev, i2c);
1204
1205 pm_runtime_enable(&pdev->dev);
1206 pm_runtime_enable(&i2c->adap.dev);
1209 return 0;
1210 }
s3c24xx_i2c_probe()
--1074-1077-->準(zhǔn)備好指針與變量, 準(zhǔn)備從傳入的對(duì)象中提取數(shù)據(jù), 雖說(shuō)這是C89的語(yǔ)法要求, 但這種寫(xiě)法確實(shí)比較舒服, 遇到不認(rèn)識(shí)的變量就去函數(shù)開(kāi)頭找
--1079-->如果pdev->dev.of_node為空, 表示設(shè)備不是通過(guò)設(shè)備樹(shù)獲得的, 那么就調(diào)用dev_get_platdata獲取pdev->dev.oplatform_data中的數(shù)據(jù), 顯然, 在編寫(xiě)設(shè)備文件的時(shí)候這里藏的是一個(gè)s3c2410_platform_i2c對(duì)象, 所以我們用pdata取出來(lái)以備使用
--1087-->pdev->dev是device類(lèi)型, 以它為的detach為標(biāo)志分配一個(gè)我們自己的對(duì)象的空間并將分配的首地址返回給i2c,。 這里使用的是devm_kzalloc(), 函數(shù) devm_kzalloc()和kzalloc()一樣都是內(nèi)核內(nèi)存分配函數(shù),,但是devm_kzalloc()是跟設(shè)備(device)有關(guān)的,,當(dāng)設(shè)備(device)被detached或者驅(qū)動(dòng)(driver)卸載(unloaded)時(shí),,內(nèi)存會(huì)被自動(dòng)釋放。另外,,當(dāng)內(nèi)存不在使用時(shí),,可以使用函數(shù)devm_kfree()釋放。而kzalloc()則需要手動(dòng)釋放(使用kfree()),,但如果工程師檢查不仔細(xì),,則有可能造成內(nèi)存泄漏
--1100-1103-->如果在--1079--中獲得了相應(yīng)的s3c2410_platform_i2c對(duì)象地址,就將其拷貝到資源對(duì)象中的相應(yīng)的域存起來(lái),,否則自己去設(shè)備樹(shù)中找
--1106-1110-->使用賦值的方式直接對(duì)一部分資源對(duì)象的域進(jìn)行初始化
--1112-->初始化資源對(duì)象中的等待隊(duì)列頭wait_queue_head_t wait
--1116-->初始化資源對(duì)象中的device dev
--1117-->初始化資源對(duì)象中的struct clk
--1128-->獲取pdev中的地址resource, ioremap之后用于初始化資源對(duì)象中的regs域, 使用的是devm_ioremap_resource(), 同樣是基于device的資源自動(dòng)回收API
--1139-->將自定義資源對(duì)象指針藏到algo_data中, 和--1203--的作用一樣, 給xfer()接口函數(shù)用
--1140-->初始化資源對(duì)象中的i2c_adapter對(duì)象中的部分成員, 指定其父設(shè)備是控制器設(shè)備的device域
--1142-->初始化資源對(duì)象中的pctrl域, 使用的是devm_pinctrl_get_select_default()
--1147-->使用to_platform_device(其實(shí)就是container_of)通過(guò)i2c->dev找到包含它的platform_device對(duì)象, 回調(diào)cfg_gpio()函數(shù), 配置GPIO引腳
--1154-->初始化時(shí)鐘
--1166-->獲取中斷資源
--1171-->注冊(cè)中斷, devm_request_irq
--1193-1194-->初始化i2c->adap對(duì)象, 總線編號(hào)是來(lái)自于設(shè)備的
--1196-->將構(gòu)造的adapter對(duì)象注冊(cè)到內(nèi)核
--1203-->設(shè)置私有數(shù)據(jù), pdev->dev->p->driver_data = i2c; 由于i2c->dev==pdev->dev, 所以其實(shí)就是將資源對(duì)象的首地址賦值給藏到device->device_private->driver_data中, 因?yàn)樗械慕涌诙际鞘褂胮latform_device作為形參的, 這種方法可以方便的找到自定義資源對(duì)象, 所以才叫void * driver_data
--1205-->設(shè)置dev的電源管理
--1206-->設(shè)置adap的電源管理
s3c24xx_i2c_algorithm
probe中我們最關(guān)心的就是這個(gè)--1107--實(shí)現(xiàn)的接口了, i2c-core最終就是通過(guò)algo->xfer將設(shè)備驅(qū)動(dòng)的數(shù)據(jù)發(fā)送出去的, 是一個(gè)硬件相關(guān)的函數(shù)
787 static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
788 .master_xfer = s3c24xx_i2c_xfer,
789 .functionality = s3c24xx_i2c_func,
790 };
748 static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msgs, int num)
750 {
751 struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
758 for (retry = 0; retry < adap->retries; retry++) {
760 ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
770 udelay(100);
771 }
776 }
s3c24xx_i2c_xfer()
--760-->循環(huán)調(diào)用發(fā)送函數(shù), 函數(shù)的實(shí)現(xiàn)如下, 可以看到其中對(duì)寄存器的讀寫(xiě), 設(shè)備驅(qū)動(dòng)中的發(fā)送的請(qǐng)求, 就是通過(guò)這些readl(), writel()來(lái)實(shí)現(xiàn)的.
--770-->時(shí)序要求!
256 static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
257 struct i2c_msg *msg)
258 {
275 /* todo - check for whether ack wanted or not */
276 s3c24xx_i2c_enable_ack(i2c);
277
278 iiccon = readl(i2c->regs + S3C2410_IICCON);
279 writel(stat, i2c->regs + S3C2410_IICSTAT);
280
281 dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
282 writeb(addr, i2c->regs + S3C2410_IICDS);
287 ndelay(i2c->tx_setup);
288
290 writel(iiccon, i2c->regs + S3C2410_IICCON);
291
292 stat |= S3C2410_IICSTAT_START;
293 writel(stat, i2c->regs + S3C2410_IICSTAT);
294
295 if (i2c->quirks & QUIRK_POLL) {
296 while ((i2c->msg_num != 0) && is_ack(i2c)) {
297 i2c_s3c_irq_nextbyte(i2c, stat);
298 stat = readl(i2c->regs + S3C2410_IICSTAT);
299
300 if (stat & S3C2410_IICSTAT_ARBITR)
301 dev_err(i2c->dev, "deal with arbitration loss\n");
302 }
303 }
304 }