I2C驱动片段

static void ft5x0x_ts_release(void)
{
	struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);

#ifdef FT5X0X_MULTI_TOUCH
	input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0);
	input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 0);
	input_report_key(data->input_dev, BTN_TOUCH, 0);
#else
	input_report_abs(data->input_dev, ABS_PRESSURE, 0);
	input_report_key(data->input_dev, BTN_TOUCH, 0);
#endif
	input_sync(data->input_dev);
}

static int ft5x0x_read_data(void)
{
	struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
	struct ts_event *event = &data->event;
	u32 buf[32] = {0};
	int ret = -1;
	
#ifdef FT5X0X_MULTI_TOUCH
	ret = ft5x0x_i2c_rxdata(buf, 31);
#else
	ret = ft5x0x_i2c_rxdata(buf, 7);
#endif
	if (ret < 0) {
		printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
	}

	memset(event, 0, sizeof(struct ts_event));
	event->touch_point = buf[2] & 0x07;

	if (event->touch_point == 0) {
		ft5x0x_ts_release();
		return 1;
	}

#ifdef FT5X0X_MULTI_TOUCH
	switch (event->touch_point) {
		case 5:
			event->x5 = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c];
			event->y5 = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e];
		case 4:
			event->x4 = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];
			event->y4 = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];
		case 3:
			event->x3 = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];
			event->y3 = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];
		case 2:
			event->x2 = (s16)(buf[9] & 0x0F)<<8 | (s16)buf[10];
			event->y2 = (s16)(buf[11] & 0x0F)<<8 | (s16)buf[12];
		case 1:
			event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
			event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
			break;
		default:
			return -1;
	}
#else
	if (event->touch_point == 1) { 
		event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
		event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
	}
#endif

	event->pressure = 200;

	return 0;
}

static void ft5x0x_reprot_value(void)
{
	struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
	struct ts_event *event = &data->event;

#ifdef FT5X0X_MULTI_TOUCH
	switch(event->touch_point) {
		case 5:
			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
			input_report_abs(data->input_dev, ABS_MT_POSITION_X,  event->x5);
			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,  event->y5);
			input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure);
			input_mt_sync(data->input_dev);
		case 4:
			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
			input_report_abs(data->input_dev, ABS_MT_POSITION_X,  event->x4);
			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,  event->y4);
			input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure);
			input_mt_sync(data->input_dev);
		case 3:
			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
			input_report_abs(data->input_dev, ABS_MT_POSITION_X,  event->x3);
			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,  event->y3);
			input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure);
			input_mt_sync(data->input_dev);
		case 2:
			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
			input_report_abs(data->input_dev, ABS_MT_POSITION_X,  event->x2);
			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,  event->y2);
			input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure);
			input_mt_sync(data->input_dev);
		case 1:
			input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
			input_report_abs(data->input_dev, ABS_MT_POSITION_X,  event->x1);
			input_report_abs(data->input_dev, ABS_MT_POSITION_Y,  event->y1);
			input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, event->pressure);
			input_mt_sync(data->input_dev);
			break;
		default:
			break;
	}
#else
	if (event->touch_point == 1) {
		input_report_abs(data->input_dev, ABS_X, event->x1);
		input_report_abs(data->input_dev, ABS_Y, event->y1);
		input_report_abs(data->input_dev, ABS_PRESSURE, event->pressure);
	}
	input_report_key(data->input_dev, BTN_TOUCH, 1);
#endif

	input_sync(data->input_dev);

#ifdef FT5X0X_MULTI_TOUCH
	printk("   >>> Point[0] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x1, event->y1, event->pressure, event->pressure);
	printk("   >>> Point[1] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x2, event->y2, event->pressure, event->pressure);
	printk("   >>> Point[2] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x3, event->y3, event->pressure, event->pressure);
	printk("   >>> Point[3] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x4, event->y4, event->pressure, event->pressure);
	printk("   >>> Point[4] point:(%d, %d), ABS_MT_TOUCH_MAJOR: %d, ABS_MT_WIDTH_MAJOR: %d >>>\n", event->x5, event->y5, event->pressure, event->pressure);
	printk("\n");
#else
	printk("   >>> one point:(%d, %d), ABS_PRESSURE: %d, BTN_TOUCH: %d >>>\n", event->x1, event->y1, event->pressure, 1);
#endif
}

static void ft5x0x_ts_pen_irq_work(struct work_struct *work)
{
	int ret = -1;

	ret = ft5x0x_read_data();
	if (ret == 0)
		ft5x0x_report_value();
}

static interrupt_r ft5x0x_ts_interrupt(int irq, void *dev_id)
{
	struct ft5x0x_ts_data *ft5x0x_ts = dev_id;

	if (!work_pending(&ft5x0x_ts->pen_irq_work))
		queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_irq_work);

	return IRQ_HANDLED;
}

#ifdef CONFIG_HAS_EARLYSUSPEND
static void ft5x0x_ts_suspend(struct early_suspend *handler)
{
	struct ft5x0x_ts_data *ft5x0x_ts;

	ts = container_of(handler, struct ft5x0x_ts_data, early_suspend);
	disable_irq(this_client->irq);
	cancel_workqueue(ft5x0x_ts->pen_irq_work);
	flush_workqueue(ft5x0x_ts->ts_workqueue);

	ft5x0x_write_reg(FT5X0X_REG_PMODE, PMODE_MONITOR);

	printk("[FST] %s\n", __func__);
}

static void ft5x0x_ts_resume(struct early_suspend *handler)
{
	ventana_touchscreen_reset();

	enable_irq(this_client->irq);
	
	ft5x0x_write_reg(FT5X0X_REG_PMODE, PMODE_ACTIVE);
	
	printk("[FST] %s\n", __func__);
}
#endif

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

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		err = -ENODEV;
		goto exit_i2c_check_functionality;
	}
	
	ft5x0x_ts = kzalloc(sizeof(ft5x0x_ts_data), GPL_KERNEL);
	if (!ft5x0x_ts) {
		err = -ENOMEM;
		goto exit_alloc_data;
	}

	this_client = client;

	i2c_set_clientdata(client, ft5x0x_ts);

	INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_ts_pen_irq_work);

	ft5x0x_ts->ts_workqueue = create_siglethread_workqueue(dev_name(&client->dev));

	if (!ft5x0x_ts->ts_workqueue) {
		err = -ESRCH;
		goto exit_create_siglethread;
	}

	err = request_irq(client->irq, ft5x0x_ts_interrupt, IRQF_TRIGGER_FALLING, "ft5x0x-irq", ft5x0x_ts);
	if (err < 0) {
		dev_err(&client->dev, "ft5x0x_ts_probe: request irq failed\n");
		goto exit_irq_request;
	}

	disable_irq(this_client-irq);

	input_dev = input_allocate_device();
	if (!input_dev) {
		err = -ENOMEM;
		dev_err(&client-dev, "ft5x0x_ts_probe: failed alloc input device\n");
	}

	ft5x0x_ts->input_dev = input_dev;

	input_dev->name = FT5X0X_NAME;

	set_bit(EV_ABS, input_dev->evbit);
	set_bit(EV_KEY, input_dev->evbit);
	set_bit(BTN_TOUCH, input_dev->keybit);

