Qualcomm技术论坛
直播中

刘平

7年用户 240经验值
私信 关注
[经验]

基于qualcomm平台的输入驱动代码分析

前言:在qualcomm平台中,具有触摸屏、轨迹球和简单按键功能,这些功能是由安卓系统中的驱动程序实现的,并且需要用户空间的内容来协助实现。输入系统设备包括一下event设备。

/dev/input/event4:几个按键设备

/dev/input/event2:触摸屏设备

/dev/input/event5:轨迹球设备




一、触摸屏驱动

qualcomm平台的触摸屏驱动程序的实现文件是drivers/input/touchscreen/synaptics_i2c_rmi.c,此文件的核心是函数synaptics_ts_probe(),在该函数中需要进行触摸屏工作的初始化,对作为输入设备的触摸屏驱动在Linux平台下的设备名注册,同事初始化触摸事件出发时引起的中断操作。此函数的实现代码如下多事。


/**
* synaptics_rmi4_probe()
*
* Called by the kernel when an association with an I2C device of the
* same name is made (after doing i2c_add_driver).
*
* This function allocates and initializes the resources for the driver
* as an input driver, turns on the power to the sensor, queries the
* sensor for its supported Functions and characteristics, registers
* the driver to the input subsystem, sets up the interrupt, handles
* the registration of the early_suspend and late_resume functions,
* and creates a work queue for detection of other expansion Function
* modules.
*/
static int synaptics_rmi4_probe(struct i2c_client *client,
                const struct i2c_device_id *dev_id)
{
        int retval = 0;
        unsigned char ii;
        unsigned char attr_count;
        struct synaptics_rmi4_f1a_handle *f1a;
        struct synaptics_rmi4_fn *fhandler;
        struct synaptics_rmi4_fn *next_fhandler;
        struct synaptics_rmi4_data *rmi4_data;
        struct synaptics_rmi4_device_info *rmi;
        struct synaptics_rmi4_platform_data *platform_data =
                        client->dev.platform_data;
        struct dentry *temp;
        if (!i2c_check_functionality(client->adapter,
                        I2C_FUNC_SMBUS_BYTE_DATA)) {
                dev_err(&client->dev,
                                "%s: SMBus byte data not supportedn",
                                __func__);
                return -EIO;
        }
        if (client->dev.of_node) {
                platform_data = devm_kzalloc(&client->dev,
                        sizeof(*platform_data),
                        GFP_KERNEL);
                if (!platform_data) {
                        dev_err(&client->dev, "Failed to allocate memoryn");
                        return -ENOMEM;
                }
                retval = synaptics_rmi4_parse_dt(&client->dev, platform_data);
                if (retval)
                        return retval;
        } else {
                platform_data = client->dev.platform_data;
        }
        if (!platform_data) {
                dev_err(&client->dev,
                                "%s: No platform data foundn",
                                __func__);
                return -EINVAL;
        }
        rmi4_data = kzalloc(sizeof(*rmi4_data) * 2, GFP_KERNEL);
        if (!rmi4_data)
                return -ENOMEM;
        rmi = &(rmi4_data->rmi4_mod_info);
//创建设备        rmi4_data->input_dev = input_allocate_device();
        if (rmi4_data->input_dev == NULL) {
                retval = -ENOMEM;
                goto err_input_device;
        }
        rmi4_data->i2c_client = client;
        rmi4_data->current_page = MASK_8BIT;
        rmi4_data->board = platform_data;
        rmi4_data->touch_stopped = false;
        rmi4_data->sensor_sleep = false;
        rmi4_data->irq_enabled = false;
        rmi4_data->fw_updating = false;
        rmi4_data->suspended = false;
        rmi4_data->i2c_read = synaptics_rmi4_i2c_read;
        rmi4_data->i2c_write = synaptics_rmi4_i2c_write;
        rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
        rmi4_data->reset_device = synaptics_rmi4_reset_device;
        rmi4_data->flip_x = rmi4_data->board->x_flip;
        rmi4_data->flip_y = rmi4_data->board->y_flip;
        if (rmi4_data->board->fw_image_name)
                snprintf(rmi4_data->fw_image_name, NAME_BUFFER_SIZE, "%s",
                        rmi4_data->board->fw_image_name);
        rmi4_data->input_dev->name = DRIVER_NAME;
        rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
        rmi4_data->input_dev->id.bustype = BUS_I2C;
        rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
        rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
        rmi4_data->input_dev->dev.parent = &client->dev;
        input_set_drvdata(rmi4_data->input_dev, rmi4_data);
        set_bit(EV_SYN, rmi4_data->input_dev->evbit);
        set_bit(EV_KEY, rmi4_data->input_dev->evbit);
        set_bit(EV_ABS, rmi4_data->input_dev->evbit);
        set_bit(BTN_TOUCH, rmi4_data->input_dev->keybit);
        set_bit(BTN_TOOL_FINGER, rmi4_data->input_dev->keybit);
#ifdef INPUT_PROP_DIRECT
        set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit);
