标签 aosp 下的文章

转自: https://blog.csdn.net/ctx_ubuntu/article/details/80053694

TP驱动芯片厂商主要有:Goodix(汇顶),FocalTech(敦泰科技),cypress(赛普拉斯),synaptics(新思)。 TP驱动的调试主要是将接口调通。 从TP厂商获取驱动和配置资料。

4.2.1. 集成或者使用系统自带的TP驱动

查找 kernel/drivers/input/touchscreen,看是否有对应的驱动。如果没有,可以从高通的网站下载驱动或者找厂商要驱动

由于TP通过I2C与处理器通信,所以只要调通I2C,TP调试工作基本就完成了。 通过kernel log 查看类似这些probe函数:goodix_ts_probe(), cyttsp5_probe(), synaptics_rmi4_probe() 的执行情况,看看问题出在哪。 I2C主要看地址是否正确。还要用示波器量一下I2C线上的波形。I2C是不用时拉高,传输数据时才会有拉低的信号。如果log里说I2C忙,那就有可能I2C没有拉高。

TP触摸屏,应该是驱动开发中比较简单并且适合新手入手的模块。不过虽然简单,但涉及到的内容还是比较多的,其中linux相关主要的机制:

  1. input 机制
  2. 中断、定时器
  3. I2C

- 阅读剩余部分 -

转自: https://blog.csdn.net/xubin341719/article/details/7833383

关键词:android 电容屏 tp 工作队列 中断 坐点计算 电容屏主要参数 平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0

平台:S5PV310(samsung exynos 4210)

作者:xubin341719(欢迎转载,请注明作者)

android 电容屏(一):电容屏基本原理篇

android 电容屏(二):驱动调试之基本概念篇

android 电容屏(三):驱动调试之驱动程序分析篇

以goodix的gt8105为例

一、总体架构

- 阅读剩余部分 -

转自: https://blog.csdn.net/xubin341719/article/details/7833277

关键词:android 电容屏 tp 工作队列 中断 多点触摸协议 平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0 平台:S5PV310(samsung exynos 4210)

参考网站:http://edsionte.com/techblog/archives/1582 这部分参考别人的多一点

android 电容屏(一):电容屏基本原理篇

android 电容屏(二):驱动调试之基本概念篇

android 电容屏(三):驱动调试之驱动程序分析篇

    电容屏驱动调试先了解Linux电容屏驱动中几个常用的概念:
          中断下半部-工作队列;
          input机制;
          Linux与Android 多点触摸协议。

一、中断下半部-工作队列

1、中断

先看一下宋宝华先生的《linux设备驱动开发详解》里面对中断的描述吧。这本书个人感觉 写的比较好,从开始学驱动到现在,还能从中得到不少知识。

设备的中断会打断内核中进程的正常调度和运行,系统对更高吞吐率的追求势必要求中断服务程序尽可能地短小精悍。但是,这个良好的愿望往往与现实并不吻合。在大多数真实的系统中,当中断到来时,要完成的工作往往并不会是短小的,它可能要进行较大量的耗时处理。如下图描述了Linux内核的中断处理机制。为了在中断执行时间尽可能短和中断处理需完成大量工作之间找到一个平衡点,Linux将中断处理程序分解为两个半部:顶半部(top half)和底半部(bottom half)。顶半部完成尽可能少的比较紧急的功能,它往往只是简单地读取寄存器中的中断状态并清除中断标志后就进行“登记中断”的工作。“登记中断”意味着将底半部处理程序挂到该设备的底半部执行队列中去。这样,顶半部执行的速度就会很快,可以服务更多的中断请求。现在,中断处理工作的重心就落在了底半部的头上,它来完成中断事件的绝大多数任务。底半部几乎做了中断处理程序所有的事情,而且可以被新的中断打断,这也是底半部和顶半部的最大不同,因为顶半部往往被设计成不可中断。底半部则相对来说并不是非常紧急的,而且相对比较耗时,不在硬件中断服务程序中执行。尽管顶半部、底半部的结合能够改善系统的响应能力,但是,僵化地认为Linux设备驱动中的中断处理一定要分两个半部则是不对的。如果中断要处理的工作本身很少,则完全可以直接在顶半部全部完成。

其实上面这一段大致说明一个问题,那就是:中断要尽可能耗时比较短,尽快恢复系统正常调试,所以把中断触发、中断执行分开,也就是所说的“上半部分(中断触发)、底半部(中断执行)”,其实就是我们后面说的中断上下文。下半部分一般有tasklet、工作队列实现,触摸屏中中断实现以工作队列形式实现的,所以我们今天重点讲工作队列。

