基于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 supported\n",
				__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 memory\n");
			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 found\n",
				__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 regulators\n");
		goto err_reg_configure;
	}

	retval = synaptics_rmi4_power_on(rmi4_data, true);
	if (retval < 0) {
		dev_err(&client->dev, "Failed to power on\n");
		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 pinstate\n",
				PINCTRL_STATE_ACTIVE);
	}

	retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
	if (retval < 0) {
		dev_err(&client->dev, "Failed to configure gpios\n");
		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 device\n",
				__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 property\n",
					__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 device\n",
				__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 thread\n",
				__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 = %ld\n",
			__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 = %ld\n",
			__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 attributes\n",
					__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 interrupt\n",
			__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 configuration\n");
		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 state\n");
		}
	}
	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完成对其 寄存器的信息的批量读取。




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值