#endif
        retval = synaptics_rmi4_regulator_configure(rmi4_data, true);
        if (retval < 0) {
                dev_err(&client->dev, "Failed to configure regulatorsn");
                goto err_reg_configure;
        }
        retval = synaptics_rmi4_power_on(rmi4_data, true);
        if (retval < 0) {
                dev_err(&client->dev, "Failed to power onn");
                goto err_power_device;
        }
        retval = synaptics_rmi4_pinctrl_init(rmi4_data);
        if (!retval && rmi4_data->ts_pinctrl) {
                /*
                * Pinctrl handle is optional. If pinctrl handle is found
                * let pins to be configured in active state. If not found
                * continue further without error
                */
                if (pinctrl_select_state(rmi4_data->ts_pinctrl,
                                        rmi4_data->pinctrl_state_active))
                        dev_err(&rmi4_data->i2c_client->dev,
                                "Can not select %s pinstaten",
                                PINCTRL_STATE_ACTIVE);
        }
        retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
        if (retval < 0) {
                dev_err(&client->dev, "Failed to configure gpiosn");
                goto err_gpio_config;
        }
        init_waitqueue_head(&rmi4_data->wait);
        mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
        INIT_LIST_HEAD(&rmi->support_fn_list);
        mutex_init(&rmi->support_fn_list_mutex);
        retval = synaptics_rmi4_query_device(rmi4_data);
        if (retval < 0) {
                dev_err(&client->dev,
                                "%s: Failed to query devicen",
                                __func__);
                goto err_free_gpios;
        }
        if (platform_data->detect_device) {
                retval = synaptics_rmi4_parse_dt_children(&client->dev,
                                platform_data, rmi4_data);
                if (retval < 0)
                        dev_err(&client->dev,
                                "%s: Failed to parse device tree propertyn",
                                        __func__);
        }
        if (rmi4_data->board->disp_maxx)
                rmi4_data->disp_maxx = rmi4_data->board->disp_maxx;
        else
                rmi4_data->disp_maxx = rmi4_data->sensor_max_x;
        if (rmi4_data->board->disp_maxy)
                rmi4_data->disp_maxy = rmi4_data->board->disp_maxy;
        else
                rmi4_data->disp_maxy = rmi4_data->sensor_max_y;
        if (rmi4_data->board->disp_minx)
                rmi4_data->disp_minx = rmi4_data->board->disp_minx;
        else
                rmi4_data->disp_minx = 0;
        if (rmi4_data->board->disp_miny)
                rmi4_data->disp_miny = rmi4_data->board->disp_miny;
        else
                rmi4_data->disp_miny = 0;
        input_set_abs_params(rmi4_data->input_dev,
                        ABS_MT_POSITION_X, rmi4_data->disp_minx,
                        rmi4_data->disp_maxx, 0, 0);
        input_set_abs_params(rmi4_data->input_dev,
                        ABS_MT_POSITION_Y, rmi4_data->disp_miny,
                        rmi4_data->disp_maxy, 0, 0);
        input_set_abs_params(rmi4_data->input_dev,
                        ABS_PRESSURE, 0, 255, 0, 0);
#ifdef REPORT_2D_W
        input_set_abs_params(rmi4_data->input_dev,
                        ABS_MT_TOUCH_MAJOR, 0,
                        rmi4_data->max_touch_width, 0, 0);
        input_set_abs_params(rmi4_data->input_dev,
                        ABS_MT_TOUCH_MINOR, 0,
                        rmi4_data->max_touch_width, 0, 0);
#endif
#ifdef TYPE_B_PROTOCOL
        input_mt_init_slots(rmi4_data->input_dev,
                        rmi4_data->num_of_fingers, 0);