- 阅读剩余部分 -

转自: https://blog.csdn.net/xubin341719/article/details/7820492

关键词:android 电容屏 tp ITO 平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0 平台:S5PV310(samsung exynos 4210)

android 电容屏(一):电容屏基本原理篇

android 电容屏(二):驱动调试之基本概念篇

android 电容屏(三):驱动调试之驱动程序分析篇

一、电容屏工作原理

触摸屏的工作原理概括来说就是上报坐标值,X轴、Y轴的值。前面我们分析了电阻触摸屏,它是通过ADC来检测计算X、Y轴坐标值,下面我们分析一下电容触摸屏的工作原理,看它是如何去检测计算X、Y坐标的值。

与电阻式触摸屏不同,电容式触摸屏不依靠手指按力创造、改变电压值来检测坐标的。电容屏通过任何持有电荷的物体包括人体皮肤工作。(人体所带的电荷)电容式触摸屏是由诸如合金或是銦錫氧化物(ITO)这样的材料构成,电荷存储在一根根比头发还要细的微型静电网中。当手指点击屏幕,会从接触点吸收小量电流,造成角落电极的压降,利用感应人体微弱电流的方式来达到触控的目的。(这是为什么当你带上手套触摸屏幕时,没有反应的原因),下图可以清晰的说明电容屏的工作原理。

- 阅读剩余部分 -

转自: https://blog.csdn.net/daoshuti/article/details/72983620

AndroidTP驱动之(三)input

0. 前情提要

上文中我们已经完成对设备树的解析工作,获取了tp的硬件信息。 我们知道Linux内核上报输入事件是通过input子系统,TP作为输入设备自然要通过input子系统来上报。 现在的kernel都支持多点触控了,多点触控的协议有两种协议A和协议B,协议A不需要硬件支持,协议B需要硬件支持。 这里我们不讨论协议A/B,有兴趣的同学自己Google。 下面我们就初始化input子系统。

1. probe函数

在probe函数的开始我们先定义了两个结构体指针。为后面的input初始化做准备。 这两个以结构体,一个是input_dev,另一个是自定义的结构体mytp_data。 input_dev自不别说,我们的TP通过这个结构体来上报数据。 mytp_data是我们TP驱动中自定义的结构体,方便我们来编写程序。 具体定义如下:

struct mytp_data
{
    struct i2c_client *client;
    struct input_dev *input_dev;
    struct mytp_platform_data *pdata;
};

如上所示,现在mytp_data结构体的成员很少只有三个,后期随着功能的增加,我们还会添加。 这三个结构体成员都是很重要的,i2c_client用来和TP通信,input_dev用来上报TP数据,mytp_platform_data存放了硬件平台的数据。 probe函数中input初始化代码具体如下:

struct input_dev *input_dev;
struct mytp_data *data;

data = devm_kzalloc(&client->dev, sizeof(struct mytp_data), GFP_KERNEL);
if (!data)
{
    PRINT_INFO("[MEMORY]Failed to allocate memory");
    return -ENOMEM;
}

input_dev = input_allocate_device();
if (!input_dev)
{
    PRINT_INFO("[INPUT]Failed to allocate input device");
    return -ENOMEM;
}

data->input_dev = input_dev;
data->client = client;
data->pdata = pdata;

mytp_input_dev_init(client, data, input_dev, pdata);

代码的逻辑很清晰,完成结构体变量的初始化后调用mytp_input_dev_init()函数。 这个函数就是用来初始化input的。具体见下一小节。

2. mytp_input_dev_init函数

函数一开始显示初始化input_dev结构体, 然后将驱动私有的mytp_data结构体指针变量data,通过input_set_drvdata和i2c_set_clientdata函数放入input_dev和client中。 之后通过__set_bit函数设置上报的数据类型,和键值。 通过宏MYTP_MT_PROTOCOL_B_EN选择多点上报的方式。 通过input_register_device注册input设备。

