鼠标 芯片gen6 linux驱动代码

发布于:2024-12-20 ⋅ 阅读:(12) ⋅ 点赞:(0)

/*

  • Cypress APA trackpad with I2C interface
  • Copyright © 2015 Cypress Semiconductor, 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/mutex.h>
#include <linux/completion.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/crc-itu-t.h>
#include “cyapa.h”

#define GEN6_ENABLE_CMD_IRQ 0x41
#define GEN6_DISABLE_CMD_IRQ 0x42
#define GEN6_ENABLE_DEV_IRQ 0x43
#define GEN6_DISABLE_DEV_IRQ 0x44

#define GEN6_POWER_MODE_ACTIVE 0x01
#define GEN6_POWER_MODE_LP_MODE1 0x02
#define GEN6_POWER_MODE_LP_MODE2 0x03
#define GEN6_POWER_MODE_BTN_ONLY 0x04

#define GEN6_SET_POWER_MODE_INTERVAL 0x47
#define GEN6_GET_POWER_MODE_INTERVAL 0x48

#define GEN6_MAX_RX_NUM 14
#define GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC 0x00
#define GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM 0x12

struct pip_app_cmd_head {
__le16 addr;
__le16 length;
u8 report_id;
u8 resv; /* Reserved, must be 0 /
u8 cmd_code; /
bit7: resv, set to 0; bit6~0: command code.*/
} __packed;

struct pip_app_resp_head {
__le16 length;
u8 report_id;
u8 resv; /* Reserved, must be 0 /
u8 cmd_code; /
bit7: TGL; bit6~0: command code./
/

* The value of data_status can be the first byte of data or
* the command status or the unsupported command code depending on the
* requested command code.
*/
u8 data_status;
} __packed;

struct pip_fixed_info {
u8 silicon_id_high;
u8 silicon_id_low;
u8 family_id;
};

static u8 pip_get_bl_info[] = {
0x04, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x01, 0x38,
0x00, 0x00, 0x70, 0x9E, 0x17
};

static bool cyapa_sort_pip_hid_descriptor_data(struct cyapa *cyapa,
u8 *buf, int len)
{
if (len != PIP_HID_DESCRIPTOR_SIZE)
return false;

if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID ||
	buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID)
	return true;

return false;

}

static int cyapa_get_pip_fixed_info(struct cyapa *cyapa,
struct pip_fixed_info *pip_info, bool is_bootloader)
{
u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH];
int resp_len;
u16 product_family;
int error;

if (is_bootloader) {
	/* Read Bootloader Information to determine Gen5 or Gen6. */
	resp_len = sizeof(resp_data);
	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
			pip_get_bl_info, sizeof(pip_get_bl_info),
			resp_data, &resp_len,
			2000, cyapa_sort_tsg_pip_bl_resp_data,
			false);
	if (error || resp_len < PIP_BL_GET_INFO_RESP_LENGTH)
		return error ? error : -EIO;

	pip_info->family_id = resp_data[8];
	pip_info->silicon_id_low = resp_data[10];
	pip_info->silicon_id_high = resp_data[11];

	return 0;
}

/* Get App System Information to determine Gen5 or Gen6. */
resp_len = sizeof(resp_data);
error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
		pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH,
		resp_data, &resp_len,
		2000, cyapa_pip_sort_system_info_data, false);
if (error || resp_len < PIP_READ_SYS_INFO_RESP_LENGTH)
	return error ? error : -EIO;

product_family = get_unaligned_le16(&resp_data[7]);
if ((product_family & PIP_PRODUCT_FAMILY_MASK) !=
	PIP_PRODUCT_FAMILY_TRACKPAD)
	return -EINVAL;

pip_info->family_id = resp_data[19];
pip_info->silicon_id_low = resp_data[21];
pip_info->silicon_id_high = resp_data[22];

return 0;

}

int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
{
u8 cmd[] = { 0x01, 0x00};
struct pip_fixed_info pip_info;
u8 resp_data[PIP_HID_DESCRIPTOR_SIZE];
int resp_len;
bool is_bootloader;
int error;

cyapa->state = CYAPA_STATE_NO_DEVICE;

/* Try to wake from it deep sleep state if it is. */
cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);

/* Empty the buffer queue to get fresh data with later commands. */
cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);

/*
 * Read description info from trackpad device to determine running in
 * APP mode or Boo