// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012-2017 Hideep, Inc.
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/regmap.h>
#include <linux/sysfs.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
#define HIDEEP_TS_NAME "HiDeep Touchscreen"
#define HIDEEP_I2C_NAME "hideep_ts"
#define HIDEEP_MT_MAX 10
#define HIDEEP_KEY_MAX 3
/* count(2) + touch data(100) + key data(6) */
#define HIDEEP_MAX_EVENT 108UL
#define HIDEEP_TOUCH_EVENT_INDEX 2
#define HIDEEP_KEY_EVENT_INDEX 102
/* Touch & key event */
#define HIDEEP_EVENT_ADDR 0x240
/* command list */
#define HIDEEP_RESET_CMD 0x9800
/* event bit */
#define HIDEEP_MT_RELEASED BIT(4)
#define HIDEEP_KEY_PRESSED BIT(7)
#define HIDEEP_KEY_FIRST_PRESSED BIT(8)
#define HIDEEP_KEY_PRESSED_MASK (HIDEEP_KEY_PRESSED | \
HIDEEP_KEY_FIRST_PRESSED)
#define HIDEEP_KEY_IDX_MASK 0x0f
/* For NVM */
#define HIDEEP_YRAM_BASE 0x40000000
#define HIDEEP_PERIPHERAL_BASE 0x50000000
#define HIDEEP_ESI_BASE (HIDEEP_PERIPHERAL_BASE + 0x00000000)
#define HIDEEP_FLASH_BASE (HIDEEP_PERIPHERAL_BASE + 0x01000000)
#define HIDEEP_SYSCON_BASE (HIDEEP_PERIPHERAL_BASE + 0x02000000)
#define HIDEEP_SYSCON_MOD_CON (HIDEEP_SYSCON_BASE + 0x0000)
#define HIDEEP_SYSCON_SPC_CON (HIDEEP_SYSCON_BASE + 0x0004)
#define HIDEEP_SYSCON_CLK_CON (HIDEEP_SYSCON_BASE + 0x0008)
#define HIDEEP_SYSCON_CLK_ENA (HIDEEP_SYSCON_BASE + 0x000C)
#define HIDEEP_SYSCON_RST_CON (HIDEEP_SYSCON_BASE + 0x0010)
#define HIDEEP_SYSCON_WDT_CON (HIDEEP_SYSCON_BASE + 0x0014)
#define HIDEEP_SYSCON_WDT_CNT (HIDEEP_SYSCON_BASE + 0x0018)
#define HIDEEP_SYSCON_PWR_CON (HIDEEP_SYSCON_BASE + 0x0020)
#define HIDEEP_SYSCON_PGM_ID (HIDEEP_SYSCON_BASE + 0x00F4)
#define HIDEEP_FLASH_CON (HIDEEP_FLASH_BASE + 0x0000)
#define HIDEEP_FLASH_STA (HIDEEP_FLASH_BASE + 0x0004)
#define HIDEEP_FLASH_CFG (HIDEEP_FLASH_BASE + 0x0008)
#define HIDEEP_FLASH_TIM (HIDEEP_FLASH_BASE + 0x000C)
#define HIDEEP_FLASH_CACHE_CFG (HIDEEP_FLASH_BASE + 0x0010)
#define HIDEEP_FLASH_PIO_SIG (HIDEEP_FLASH_BASE + 0x400000)
#define HIDEEP_ESI_TX_INVALID (HIDEEP_ESI_BASE + 0x0008)
#define HIDEEP_PERASE 0x00040000
#define HIDEEP_WRONLY 0x00100000
#define HIDEEP_NVM_MASK_OFS 0x0000000C
#define HIDEEP_NVM_DEFAULT_PAGE 0
#define HIDEEP_NVM_SFR_WPAGE 1
#define HIDEEP_NVM_SFR_RPAGE 2
#define HIDEEP_PIO_SIG 0x00400000
#define HIDEEP_PROT_MODE 0x03400000
#define HIDEEP_NVM_PAGE_SIZE 128
#define HIDEEP_DWZ_INFO 0x000002C0
struct hideep_event {
__le16 x;
__le16 y;
__le16 z;
u8 w;
u8 flag;
u8 type;
u8 index;
};
struct dwz_info {
__be32 code_start;
u8 code_crc[12];
__be32 c_code_start;
__be16 gen_ver;
__be16 c_code_len;
__be32 vr_start;
__be16 rsv0;
__be16 vr_len;
__be32 ft_start;
__be16 vr_version;
__be16 ft_len;
__be16 core_ver;
__be16 boot_ver;
__be16 release_ver;
__be16 custom_ver;
u8 factory_id;
u8 panel_type;
u8 model_name[6];
__be16 extra_option;
__be16 product_code;
__be16 vendor_id;
__be16 product_id;
};
struct pgm_packet {
struct {
u8 unused[3];
u8 len;
__be32 addr;
} header;
__be32 payload[HIDEEP_NVM_PAGE_SIZE / sizeof(__be32)];
};
#define HIDEEP_XFER_BUF_SIZE sizeof(struct pgm_packet)
struct hideep_ts {
struct i2c_client *client;
struct input_dev *input_dev;
struct regmap *reg;
struct touchscreen_properties prop;
struct gpio_desc *reset_gpio;
struct regulator *vcc_vdd;
struct regulator *vcc_vid;
struct mutex dev_mutex;
u32 tch_count;
u32 lpm_count;
/*
* Data buffer to read packet from the device (contacts and key
* states). We align it on double-word boundary to keep word-sized
* fields in contact data and double-word-sized fields in program
* packet aligned.
*/
u8 xfer_buf[HIDEEP_XFER_BUF_SIZE] __aligned(4);
int key_num;
u32 key_codes[HIDEEP_KEY_MAX];
struct dwz_info dwz_info;
unsigned int fw_size;
u32 nvm_mask;
};
static int hideep_pgm_w_mem(struct hideep_ts *ts, u32 addr,
const __be32 *data, size_t count)
{
struct pgm_packet *packet = (void *)ts->xfer_buf;
size_t len = count * sizeof(*data);
struct i2c_msg msg = {
.addr = ts->client->addr,
.len = len + sizeof(packet->header.len) +
sizeof(packet->header.addr),
.buf = &packet->header.len,
};
int ret;
if (len > HIDEEP_NVM_PAGE_SIZE)
return -EINVAL;
packet->header.len = 0x80 | (count - 1);
packet->header.addr = cpu_to_be32(addr);
memcpy(packet->payload, data, len);
ret = i2c_transfer(ts->client->adapter, &msg, 1);
if (ret != 1)
return ret < 0 ? ret : -EIO;
return 0;
}
static int hideep_pgm_r_mem(struct hideep_ts *ts, u32 addr,
__be32 *data, size_t count)
{
struct pgm_packet *packet = (void *)ts->xfer_buf;
size_t len = count * sizeof(*data);
struct i2c_msg msg[] = {
{
.addr = ts->client->addr,
.len = sizeof(packet->header.