static int mytp_input_dev_init( struct i2c_client *client, struct mytp_data *data,  struct input_dev *input_dev, struct mytp_platform_data *pdata)
{
    int  err, len;

    /* Init and register Input device */
    input_dev->name = MYTP_DRIVER_NAME;
    input_dev->id.bustype = BUS_I2C;
    input_dev->dev.parent = &client->dev;

    input_set_drvdata(input_dev, data);
    i2c_set_clientdata(client, data);

    __set_bit(EV_KEY, input_dev->evbit);
    if (data->pdata->have_key)
    {
        PRINT_INFO("set key capabilities");
        for (len = 0; len < data->pdata->key_number; len++)
        {
            input_set_capability(input_dev, EV_KEY, data->pdata->keys[len]);
        }
    }
    __set_bit(EV_ABS, input_dev->evbit);
    __set_bit(BTN_TOUCH, input_dev->keybit);
    __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);

#if MYTP_MT_PROTOCOL_B_EN
    input_mt_init_slots(input_dev, pdata->max_touch_number, INPUT_MT_DIRECT);
#else
    input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 0x0f, 0, 0);
#endif
    input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min, pdata->x_max, 0, 0);
    input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min, pdata->y_max, 0, 0);
    input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0);

    err = input_register_device(input_dev);
    if (err)
    {
        PRINT_INFO("Input device registration failed");
        goto free_inputdev;
    }

    return 0;

free_inputdev:
    input_free_device(input_dev);
    return err;
}

3. remove函数

input_unregister_device(data->input_dev);

注销input设备。 另注:

前文中i2c设备在exit函数中注销。  
而设备树,只是从中获取硬件信息,不能注销。  
内存申请时,使用的是devm\_kzalloc函数,其会在驱动模块注销主动释放内存,所以不需要手动free。  

用到的头文件和宏

头文件

#include <linux/input.h>
#include <linux/input/mt.h>

#define MYTP_MT_PROTOCOL_B_EN   1

MYTP_DRIVER_NAME宏,前文已经定义过。 End

至此TP的input初始化完成。

转自: https://blog.csdn.net/daoshuti/article/details/72972350

AndroidTP驱动之(二)设备树解析

0. 前情提要

上文中我们已经初步搭好了TP驱动的框架。当然我们还缺了重要的部分input子系统,这个不急,我们下一篇文章再叙。 本文我们来完成TP driver中对设备树的解析。

1. probe函数

我们知道驱动匹配有四种方式:设备树匹配、设备名称匹配、设备ID匹配、ACPI方式匹配。 这里我们只用设备树匹配,这也是Android驱动中最常用的匹配方式。 我们知道当驱动和设备树匹配的时候,probe函数就会被执行。 这时一般首先进行设备树的解析,从设备树中获取设备的硬件信息。

    struct mytp_platform_data *pdata;
    int err;

    if (client->dev.of_node)
    {
        pdata = devm_kzalloc(&client->dev,
                sizeof(struct mytp_platform_data),
                GFP_KERNEL);
        if (!pdata)
        {
            PRINT_INFO("[MEMORY]Failed to allocate memory");
            return -ENOMEM;
        }
        err = mytp_parse_dt(&client->dev, pdata);
        if (err)
        {
            PRINT_INFO("[DTS]DT parsing failed");
        }
    }
    else
    {
        return -1;
    }

    if (!pdata)
    {
        PRINT_INFO("Invalid pdata");
        return -EINVAL;
    }

从代码中我们很清晰的看到,我们先是定义了一个结构体指针pdata。这是用来存放平台数据。 接着,我们为这结构体申请了内存,并做异常处理。 之后调用mytp_parse_dt函数对设备树进行解析。也做了相应的异常处理。

1.1 mytp_platform_data结构体

struct mytp_platform_data
{
    u32 irq_gpio;
    u32 irq_gpio_flags;
    u32 reset_gpio;
    u32 reset_gpio_flags;
    bool have_key;
    u32 key_number;
    u32 keys[4];
    u32 key_y_coord;
    u32 key_x_coords[4];
    u32 x_max;
    u32 y_max;
    u32 x_min;
    u32 y_min;
    u32 max_touch_number;
};

头四个结构体成员变量,分别是两个gpio所使用的,一个是irq中断,一个是TP的reset复位引脚。 之后的bool变量,是TP按键的标志,表示是否支持TP按键。 紧接着的四个key_打头的变量是提供给TP按键处理函数用的。 x_max、x_min、y_max、y_min限定了tp的触摸范围。 最后的一个变量限定了tp支持的最大多点触控数目。

1.2 mytp_parse_dt函数

这个函数就是用来解析设备树的。 其中的mytp_get_dt_coords函数是自己实现的,用来解析设备树中的数组的。具体实现见1.3小节。

