Uwe Kleine-König (The Capable Hub)Input: Use named initializers for arrays of i2c_device_data47ceab26 months agoHistory
1499 lines · 36.9 KB · C
RawDownload
/* * Cypress APA trackpad with I2C interface * * Author: Dudley Du <dudl@cypress.com> * Further cleanup and restructuring by: *   Daniel Kurtz <djkurtz@chromium.org> *   Benson Leung <bleung@chromium.org> * * Copyright (C) 2011-2015 Cypress Semiconductor, Inc. * Copyright (C) 2011-2012 Google, Inc. * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file COPYING in the main directory of this archive for * more details. */ #include <linux/delay.h>#include <linux/i2c.h>#include <linux/input.h>#include <linux/input/mt.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/mutex.h>#include <linux/regulator/consumer.h>#include <linux/slab.h>#include <linux/uaccess.h>#include <linux/pm_runtime.h>#include <linux/acpi.h>#include <linux/of.h>#include "cyapa.h"  #define CYAPA_ADAPTER_FUNC_NONE   0#define CYAPA_ADAPTER_FUNC_I2C    1#define CYAPA_ADAPTER_FUNC_SMBUS  2#define CYAPA_ADAPTER_FUNC_BOTH   3 #define CYAPA_FW_NAME		"cyapa.bin" const char product_id[] = "CYTRA"; static int cyapa_reinitialize(struct cyapa *cyapa); bool cyapa_is_pip_bl_mode(struct cyapa *cyapa){	if (cyapa->gen == CYAPA_GEN6 && cyapa->state == CYAPA_STATE_GEN6_BL)		return true; 	if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL)		return true; 	return false;} bool cyapa_is_pip_app_mode(struct cyapa *cyapa){	if (cyapa->gen == CYAPA_GEN6 && cyapa->state == CYAPA_STATE_GEN6_APP)		return true; 	if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP)		return true; 	return false;} static bool cyapa_is_bootloader_mode(struct cyapa *cyapa){	if (cyapa_is_pip_bl_mode(cyapa))		return true; 	if (cyapa->gen == CYAPA_GEN3 &&		cyapa->state >= CYAPA_STATE_BL_BUSY &&		cyapa->state <= CYAPA_STATE_BL_ACTIVE)		return true; 	return false;} static inline bool cyapa_is_operational_mode(struct cyapa *cyapa){	if (cyapa_is_pip_app_mode(cyapa))		return true; 	if (cyapa->gen == CYAPA_GEN3 && cyapa->state == CYAPA_STATE_OP)		return true; 	return false;} /* Returns 0 on success, else negative errno on failure. */static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len,					u8 *values){	struct i2c_client *client = cyapa->client;	struct i2c_msg msgs[] = {		{			.addr = client->addr,			.flags = 0,			.len = 1,			.buf = &reg,		},		{			.addr = client->addr,			.flags = I2C_M_RD,			.len = len,			.buf = values,		},	};	int ret; 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 	if (ret != ARRAY_SIZE(msgs))		return ret < 0 ? ret : -EIO; 	return 0;} /** * cyapa_i2c_write - Execute i2c block data write operation * @cyapa: Handle to this driver * @reg: Offset of the data to written in the register map * @len: number of bytes to write * @values: Data to be written * * Return negative errno code on error; return zero when success. */static int cyapa_i2c_write(struct cyapa *cyapa, u8 reg,					 size_t len, const void *values){	struct i2c_client *client = cyapa->client;	char buf[32];	int ret; 	if (len > sizeof(buf) - 1)		return -ENOMEM; 	buf[0] = reg;	memcpy(&buf[1], values, len); 	ret = i2c_master_send(client, buf, len + 1);	if (ret != len + 1)		return ret < 0 ? ret : -EIO; 	return 0;} static u8 cyapa_check_adapter_functionality(struct i2c_client *client){	u8 ret = CYAPA_ADAPTER_FUNC_NONE; 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))		ret |= CYAPA_ADAPTER_FUNC_I2C;	if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |				     I2C_FUNC_SMBUS_BLOCK_DATA |				     I2C_FUNC_SMBUS_I2C_BLOCK))		ret |= CYAPA_ADAPTER_FUNC_SMBUS;	return ret;} /* * Query device for its current operating state. */static int cyapa_get_state(struct cyapa *cyapa){	u8 status[BL_STATUS_SIZE];	u8 cmd[32];	/* The i2c address of gen4 and gen5 trackpad device must be even. */	bool even_addr = ((cyapa->client->addr & 0x0001) == 0);	bool smbus = false;	int retries = 2;	int error; 	cyapa->state = CYAPA_STATE_NO_DEVICE; 	/*	 * Get trackpad status by reading 3 registers starting from 0.	 * If the device is in the bootloader, this will be BL_HEAD.	 * If the device is in operation mode, this will be the DATA regs.	 *	 */	error = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE,				       status); 	/*	 * On smbus systems in OP mode, the i2c_reg_read will fail with	 * -ETIMEDOUT.  In this case, try again using the smbus equivalent	 * command.  This should return a BL_HEAD indicating CYAPA_STATE_OP.	 */	if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO)) {		if (!even_addr)			error = cyapa_read_block(cyapa,					CYAPA_CMD_BL_STATUS, status);		smbus = true;	} 	if (error != BL_STATUS_SIZE)		goto error; 	/*	 * Detect trackpad protocol based on characteristic registers and bits.	 */	do {		cyapa->status[REG_OP_STATUS] = status[REG_OP_STATUS];		cyapa->status[REG_BL_STATUS] = status[REG_BL_STATUS];		cyapa->status[REG_BL_ERROR] = status[REG_BL_ERROR]; 		if (cyapa->gen == CYAPA_GEN_UNKNOWN ||				cyapa->gen == CYAPA_GEN3) {			error = cyapa_gen3_ops.state_parse(cyapa,					status, BL_STATUS_SIZE);			if (!error)				goto out_detected;		}		if (cyapa->gen == CYAPA_GEN_UNKNOWN ||				cyapa->gen == CYAPA_GEN6 ||				cyapa->gen == CYAPA_GEN5) {			error = cyapa_pip_state_parse(cyapa,					status, BL_STATUS_SIZE);			if (!error)				goto out_detected;		}		/* For old Gen5 trackpads detecting. */		if ((cyapa->gen == CYAPA_GEN_UNKNOWN ||				cyapa->gen == CYAPA_GEN5) &&			!smbus && even_addr) {			error = cyapa_gen5_ops.state_parse(cyapa,					status, BL_STATUS_SIZE);			if (!error)				goto out_detected;		} 		/*		 * Write 0x00 0x00 to trackpad device to force update its		 * status, then redo the detection again.		 */		if (!smbus) {			cmd[0] = 0x00;			cmd[1] = 0x00;			error = cyapa_i2c_write(cyapa, 0, 2, cmd);			if (error)				goto error; 			msleep(50); 			error = cyapa_i2c_read(cyapa, BL_HEAD_OFFSET,					BL_STATUS_SIZE, status);			if (error)				goto error;		}	} while (--retries > 0 && !smbus); 	goto error; out_detected:	if (cyapa->state <= CYAPA_STATE_BL_BUSY)		return -EAGAIN;	return 0; error:	return (error < 0) ? error : -EAGAIN;} /* * Poll device for its status in a loop, waiting up to timeout for a response. * * When the device switches state, it usually takes ~300 ms. * However, when running a new firmware image, the device must calibrate its * sensors, which can take as long as 2 seconds. * * Note: The timeout has granularity of the polling rate, which is 100 ms. * * Returns: *   0 when the device eventually responds with a valid non-busy state. *   -ETIMEDOUT if device never responds (too many -EAGAIN) *   -EAGAIN    if bootload is busy, or unknown state. *   < 0        other errors */int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout){	int error;	int tries = timeout / 100; 	do {		error = cyapa_get_state(cyapa);		if (!error && cyapa->state > CYAPA_STATE_BL_BUSY)			return 0; 		msleep(100);	} while (tries--); 	return (error == -EAGAIN || error == -ETIMEDOUT) ? -ETIMEDOUT : error;} /* * Check if device is operational. * * An operational device is responding, has exited bootloader, and has * firmware supported by this driver. * * Returns: *   -ENODEV no device *   -EBUSY  no device or in bootloader *   -EIO    failure while reading from device *   -ETIMEDOUT timeout failure for bus idle or bus no response *   -EAGAIN device is still in bootloader *           if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware *   -EINVAL device is in operational mode, but not supported by this driver *   0       device is supported */static int cyapa_check_is_operational(struct cyapa *cyapa){	int error; 	error = cyapa_poll_state(cyapa, 4000);	if (error)		return error; 	switch (cyapa->gen) {	case CYAPA_GEN6:		cyapa->ops = &cyapa_gen6_ops;		break;	case CYAPA_GEN5:		cyapa->ops = &cyapa_gen5_ops;		break;	case CYAPA_GEN3:		cyapa->ops = &cyapa_gen3_ops;		break;	default:		return -ENODEV;	} 	error = cyapa->ops->operational_check(cyapa);	if (!error && cyapa_is_operational_mode(cyapa))		cyapa->operational = true;	else		cyapa->operational = false; 	return error;}  /* * Returns 0 on device detected, negative errno on no device detected. * And when the device is detected and operational, it will be reset to * full power active mode automatically. */static int cyapa_detect(struct cyapa *cyapa){	struct device *dev = &cyapa->client->dev;	int error; 	error = cyapa_check_is_operational(cyapa);	if (error) {		if (error != -ETIMEDOUT && error != -ENODEV &&			cyapa_is_bootloader_mode(cyapa)) {			dev_warn(dev, "device detected but not operational\n");			return 0;		} 		dev_err(dev, "no device detected: %d\n", error);		return error;	} 	return 0;} static int cyapa_open(struct input_dev *input){	struct cyapa *cyapa = input_get_drvdata(input);	struct i2c_client *client = cyapa->client;	struct device *dev = &client->dev;	int error; 	error = mutex_lock_interruptible(&cyapa->state_sync_lock);	if (error)		return error; 	if (cyapa->operational) {		/*		 * though failed to set active power mode,		 * but still may be able to work in lower scan rate		 * when in operational mode.		 */		error = cyapa->ops->set_power_mode(cyapa,				PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);		if (error) {			dev_warn(dev, "set active power failed: %d\n", error);			goto out;		}	} else {		error = cyapa_reinitialize(cyapa);		if (error || !cyapa->operational) {			error = error ? error : -EAGAIN;			goto out;		}	} 	enable_irq(client->irq);	if (!pm_runtime_enabled(dev)) {		pm_runtime_set_active(dev);		pm_runtime_enable(dev);	} 	pm_runtime_get_sync(dev);	pm_runtime_put_sync_autosuspend(dev);out:	mutex_unlock(&cyapa->state_sync_lock);	return error;} static void cyapa_close(struct input_dev *input){	struct cyapa *cyapa = input_get_drvdata(input);	struct i2c_client *client = cyapa->client;	struct device *dev = &cyapa->client->dev; 	mutex_lock(&cyapa->state_sync_lock); 	disable_irq(client->irq);	if (pm_runtime_enabled(dev))		pm_runtime_disable(dev);	pm_runtime_set_suspended(dev); 	if (cyapa->operational)		cyapa->ops->set_power_mode(cyapa,				PWR_MODE_OFF, 0, CYAPA_PM_DEACTIVE); 	mutex_unlock(&cyapa->state_sync_lock);} static int cyapa_create_input_dev(struct cyapa *cyapa){	struct device *dev = &cyapa->client->dev;	struct input_dev *input;	int error; 	if (!cyapa->physical_size_x || !cyapa->physical_size_y)		return -EINVAL; 	input = devm_input_allocate_device(dev);	if (!input) {		dev_err(dev, "failed to allocate memory for input device.\n");		return -ENOMEM;	} 	input->name = CYAPA_NAME;	input->phys = cyapa->phys;	input->id.bustype = BUS_I2C;	input->id.version = 1;	input->id.product = 0;  /* Means any product in eventcomm. */	input->dev.parent = &cyapa->client->dev; 	input->open = cyapa_open;	input->close = cyapa_close; 	input_set_drvdata(input, cyapa); 	__set_bit(EV_ABS, input->evbit); 	/* Finger position */	input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,			     0);	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,			     0);	input_set_abs_params(input, ABS_MT_PRESSURE, 0, cyapa->max_z, 0, 0);	if (cyapa->gen > CYAPA_GEN3) {		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);		input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);		/*		 * Orientation is the angle between the vertical axis and		 * the major axis of the contact ellipse.		 * The range is -127 to 127.		 * the positive direction is clockwise form the vertical axis.		 * If the ellipse of contact degenerates into a circle,		 * orientation is reported as 0.		 *		 * Also, for Gen5 trackpad the accurate of this orientation		 * value is value + (-30 ~ 30).		 */		input_set_abs_params(input, ABS_MT_ORIENTATION,				-127, 127, 0, 0);	}	if (cyapa->gen >= CYAPA_GEN5) {		input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);		input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0);		input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0);	} 	input_abs_set_res(input, ABS_MT_POSITION_X,			  cyapa->max_abs_x / cyapa->physical_size_x);	input_abs_set_res(input, ABS_MT_POSITION_Y,			  cyapa->max_abs_y / cyapa->physical_size_y); 	if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)		__set_bit(BTN_LEFT, input->keybit);	if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)		__set_bit(BTN_MIDDLE, input->keybit);	if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)		__set_bit(BTN_RIGHT, input->keybit);

Lines 1–500 of 1499.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t