在网上对于gsl680驱动的剖析文章很多,本人自己也负责过tp驱动的移植,但是对于内部tp驱动的构造从未了解过,觉得有必要对tp驱动进行一个梳理。以下仅为本人观点,如有不对欢迎各路大佬指点,目的主要是分析tp驱动的整个流程

首先,分析一个驱动,特别是像我这种工作经验不是很饱满的人,我自己习惯的方式是:先对整个驱动相关文件进行一个梳理,入口、出口以及他内部主要核心操作都在哪里。因此,我后面会分为三篇文章进行我个人的梳理。分别是以下:

1.入口函数gsl_g15d_init的初始化操作

2.gsl680驱动的前期工作(如供电、复位、中断脚初始化等)

3.gsl680驱动的input子系统相关步骤

那么本篇就先从头开始分析gsl680驱动的入口及初始化操作

module_init(gsl_g15d_init);

这里是作为一个驱动的入口,没啥好说的

return i2c_add_driver(&gsl_ts_driver);

这个是将gsl_ts_driver这个驱动结构体添加至i2c总线上,i2c_add_driver这个就是一个i2c总线添加驱动的api,会用即可

static struct i2c_driver gsl_ts_driver = {
        .driver = {
                .name = GSL_TS_NAME,
        .owner    = THIS_MODULE,
                .of_match_table = gsl_match_table,
        },
        .probe = gsl_ts_probe,
        .remove = gsl_ts_remove,
        .id_table       = gsl_ts_id,
};

而这个gsl_ts_driver的结构体内就会定义各个内容,其中.driver以及.id_table可以理解为就是为了与设备树内的tp设备进行一个配对操作,这个也不是重点。我们主要分析的重点应该放在.probe属性上,看看gsl_ts_probe做了什么

static int gsl_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
        int err = 0;
        struct input_dev *input_dev;

        struct gsl_ts_platform_data *pdata;
        dev_info("%s\n",__func__);
        printk("%s: ======probe begin ========\n",__func__);
        printk("i2c addr: 0x%02x from dtsi\n",client->addr);

        if (client->dev.of_node) {
                pdata = devm_kzalloc(&client->dev,
                        sizeof(struct gsl_ts_platform_data), GFP_KERNEL);
                ...
                err = gsl_parse_dt(&client->dev, pdata);
                ...
        else
                pdata = client->dev.platform_data;
        }
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                err = -ENODEV;
        dev_err(&client->dev, "I2c doesn't work\n");
                goto exit_check_functionality_failed;
        }
}

在probe函数的上半段,我们可以看到他实际上的功能就集中在两部分:gsl_parse_dt以及i2c_check_functionality。

首先看看gsl_parse_dt,从名称上可以看到似乎是与设备数比对相关。

static int gsl_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
{
         struct device_node *np;
    if (!dev)
        return -ENODEV;

       np = dev->of_node;
        pdata->name = "gsl";
        pdata->irq_gpio = of_get_named_gpio(np, "silead,irq-gpio", 0);
        pdata->reset_gpio = of_get_named_gpio(np, "silead,rst-gpio", 0);
    if (!gpio_is_valid(pdata->irq_gpio) || !gpio_is_valid(pdata->reset_gpio)) {
        printk("Invalid GPIO, irq-gpio:%d, rst-gpio:%d",
            pdata->irq_gpio, pdata->reset_gpio);
        return -EINVAL;
    }
    return 0;
}

这里确实是跟我们上面猜测的搭边,与设备数有关。of_get_name_gpio是linux自带的api,用于搜索设备树节点内的属性名称,这里是通过搜索"silead,irq-gpio"以及"silead,rst-gpio"这个属性确定中断gpio以及复位gpio(实际上根据大佬跟我说的,tp驱动最关键的就是中断以及复位),获取成功后会进行判断这两个gpio是否真的被获取到了。

那么至此,我们的设备树里面已经有3个属性可以根据硬件原理图填写了,分别是 compatible(初始化过程中的配对name)、silead,irq-gpio(中断gpio)以及silead,reset-gpio(复位gpio)

gsl{
            compatible = "silead,gsl-tp";
            silead,rst-gpio = <&tlmm 87 0x0>;
            silead,irq-gpio = <&tlmm 88 0x2002>;
        };

下面就是另外一个函数:i2c_check_functionality,实际上就是通过调用kernel内的api,判断当前的这个驱动是否匹配i2c总线设备模型罢了。

if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                err = -ENODEV;
        dev_err(&client->dev, "I2c doesn't work\n");
                goto exit_check_functionality_failed;
        }

所以,第一章讲的内容其实特别简单,一些很基础的知识。只不过我个人认为自己有必要梳理这部分的知识罢了,基础不牢谈何上层。