static int mytp_parse_dt(struct device *dev, struct mytp_platform_data *pdata)
{
    int rc;
    struct device_node *np = dev->of_node;
    u32 temp_val;

    rc = mytp_get_dt_coords(dev, "focaltech,display-coords", pdata);
    if (rc)
        PRINT_INFO("Unable to get display-coords");

    /* key */
    pdata->have_key = of_property_read_bool(np, "focaltech,have-key");
    if (pdata->have_key)
    {
        rc = of_property_read_u32(np, "focaltech,key-number", &pdata->key_number);
        if (rc)
        {
            PRINT_INFO("Key number undefined!");
        }
        rc = of_property_read_u32_array(np, "focaltech,keys",
                pdata->keys, pdata->key_number);
        if (rc)
        {
            PRINT_INFO("Keys undefined!");
        }
        rc = of_property_read_u32(np, "focaltech,key-y-coord", &pdata->key_y_coord);
        if (rc)
        {
            PRINT_INFO("Key Y Coord undefined!");
        }
        rc = of_property_read_u32_array(np, "focaltech,key-x-coords",
                pdata->key_x_coords, pdata->key_number);
        if (rc)
        {
            PRINT_INFO("Key X Coords undefined!");
        }
        PRINT_INFO("%d: (%d, %d, %d), [%d, %d, %d][%d]",
                pdata->key_number, pdata->keys[0], pdata->keys[1], pdata->keys[2],
                pdata->key_x_coords[0], pdata->key_x_coords[1], pdata->key_x_coords[2],
                pdata->key_y_coord);
    }

    /* reset, irq gpio info */
    pdata->reset_gpio = of_get_named_gpio_flags(np, "focaltech,reset-gpio", 0, &pdata->reset_gpio_flags);
    if (pdata->reset_gpio < 0)
    {
        PRINT_INFO("Unable to get reset_gpio");
    }

    pdata->irq_gpio = of_get_named_gpio_flags(np, "focaltech,irq-gpio", 0, &pdata->irq_gpio_flags);
    if (pdata->irq_gpio < 0)
    {
        PRINT_INFO("Unable to get irq_gpio");
    }

    rc = of_property_read_u32(np, "focaltech,max-touch-number", &temp_val);
    if (!rc)
    {
        pdata->max_touch_number = temp_val;
        PRINT_INFO("max_touch_number=%d", pdata->max_touch_number);
    }
    else
    {
        PRINT_INFO("Unable to get max-touch-number");
        pdata->max_touch_number = MYTP_MAX_POINTS;
    }

    return 0;
}

1.3 mytp_get_dt_coords函数

static int mytp_get_dt_coords(struct device *dev, char *name,
        struct mytp_platform_data *pdata)
{
    u32 coords[MYTP_COORDS_ARR_SIZE];
    struct property *prop;
    struct device_node *np = dev->of_node;
    int coords_size, rc;

    prop = of_find_property(np, name, NULL);
    if (!prop)
        return -EINVAL;
    if (!prop->value)
        return -ENODATA;

    coords_size = prop->length / sizeof(u32);
    if (coords_size != MYTP_COORDS_ARR_SIZE)
    {
        PRINT_INFO("invalid %s", name);
        return -EINVAL;
    }

    rc = of_property_read_u32_array(np, name, coords, coords_size);
    if (rc && (rc != -EINVAL))
    {
        PRINT_INFO("Unable to read %s", name);
        return rc;
    }

    if (!strcmp(name, "focaltech,display-coords"))
    {
        pdata->x_min = coords[0];
        pdata->y_min = coords[1];
        pdata->x_max = coords[2];
        pdata->y_max = coords[3];
    }
    else
    {
        PRINT_INFO("unsupported property %s", name);
        return -EINVAL;
    }

    return 0;
}

End

至此我们完成了对设备树的解析。

转自: https://blog.csdn.net/daoshuti/article/details/72972112

AndroidTP驱动之(一)I2C

0. 前言

Android TP 驱动系列主要用来记录自己关于TP的心得体会。 为了完整的梳理TP driver相关的知识,也为了跟好回顾Linux driver的编写流程。 我将参照已有的驱动代码(focaltech的驱动代码)从零开始,一步一步写出一个TP驱动。 驱动模块的名字就叫做mytp。

1. 模块三要素

1.0 header & define

#include <linux/kernel.h>
#include <linux/module.h>

#define PRINT_INFO(fmt, args...) printk(KERN_ERR "[MYTP][%s]"fmt"\n", __func__, ##args)