#ifdef FT5X0X_MULTI_TOUCH
	set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit);
	set_bit(ABS_MT_POSITION_X, input_dev->absbit);
	set_bit(ABS_MT_POSITION_Y, input_dev->absbit);
	set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit);

	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
	input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
#else
	set_bit(ABS_X, input_dev->absbit);
	set_bit(ABS_Y, input_dev->absbit);
	set_bit(ABS_PRESSURE, input_dev->absbit);
	set_bit(BTN_TOUCH, input_dev->keybit);

	input_set_abs_params(input_dev, ABS_X, 0, SCREEN_MAX_X, 0, 0);
	input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAX_Y, 0, 0);
	input_set_abs_params(input_dev, ABS_PRESSURE, 0, PRESS_MAX, 0 , 0);

	err = input_register_device(input_dev);
	if (err) {
		dev_err(&client->dev, "ft5x0x_ts_probe: failed to register input device: %s\n", 
				dev_name(&client->dev));
		goto exit_input_register_device;
	}
#endif

#ifdef CONFIG_HAS_EARLYSUSPEND
	ft5x0x_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
	ft5x0x_ts->early_suspend.suspend = ft5x0x_ts_suspend;
	ft5x0x_ts->early_suspend.resume = ft5x0x_ts_resume;
	register_early_suspend(ft5x0x_ts->early_suspend);
#endif
	msleep(50);

	//Get some register information
	uc_reg_value = ft5x0x_read_fw_ver();
	printk("[FST] Firmware version = 0x%sx\n", uc_reg_value);

	//Auto calibration
	err = ft5x0x_write_reg(CALIBRATION_REG, 0x00);
	if (err)
		printk("[FST] Auto calibration failed.\n");
	else
		printk("[FST] Auto calibration successfully.\n");
	//Config the run mode of TPM, reg - 0xa7 : auto calibration - 0x04
	ft5x0x_write_reg(FT5X0X_REG_STATE, 0x00);
	printk("[FST] Auto calibration during running.\n");

	enable_irq(this_client->irq);

	return 0;

exit_input_register_device:
	input_free_device(input_dev);

exit_alloc_data:
	free_irq(client->irq, ft5x0x_ts);

exit_irq_request:

exit_create_siglethread:
	i2c_set_clientdata(client, NULL);

exit_alloc_data:

exit_i2c_check_functionality:
	return err;

}

static int __devexit ft5x0x_ts_remove(struct i2c_client *client)
{
	struct ft5x0x_ts_data *ft5x0x_ts = i2c_get_clientdata(client);

#ifdef CONFIG_HAS_EARLYSUSPEND
	unregister_early_suspend(&ft5x0x_ts->early_suspend);
#endif
	free_irq(client->irq, ft5x0x_ts);
	input_unregister_device(ft5x0x_ts->input_dev);
	kfree(ft5x0x_ts);
	cancel_work_sync(&ft5x0x_ts->pen_event_work);
	destroy_workqueue(ft5x0x_ts->ts_workqueue);
	i2c_set_cleintdata(client, NULL);

	return 0;
} 

static const struct i2c_device_id  ft5x0x_ts_id[] = {
	{FT5X0X_NAME, 0}
};
MODULE_DEVICE_TABLE(i2c, ft5x0x_id);

static struct i2c_driver ft5x0x_ts_driver = {
	.probe 	  = ft5x0x_ts_probe,
	.remove   = __devexit_p(ft5x0x_ts_remove),
	.id_table = ft5x0x_ts_id,
	.driver   = {
		.name  = FT5X0X_TS,
		.owner = THIS_MODULE,
	},
};

static int __init ft5x0x_ts_init(void)
{
	int ret;

	ret = i2c_add_driver(&ft5x0x_ts_driver);

	return ret;
}

static void __exit ft5x0x_ts_exit(void)
{
	i2c_delete_driver(&ft5x0x_ts_driver);
}

module_init(ft5x0x_ts_init);
module_exit(ft5x0x_ts_exit);

你可能感兴趣的:(c,struct,report,Module,table,input)