#endif
        i2c_set_clientdata(client, rmi4_data);
        f1a = NULL;
        mutex_lock(&rmi->support_fn_list_mutex);
        if (!list_empty(&rmi->support_fn_list)) {
                list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
                        if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
                                f1a = fhandler->data;
                }
        }
        mutex_unlock(&rmi->support_fn_list_mutex);
        if (f1a) {
                for (ii = 0; ii < f1a->valid_button_count; ii++) {
                        set_bit(f1a->button_map[ii],
                                        rmi4_data->input_dev->keybit);
                        input_set_capability(rmi4_data->input_dev,
                                        EV_KEY, f1a->button_map[ii]);
                }
        }
        retval = input_register_device(rmi4_data->input_dev);
        if (retval) {
                dev_err(&client->dev,
                                "%s: Failed to register input devicen",
                                __func__);
                goto err_register_input;
        }
        configure_sleep(rmi4_data);
        if (!exp_fn_inited) {
                mutex_init(&exp_fn_list_mutex);
                INIT_LIST_HEAD(&exp_fn_list);
                exp_fn_inited = 1;
        }
        rmi4_data->det_workqueue =
                        create_singlethread_workqueue("rmi_det_workqueue");
        INIT_DELAYED_WORK(&rmi4_data->det_work,
                        synaptics_rmi4_detection_work);
        queue_delayed_work(rmi4_data->det_workqueue,
                        &rmi4_data->det_work,
                        msecs_to_jiffies(EXP_FN_DET_INTERVAL));
        rmi4_data->irq = gpio_to_irq(platform_data->irq_gpio);
        retval = request_threaded_irq(rmi4_data->irq, NULL,
                synaptics_rmi4_irq, platform_data->irq_flags,
                DRIVER_NAME, rmi4_data);
        rmi4_data->irq_enabled = true;
        if (retval < 0) {
                dev_err(&client->dev,
                                "%s: Failed to create irq threadn",
                                __func__);
                goto err_enable_irq;
        }
        rmi4_data->dir = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL);
        if (rmi4_data->dir == NULL || IS_ERR(rmi4_data->dir)) {
                dev_err(&client->dev,
                        "%s: Failed to create debugfs directory, rc = %ldn",
                        __func__, PTR_ERR(rmi4_data->dir));
                retval = PTR_ERR(rmi4_data->dir);
                goto err_create_debugfs_dir;
        }
        temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, rmi4_data->dir,
                                        rmi4_data, &debug_suspend_fops);
        if (temp == NULL || IS_ERR(temp)) {
                dev_err(&client->dev,
                        "%s: Failed to create suspend debugfs file, rc = %ldn",
                        __func__, PTR_ERR(temp));
                retval = PTR_ERR(temp);
                goto err_create_debugfs_file;
        }
        for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
                retval = sysfs_create_file(&client->dev.kobj,
                                &attrs[attr_count].attr);
                if (retval < 0) {
                        dev_err(&client->dev,
                                        "%s: Failed to create sysfs attributesn",
                                        __func__);
                        goto err_sysfs;
                }
        }
        synaptics_rmi4_sensor_wake(rmi4_data);
        retval = synaptics_rmi4_irq_enable(rmi4_data, true);
        if (retval < 0) {
                dev_err(&client->dev,
                        "%s: Failed to enable attention interruptn",
                        __func__);
                goto err_sysfs;
        }
        synaptics_secure_touch_init(rmi4_data);
        synaptics_secure_touch_stop(rmi4_data, 1);
        retval = synaptics_rmi4_check_configuration(rmi4_data);
        if (retval < 0) {
                dev_err(&client->dev, "Failed to check configurationn");
                return retval;
        }
        return retval;
err_sysfs:
        for (attr_count--; attr_count >= 0; attr_count--) {
                sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
                                &attrs[attr_count].attr);
        }
err_create_debugfs_file:
        debugfs_remove_recursive(rmi4_data->dir);
err_create_debugfs_dir:
        free_irq(rmi4_data->irq, rmi4_data);
err_enable_irq:
        cancel_delayed_work_sync(&rmi4_data->det_work);
        flush_workqueue(rmi4_data->det_workqueue);
        destroy_workqueue(rmi4_data->det_workqueue);
        input_unregister_device(rmi4_data->input_dev);
err_register_input:
        mutex_lock(&rmi->support_fn_list_mutex);
        if (!list_empty(&rmi->support_fn_list)) {
                list_for_each_entry_safe(fhandler, next_fhandler,
                                        &rmi->support_fn_list, link) {
                        if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
                                synaptics_rmi4_f1a_kfree(fhandler);
                        else {
                                kfree(fhandler->data);
                                kfree(fhandler->extra);
                        }
                        kfree(fhandler);
                }
        }
        mutex_unlock(&rmi->support_fn_list_mutex);
err_free_gpios:
        if (gpio_is_valid(rmi4_data->board->reset_gpio))
                gpio_free(rmi4_data->board->reset_gpio);
        if (gpio_is_valid(rmi4_data->board->irq_gpio))
                gpio_free(rmi4_data->board->irq_gpio);
err_gpio_config:
        if (rmi4_data->ts_pinctrl) {
                if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
                        devm_pinctrl_put(rmi4_data->ts_pinctrl);
                        rmi4_data->ts_pinctrl = NULL;
                } else {
                        retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
                                        rmi4_data->pinctrl_state_release);
                        if (retval)
                                pr_err("failed to select release pinctrl staten");
                }
        }
        synaptics_rmi4_power_on(rmi4_data, false);
err_power_device:
        synaptics_rmi4_regulator_configure(rmi4_data, false);
err_reg_configure:
        input_free_device(rmi4_data->input_dev);
        rmi4_data->input_dev = NULL;
err_input_device:
        kfree(rmi4_data);
        return retval;
}

在上述代码中,通过i2c_smbus_read_byte_data()函数对其寄存器信息进行读取即可完成其时间信息的获取,也可以通过i2c_transfer完成对其 寄存器的信息的批量读取。

更多回帖

发帖
×
20
完善资料,
赚取积分