Uwe Kleine-König (The Capable Hub)Input: Use named initializers for arrays of i2c_device_data47ceab25 months agoHistory
862 lines · 21.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2012-2013 MundoReader S.L. * Author: Heiko Stuebner <heiko@sntech.de> * * based in parts on Nook zforce driver * * Copyright (C) 2010 Barnes & Noble, Inc. * Author: Pieter Truter<ptruter@intrinsyc.com> */ #include <linux/delay.h>#include <linux/device.h>#include <linux/gpio/consumer.h>#include <linux/i2c.h>#include <linux/input.h>#include <linux/input/mt.h>#include <linux/input/touchscreen.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/of.h>#include <linux/property.h>#include <linux/regulator/consumer.h>#include <linux/slab.h>#include <linux/unaligned.h> #define WAIT_TIMEOUT		msecs_to_jiffies(1000) #define FRAME_START		0xee#define FRAME_MAXSIZE		257 /* Offsets of the different parts of the payload the controller sends */#define PAYLOAD_HEADER		0#define PAYLOAD_LENGTH		1#define PAYLOAD_BODY		2 /* Response offsets */#define RESPONSE_ID		0#define RESPONSE_DATA		1 /* Commands */#define COMMAND_DEACTIVATE	0x00#define COMMAND_INITIALIZE	0x01#define COMMAND_RESOLUTION	0x02#define COMMAND_SETCONFIG	0x03#define COMMAND_DATAREQUEST	0x04#define COMMAND_SCANFREQ	0x08#define COMMAND_STATUS		0X1e /* * Responses the controller sends as a result of * command requests */#define RESPONSE_DEACTIVATE	0x00#define RESPONSE_INITIALIZE	0x01#define RESPONSE_RESOLUTION	0x02#define RESPONSE_SETCONFIG	0x03#define RESPONSE_SCANFREQ	0x08#define RESPONSE_STATUS		0X1e /* * Notifications are sent by the touch controller without * being requested by the driver and include for example * touch indications */#define NOTIFICATION_TOUCH		0x04#define NOTIFICATION_BOOTCOMPLETE	0x07#define NOTIFICATION_OVERRUN		0x25#define NOTIFICATION_PROXIMITY		0x26#define NOTIFICATION_INVALID_COMMAND	0xfe #define ZFORCE_REPORT_POINTS		2#define ZFORCE_MAX_AREA			0xff #define STATE_DOWN			0#define STATE_MOVE			1#define STATE_UP			2 #define SETCONFIG_DUALTOUCH		(1 << 0) struct zforce_point {	int coord_x;	int coord_y;	int state;	int id;	int area_major;	int area_minor;	int orientation;	int pressure;	int prblty;}; /* * @client		the i2c_client * @input		the input device * @suspending		in the process of going to suspend (don't emit wakeup *			events for commands executed to suspend the device) * @suspended		device suspended * @command_done	completion to wait for the command result * @command_waiting	the id of the command that is currently waiting *			for a result * @command_result	returned result of the command */struct zforce_ts {	struct i2c_client	*client;	struct input_dev	*input;	struct touchscreen_properties prop;	char			phys[32]; 	struct gpio_desc	*gpio_int;	struct gpio_desc	*gpio_rst; 	bool			suspending;	bool			suspended;	bool			boot_complete; 	/* Firmware version information */	u16			version_major;	u16			version_minor;	u16			version_build;	u16			version_rev; 	struct completion	command_done;	int			command_waiting;	int			command_result;}; static int zforce_command(struct zforce_ts *ts, u8 cmd){	struct i2c_client *client = ts->client;	char buf[3];	int ret; 	dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); 	buf[0] = FRAME_START;	buf[1] = 1; /* data size, command only */	buf[2] = cmd; 	ret = i2c_master_send(client, &buf[0], ARRAY_SIZE(buf));	if (ret < 0) {		dev_err(&client->dev, "i2c send data request error: %d\n", ret);		return ret;	} 	return 0;} static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len){	struct i2c_client *client = ts->client;	int ret; 	dev_dbg(&client->dev, "sending %d bytes for command 0x%x\n",		buf[1], buf[2]); 	ts->command_waiting = buf[2]; 	ret = i2c_master_send(client, buf, len);	if (ret < 0) {		dev_err(&client->dev, "i2c send data request error: %d\n", ret);		return ret;	} 	dev_dbg(&client->dev, "waiting for result for command 0x%x\n", buf[2]); 	if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0)		return -ETIME; 	ret = ts->command_result;	return 0;} static int zforce_command_wait(struct zforce_ts *ts, u8 cmd){	struct i2c_client *client = ts->client;	char buf[3];	int error; 	dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd); 	buf[0] = FRAME_START;	buf[1] = 1; /* data size, command only */	buf[2] = cmd; 	error = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));	if (error) {		dev_err(&client->dev, "i2c send data request error: %d\n",			error);		return error;	} 	return 0;} static int zforce_resolution(struct zforce_ts *ts, u16 x, u16 y){	struct i2c_client *client = ts->client;	char buf[7] = { FRAME_START, 5, COMMAND_RESOLUTION,			(x & 0xff), ((x >> 8) & 0xff),			(y & 0xff), ((y >> 8) & 0xff) }; 	dev_dbg(&client->dev, "set resolution to (%d,%d)\n", x, y); 	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));} static int zforce_scan_frequency(struct zforce_ts *ts, u16 idle, u16 finger,				 u16 stylus){	struct i2c_client *client = ts->client;	char buf[9] = { FRAME_START, 7, COMMAND_SCANFREQ,			(idle & 0xff), ((idle >> 8) & 0xff),			(finger & 0xff), ((finger >> 8) & 0xff),			(stylus & 0xff), ((stylus >> 8) & 0xff) }; 	dev_dbg(&client->dev,		"set scan frequency to (idle: %d, finger: %d, stylus: %d)\n",		idle, finger, stylus); 	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));} static int zforce_setconfig(struct zforce_ts *ts, char b1){	struct i2c_client *client = ts->client;	char buf[7] = { FRAME_START, 5, COMMAND_SETCONFIG,			b1, 0, 0, 0 }; 	dev_dbg(&client->dev, "set config to (%d)\n", b1); 	return zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));} static int zforce_start(struct zforce_ts *ts){	struct i2c_client *client = ts->client;	int error; 	dev_dbg(&client->dev, "starting device\n"); 	error = zforce_command_wait(ts, COMMAND_INITIALIZE);	if (error) {		dev_err(&client->dev, "Unable to initialize, %d\n", error);		return error;	} 	error = zforce_resolution(ts, ts->prop.max_x, ts->prop.max_y);	if (error) {		dev_err(&client->dev, "Unable to set resolution, %d\n", error);		goto err_deactivate;	} 	error = zforce_scan_frequency(ts, 10, 50, 50);	if (error) {		dev_err(&client->dev, "Unable to set scan frequency, %d\n",			error);		goto err_deactivate;	} 	error = zforce_setconfig(ts, SETCONFIG_DUALTOUCH);	if (error) {		dev_err(&client->dev, "Unable to set config\n");		goto err_deactivate;	} 	/* start sending touch events */	error = zforce_command(ts, COMMAND_DATAREQUEST);	if (error) {		dev_err(&client->dev, "Unable to request data\n");		goto err_deactivate;	} 	/*	 * Per NN, initial cal. take max. of 200msec.	 * Allow time to complete this calibration	 */	msleep(200); 	return 0; err_deactivate:	zforce_command_wait(ts, COMMAND_DEACTIVATE);	return error;} static int zforce_stop(struct zforce_ts *ts){	struct i2c_client *client = ts->client;	int error; 	dev_dbg(&client->dev, "stopping device\n"); 	/* Deactivates touch sensing and puts the device into sleep. */	error = zforce_command_wait(ts, COMMAND_DEACTIVATE);	if (error) {		dev_err(&client->dev, "could not deactivate device, %d\n",			error);		return error;	} 	return 0;} static int zforce_touch_event(struct zforce_ts *ts, u8 *payload){	struct i2c_client *client = ts->client;	struct zforce_point point;	int count, i, num = 0;	u8 *p; 	count = payload[0];	if (count > ZFORCE_REPORT_POINTS) {		dev_warn(&client->dev,			 "too many coordinates %d, expected max %d\n",			 count, ZFORCE_REPORT_POINTS);		count = ZFORCE_REPORT_POINTS;	} 	for (i = 0; i < count; i++) {		p = &payload[i * 9 + 1]; 		point.coord_x = get_unaligned_le16(&p[0]);		point.coord_y = get_unaligned_le16(&p[2]); 		if (point.coord_x > ts->prop.max_x ||		    point.coord_y > ts->prop.max_y) {			dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",				point.coord_x, point.coord_y);			point.coord_x = point.coord_y = 0;		} 		point.state = p[4] & 0x0f;		point.id = (p[4] & 0xf0) >> 4; 		/* determine touch major, minor and orientation */		point.area_major = max(p[5], p[6]);		point.area_minor = min(p[5], p[6]);		point.orientation = p[5] > p[6]; 		point.pressure = p[7];		point.prblty = p[8]; 		dev_dbg(&client->dev,			"point %d/%d: state %d, id %d, pressure %d, prblty %d, x %d, y %d, amajor %d, aminor %d, ori %d\n",			i, count, point.state, point.id,			point.pressure, point.prblty,			point.coord_x, point.coord_y,			point.area_major, point.area_minor,			point.orientation); 		/* the zforce id starts with "1", so needs to be decreased */		input_mt_slot(ts->input, point.id - 1); 		if (input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,					       point.state != STATE_UP)) {			touchscreen_report_pos(ts->input, &ts->prop,					       point.coord_x, point.coord_y,					       true);			input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,					 point.area_major);			input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,					 point.area_minor);			input_report_abs(ts->input, ABS_MT_ORIENTATION,					 point.orientation);			num++;		}	} 	input_mt_sync_frame(ts->input); 	input_mt_report_finger_count(ts->input, num); 	input_sync(ts->input); 	return 0;} static int zforce_read_packet(struct zforce_ts *ts, u8 *buf){	struct i2c_client *client = ts->client;	int ret; 	/* read 2 byte message header */	ret = i2c_master_recv(client, buf, 2);	if (ret < 0) {		dev_err(&client->dev, "error reading header: %d\n", ret);		return ret;	} 	if (buf[PAYLOAD_HEADER] != FRAME_START) {		dev_err(&client->dev, "invalid frame start: %d\n", buf[0]);		return -EIO;	} 	if (buf[PAYLOAD_LENGTH] == 0) {		dev_err(&client->dev, "invalid payload length: %d\n",			buf[PAYLOAD_LENGTH]);		return -EIO;	} 	/* read the message */	ret = i2c_master_recv(client, &buf[PAYLOAD_BODY], buf[PAYLOAD_LENGTH]);	if (ret < 0) {		dev_err(&client->dev, "error reading payload: %d\n", ret);		return ret;	} 	dev_dbg(&client->dev, "read %d bytes for response command 0x%x\n",		buf[PAYLOAD_LENGTH], buf[PAYLOAD_BODY]); 	return 0;} static void zforce_complete(struct zforce_ts *ts, int cmd, int result){	struct i2c_client *client = ts->client; 	if (ts->command_waiting == cmd) {		dev_dbg(&client->dev, "completing command 0x%x\n", cmd);		ts->command_result = result;		complete(&ts->command_done);	} else {		dev_dbg(&client->dev, "command %d not for us\n", cmd);	}} static irqreturn_t zforce_irq(int irq, void *dev_id){	struct zforce_ts *ts = dev_id;	struct i2c_client *client = ts->client; 	if (ts->suspended && device_may_wakeup(&client->dev))		pm_wakeup_event(&client->dev, 500); 	return IRQ_WAKE_THREAD;} static irqreturn_t zforce_irq_thread(int irq, void *dev_id){	struct zforce_ts *ts = dev_id;	struct i2c_client *client = ts->client;	int error;	u8 payload_buffer[FRAME_MAXSIZE];	u8 *payload;	bool suspending; 	/*	 * When still suspended, return.	 * Due to the level-interrupt we will get re-triggered later.	 */	if (ts->suspended) {		msleep(20);		return IRQ_HANDLED;	} 	dev_dbg(&client->dev, "handling interrupt\n"); 	/* Don't emit wakeup events from commands run by zforce_suspend */	suspending = READ_ONCE(ts->suspending);	if (!suspending && device_may_wakeup(&client->dev))		pm_stay_awake(&client->dev); 	/*	 * Run at least once and exit the loop if	 * - the optional interrupt GPIO isn't specified	 *   (there is only one packet read per ISR invocation, then)	 * or	 * - the GPIO isn't active any more	 *   (packet read until the level GPIO indicates that there is	 *    no IRQ any more)	 */	do {		error = zforce_read_packet(ts, payload_buffer);		if (error) {			dev_err(&client->dev,				"could not read packet, ret: %d\n", error);			break;		} 		payload =  &payload_buffer[PAYLOAD_BODY]; 		switch (payload[RESPONSE_ID]) {		case NOTIFICATION_TOUCH:			/*			 * Always report touch-events received while			 * suspending, when being a wakeup source			 */			if (suspending && device_may_wakeup(&client->dev))				pm_wakeup_event(&client->dev, 500);			zforce_touch_event(ts, &payload[RESPONSE_DATA]);			break; 		case NOTIFICATION_BOOTCOMPLETE:			ts->boot_complete = payload[RESPONSE_DATA];			zforce_complete(ts, payload[RESPONSE_ID], 0);			break; 		case RESPONSE_INITIALIZE:		case RESPONSE_DEACTIVATE:

Lines 1–500 of 862.