1.1 module_init

static __init int mytp_init(void)
{
    PRINT_INFO("mytp init start!");
    PRINT_INFO("mytp init end!");
    return 0;
}
module_init(mytp_init);

1.2 module_exit

static __exit void mytp_exit(void)
{
    PRINT_INFO("mytp exit start!");
    PRINT_INFO("mytp exit end!");
}
module_exit(mytp_exit);

1.3 module info

MODULE_AUTHOR("wanghan");
MODULE_DESCRIPTION("TP Driver (ic:ft5435)");
MODULE_LICENSE("GPL");

2. I2C子系统

我们知道TP的IC基本都是使用I2C和CPU通信。所以,我们先通过i2c子系统创建一个字符设备驱动。 注意这里用到了头文件

#include <linux/i2c.h>

2.0 定义相关的i2c结构体变量

#define MYTP_DRIVER_NAME    "mytp_ft5435"

static const struct i2c_device_id mytp_id[] =
{
    {MYTP_DRIVER_NAME, 0},
    {},
};

static const struct of_device_id mytp_match_table[] =
{
    { .compatible = "focaltech,fts", },
    { },
};

static struct i2c_driver mytp_driver =
{
    .probe = mytp_probe,
    .remove = mytp_remove,
    .driver = {
        .name = MYTP_DRIVER_NAME,
        .owner = THIS_MODULE,
        .of_match_table = mytp_match_table,
    },
    .id_table = mytp_id,
};

2.1 实例化probe和remove函数

static int mytp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    PRINT_INFO("mytp prebo start!");

    PRINT_INFO("mytp prebo end!");
    return 0;
}

static int mytp_remove(struct i2c_client *client)
{
    PRINT_INFO("mytp remove start!");

    PRINT_INFO("mytp remove end!");
    return 0;
}

2.2 创建i2c设备

在mytp_init函数中加入

int ret;
ret = i2c_add_driver(&mytp_driver);
if ( ret != 0 )
{
    PRINT_INFO("TP driver init failed!");
}

2.3 注销i2c设备

i2c_del_driver(&mytp_driver);

End

至此,我们的驱动框架已经搭建好了。

转自: https://blog.csdn.net/xiaocaohuyang/article/details/114120766?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

文章目录

一、TP的硬件接口
二、代码路径
三、TP代码分析
    1、硬件参数设置
    2、TP设备驱动
    3、TP模组驱动

一、TP的硬件接口

引脚 名称及作用
VDD TP供电
RESET 复位引脚
EINT 中断引脚
SCL、SDA I2C接口

​ TP的工作方式比较简单: +上电后通过RESET脚控制TP芯片复位;

  • 通过I2C接口给TP设置参数或读取TP数据;
  • TP有触摸操作时通过EINT脚通知主控;

二、代码路径

描述 路径 文件
系统设置 device\top\top6737t_36_a_m0 kernel-3.18\arch\arm\configs ProjectConfig.mk user版本和userdebug版本对应:top6737t_36_a_m0_defconfig debug版本对应:top6737t_36_a_m0_debug_defconfig
接口设置 kernel-3.18\arch\arm\boot\dts top6737t_36_a_m0.dts cust_i2c.dtsi
Kernel代码 kernel-3.18\drivers\input\touchscreen\mediatek mtk_tpd.c

- 阅读剩余部分 -

转自: https://blog.csdn.net/MrDongShiYi/article/details/100709633?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

TP 相关引脚DTS中的定义 我们这个项目TP复位引脚是GPIO158,中断引脚是GPIO1,由下图原理图知道我们的TP挂载在I2c0上,3.3v的供电电压是有PMIC 2.8V供电电压通过i2c电平转换过来的,所以供电电压需要配置pmic 2.8v

- 阅读剩余部分 -

转自: https://blog.csdn.net/memory01/article/details/91895740

做Android bsp开发经常会遇到改了内核config需要快速验证的情况,如果用最简单的编译bootimage方式会很费时

肯定存在更简单的方法 以arm64位的芯片bsp包为例

cd KERNEL_PATH
$ export ARCH=arm64
/*如果你是目标defconfig是 "arch/arm64/msm8150_defconfig" */
$ make msm8150_defconfig
成功之后,这样就会出现 #configutation written to .config 提示

接下来就可以检查KERNEL_PATH 下的 .config 文件是否符合你的改动

当然如果要通过menuconfig方式来配置内核也行,执行上述命令之后再make menuconfig 即可