probe主要负责"申请资源+初始化+提供接口", 通过对probe的分析, 就可以对整个驱动的构建有一个
提纲挈领的理解
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_io
remap_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-->准备好指针与变量, 准备从传入的对象中提取数据, 虽说这是C89的语法要求, 但这种写法确实比较舒服, 遇到不认识的变量就去函数开头找
--1079-->如果pdev->dev.of_node为空, 表示设备不是通过设备树获得的, 那么就调用dev_get_platdata获取pdev->dev.oplatform_data中的数据, 显然, 在编写设备文件的时候这里藏的是一个s3c2410_platform_i2c对象, 所以我们用pdata取出来以备使用
--1087-->pdev->dev是device类型, 以它为的detach为标志分配一个我们自己的对象的空间并将分配的首地址返回给i2c。 这里使用的是devm_kzalloc(), 函数 devm_kzalloc()和kzalloc()一样都是内核内存分配函数,但是devm_kzalloc()是跟设备(device)有关的,当设备(device)被detached或者驱动(driver)卸载(unloaded)时,内存会被自动释放。另外,当内存不在使用时,可以使用函数devm_kfree()释放。而kzalloc()则需要手动释放(使用kfree()),但如果工程师检查不仔细,则有可能造成内存泄漏
--1100-1103-->如果在--1079--中获得了相应的s3c2410_platform_i2c对象地址,就将其拷贝到资源对象中的相应的域存起来,否则自己去设备树中找
--1106-1110-->使用赋值的方式直接对一部分资源对象的域进行初始化
--1112-->初始化资源对象中的等待队列头wait_queue_head_t wait
--1116-->初始化资源对象中的device dev
--1117-->初始化资源对象中的struct clk
--1128-->获取pdev中的地址resource, ioremap之后用于初始化资源对象中的regs域, 使用的是devm_ioremap_resource(), 同样是基于device的资源自动回收API
--1139-->将自定义资源对象指针藏到algo_data中, 和--1203--的作用一样, 给xfer()接口函数用
--1140-->初始化资源对象中的i2c_adapter对象中的部分成员, 指定其父设备是控制器设备的device域
--1142-->初始化资源对象中的pctrl域, 使用的是devm_pinctrl_get_select_default()
--1147-->使用to_platform_device(其实就是container_of)通过i2c->dev找到包含它的platform_device对象, 回调cfg_gpio()函数, 配置GPIO引脚
--1154-->初始化时钟
--1166-->获取中断资源
--1171-->注册中断, devm_request_irq
--1193-1194-->初始化i2c->adap对象, 总线编号是来自于设备的
--1196-->将构造的adapter对象注册到内核
--1203-->设置私有数据, pdev->dev->p->driver_data = i2c; 由于i2c->dev==pdev->dev, 所以其实就是将资源对象的首地址赋值给藏到device->device_private->driver_data中, 因为所有的接口都是使用platform_device作为形参的, 这种方法可以方便的找到自定义资源对象, 所以才叫void * driver_data
--1205-->设置dev的电源管理
--1206-->设置adap的电源管理
s3c24xx_i2c_algorithm