162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Raydium touchscreen I2C driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012-2014, Raydium Semiconductor Corporation. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Raydium reserves the right to make changes without further notice 862306a36Sopenharmony_ci * to the materials described herein. Raydium does not assume any 962306a36Sopenharmony_ci * liability arising out of the application described herein. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Contact Raydium Semiconductor Corporation at www.rad-ic.com 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/acpi.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/firmware.h> 1762306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1862306a36Sopenharmony_ci#include <linux/i2c.h> 1962306a36Sopenharmony_ci#include <linux/input.h> 2062306a36Sopenharmony_ci#include <linux/input/mt.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci#include <linux/pm_wakeirq.h> 2562306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci#include <asm/unaligned.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* Slave I2C mode */ 3062306a36Sopenharmony_ci#define RM_BOOT_BLDR 0x02 3162306a36Sopenharmony_ci#define RM_BOOT_MAIN 0x03 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* I2C bootoloader commands */ 3462306a36Sopenharmony_ci#define RM_CMD_BOOT_PAGE_WRT 0x0B /* send bl page write */ 3562306a36Sopenharmony_ci#define RM_CMD_BOOT_WRT 0x11 /* send bl write */ 3662306a36Sopenharmony_ci#define RM_CMD_BOOT_ACK 0x22 /* send ack*/ 3762306a36Sopenharmony_ci#define RM_CMD_BOOT_CHK 0x33 /* send data check */ 3862306a36Sopenharmony_ci#define RM_CMD_BOOT_READ 0x44 /* send wait bl data ready*/ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define RM_BOOT_RDY 0xFF /* bl data ready */ 4162306a36Sopenharmony_ci#define RM_BOOT_CMD_READHWID 0x0E /* read hwid */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* I2C main commands */ 4462306a36Sopenharmony_ci#define RM_CMD_QUERY_BANK 0x2B 4562306a36Sopenharmony_ci#define RM_CMD_DATA_BANK 0x4D 4662306a36Sopenharmony_ci#define RM_CMD_ENTER_SLEEP 0x4E 4762306a36Sopenharmony_ci#define RM_CMD_BANK_SWITCH 0xAA 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define RM_RESET_MSG_ADDR 0x40000004 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define RM_MAX_READ_SIZE 56 5262306a36Sopenharmony_ci#define RM_PACKET_CRC_SIZE 2 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* Touch relative info */ 5562306a36Sopenharmony_ci#define RM_MAX_RETRIES 3 5662306a36Sopenharmony_ci#define RM_RETRY_DELAY_MS 20 5762306a36Sopenharmony_ci#define RM_MAX_TOUCH_NUM 10 5862306a36Sopenharmony_ci#define RM_BOOT_DELAY_MS 100 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Offsets in contact data */ 6162306a36Sopenharmony_ci#define RM_CONTACT_STATE_POS 0 6262306a36Sopenharmony_ci#define RM_CONTACT_X_POS 1 6362306a36Sopenharmony_ci#define RM_CONTACT_Y_POS 3 6462306a36Sopenharmony_ci#define RM_CONTACT_PRESSURE_POS 5 6562306a36Sopenharmony_ci#define RM_CONTACT_WIDTH_X_POS 6 6662306a36Sopenharmony_ci#define RM_CONTACT_WIDTH_Y_POS 7 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* Bootloader relative info */ 6962306a36Sopenharmony_ci#define RM_BL_WRT_CMD_SIZE 3 /* bl flash wrt cmd size */ 7062306a36Sopenharmony_ci#define RM_BL_WRT_PKG_SIZE 32 /* bl wrt pkg size */ 7162306a36Sopenharmony_ci#define RM_BL_WRT_LEN (RM_BL_WRT_PKG_SIZE + RM_BL_WRT_CMD_SIZE) 7262306a36Sopenharmony_ci#define RM_FW_PAGE_SIZE 128 7362306a36Sopenharmony_ci#define RM_MAX_FW_RETRIES 30 7462306a36Sopenharmony_ci#define RM_MAX_FW_SIZE 0xD000 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define RM_POWERON_DELAY_USEC 500 7762306a36Sopenharmony_ci#define RM_RESET_DELAY_MSEC 50 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cienum raydium_bl_cmd { 8062306a36Sopenharmony_ci BL_HEADER = 0, 8162306a36Sopenharmony_ci BL_PAGE_STR, 8262306a36Sopenharmony_ci BL_PKG_IDX, 8362306a36Sopenharmony_ci BL_DATA_STR, 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cienum raydium_bl_ack { 8762306a36Sopenharmony_ci RAYDIUM_ACK_NULL = 0, 8862306a36Sopenharmony_ci RAYDIUM_WAIT_READY, 8962306a36Sopenharmony_ci RAYDIUM_PATH_READY, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cienum raydium_boot_mode { 9362306a36Sopenharmony_ci RAYDIUM_TS_MAIN = 0, 9462306a36Sopenharmony_ci RAYDIUM_TS_BLDR, 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* Response to RM_CMD_DATA_BANK request */ 9862306a36Sopenharmony_cistruct raydium_data_info { 9962306a36Sopenharmony_ci __le32 data_bank_addr; 10062306a36Sopenharmony_ci u8 pkg_size; 10162306a36Sopenharmony_ci u8 tp_info_size; 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistruct raydium_info { 10562306a36Sopenharmony_ci __le32 hw_ver; /*device version */ 10662306a36Sopenharmony_ci u8 main_ver; 10762306a36Sopenharmony_ci u8 sub_ver; 10862306a36Sopenharmony_ci __le16 ft_ver; /* test version */ 10962306a36Sopenharmony_ci u8 x_num; 11062306a36Sopenharmony_ci u8 y_num; 11162306a36Sopenharmony_ci __le16 x_max; 11262306a36Sopenharmony_ci __le16 y_max; 11362306a36Sopenharmony_ci u8 x_res; /* units/mm */ 11462306a36Sopenharmony_ci u8 y_res; /* units/mm */ 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* struct raydium_data - represents state of Raydium touchscreen device */ 11862306a36Sopenharmony_cistruct raydium_data { 11962306a36Sopenharmony_ci struct i2c_client *client; 12062306a36Sopenharmony_ci struct input_dev *input; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci struct regulator *avdd; 12362306a36Sopenharmony_ci struct regulator *vccio; 12462306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci struct raydium_info info; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci struct mutex sysfs_mutex; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci u8 *report_data; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci u32 data_bank_addr; 13362306a36Sopenharmony_ci u8 report_size; 13462306a36Sopenharmony_ci u8 contact_size; 13562306a36Sopenharmony_ci u8 pkg_size; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci enum raydium_boot_mode boot_mode; 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* 14162306a36Sopenharmony_ci * Header to be sent for RM_CMD_BANK_SWITCH command. This is used by 14262306a36Sopenharmony_ci * raydium_i2c_{read|send} below. 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_cistruct __packed raydium_bank_switch_header { 14562306a36Sopenharmony_ci u8 cmd; 14662306a36Sopenharmony_ci __be32 be_addr; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int raydium_i2c_xfer(struct i2c_client *client, u32 addr, 15062306a36Sopenharmony_ci struct i2c_msg *xfer, size_t xfer_count) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci int ret; 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * If address is greater than 255, then RM_CMD_BANK_SWITCH needs to be 15562306a36Sopenharmony_ci * sent first. Else, skip the header i.e. xfer[0]. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci int xfer_start_idx = (addr > 0xff) ? 0 : 1; 15862306a36Sopenharmony_ci xfer_count -= xfer_start_idx; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ret = i2c_transfer(client->adapter, &xfer[xfer_start_idx], xfer_count); 16162306a36Sopenharmony_ci if (likely(ret == xfer_count)) 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return ret < 0 ? ret : -EIO; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int raydium_i2c_send(struct i2c_client *client, 16862306a36Sopenharmony_ci u32 addr, const void *data, size_t len) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci int tries = 0; 17162306a36Sopenharmony_ci int error; 17262306a36Sopenharmony_ci u8 *tx_buf; 17362306a36Sopenharmony_ci u8 reg_addr = addr & 0xff; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci tx_buf = kmalloc(len + 1, GFP_KERNEL); 17662306a36Sopenharmony_ci if (!tx_buf) 17762306a36Sopenharmony_ci return -ENOMEM; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci tx_buf[0] = reg_addr; 18062306a36Sopenharmony_ci memcpy(tx_buf + 1, data, len); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci do { 18362306a36Sopenharmony_ci struct raydium_bank_switch_header header = { 18462306a36Sopenharmony_ci .cmd = RM_CMD_BANK_SWITCH, 18562306a36Sopenharmony_ci .be_addr = cpu_to_be32(addr), 18662306a36Sopenharmony_ci }; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* 18962306a36Sopenharmony_ci * Perform as a single i2c_transfer transaction to ensure that 19062306a36Sopenharmony_ci * no other I2C transactions are initiated on the bus to any 19162306a36Sopenharmony_ci * other device in between. Initiating transacations to other 19262306a36Sopenharmony_ci * devices after RM_CMD_BANK_SWITCH is sent is known to cause 19362306a36Sopenharmony_ci * issues. This is also why regmap infrastructure cannot be used 19462306a36Sopenharmony_ci * for this driver. Regmap handles page(bank) switch and reads 19562306a36Sopenharmony_ci * as separate i2c_transfer() operations. This can result in 19662306a36Sopenharmony_ci * problems if the Raydium device is on a shared I2C bus. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci struct i2c_msg xfer[] = { 19962306a36Sopenharmony_ci { 20062306a36Sopenharmony_ci .addr = client->addr, 20162306a36Sopenharmony_ci .len = sizeof(header), 20262306a36Sopenharmony_ci .buf = (u8 *)&header, 20362306a36Sopenharmony_ci }, 20462306a36Sopenharmony_ci { 20562306a36Sopenharmony_ci .addr = client->addr, 20662306a36Sopenharmony_ci .len = len + 1, 20762306a36Sopenharmony_ci .buf = tx_buf, 20862306a36Sopenharmony_ci }, 20962306a36Sopenharmony_ci }; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci error = raydium_i2c_xfer(client, addr, xfer, ARRAY_SIZE(xfer)); 21262306a36Sopenharmony_ci if (likely(!error)) 21362306a36Sopenharmony_ci goto out; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci msleep(RM_RETRY_DELAY_MS); 21662306a36Sopenharmony_ci } while (++tries < RM_MAX_RETRIES); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci dev_err(&client->dev, "%s failed: %d\n", __func__, error); 21962306a36Sopenharmony_ciout: 22062306a36Sopenharmony_ci kfree(tx_buf); 22162306a36Sopenharmony_ci return error; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int raydium_i2c_read(struct i2c_client *client, 22562306a36Sopenharmony_ci u32 addr, void *data, size_t len) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci int error; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci while (len) { 23062306a36Sopenharmony_ci u8 reg_addr = addr & 0xff; 23162306a36Sopenharmony_ci struct raydium_bank_switch_header header = { 23262306a36Sopenharmony_ci .cmd = RM_CMD_BANK_SWITCH, 23362306a36Sopenharmony_ci .be_addr = cpu_to_be32(addr), 23462306a36Sopenharmony_ci }; 23562306a36Sopenharmony_ci size_t xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* 23862306a36Sopenharmony_ci * Perform as a single i2c_transfer transaction to ensure that 23962306a36Sopenharmony_ci * no other I2C transactions are initiated on the bus to any 24062306a36Sopenharmony_ci * other device in between. Initiating transacations to other 24162306a36Sopenharmony_ci * devices after RM_CMD_BANK_SWITCH is sent is known to cause 24262306a36Sopenharmony_ci * issues. This is also why regmap infrastructure cannot be used 24362306a36Sopenharmony_ci * for this driver. Regmap handles page(bank) switch and writes 24462306a36Sopenharmony_ci * as separate i2c_transfer() operations. This can result in 24562306a36Sopenharmony_ci * problems if the Raydium device is on a shared I2C bus. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci struct i2c_msg xfer[] = { 24862306a36Sopenharmony_ci { 24962306a36Sopenharmony_ci .addr = client->addr, 25062306a36Sopenharmony_ci .len = sizeof(header), 25162306a36Sopenharmony_ci .buf = (u8 *)&header, 25262306a36Sopenharmony_ci }, 25362306a36Sopenharmony_ci { 25462306a36Sopenharmony_ci .addr = client->addr, 25562306a36Sopenharmony_ci .len = 1, 25662306a36Sopenharmony_ci .buf = ®_addr, 25762306a36Sopenharmony_ci }, 25862306a36Sopenharmony_ci { 25962306a36Sopenharmony_ci .addr = client->addr, 26062306a36Sopenharmony_ci .len = xfer_len, 26162306a36Sopenharmony_ci .buf = data, 26262306a36Sopenharmony_ci .flags = I2C_M_RD, 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci }; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci error = raydium_i2c_xfer(client, addr, xfer, ARRAY_SIZE(xfer)); 26762306a36Sopenharmony_ci if (unlikely(error)) 26862306a36Sopenharmony_ci return error; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci len -= xfer_len; 27162306a36Sopenharmony_ci data += xfer_len; 27262306a36Sopenharmony_ci addr += xfer_len; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return 0; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int raydium_i2c_sw_reset(struct i2c_client *client) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci const u8 soft_rst_cmd = 0x01; 28162306a36Sopenharmony_ci int error; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci error = raydium_i2c_send(client, RM_RESET_MSG_ADDR, &soft_rst_cmd, 28462306a36Sopenharmony_ci sizeof(soft_rst_cmd)); 28562306a36Sopenharmony_ci if (error) { 28662306a36Sopenharmony_ci dev_err(&client->dev, "software reset failed: %d\n", error); 28762306a36Sopenharmony_ci return error; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci msleep(RM_RESET_DELAY_MSEC); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int raydium_i2c_query_ts_bootloader_info(struct raydium_data *ts) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct i2c_client *client = ts->client; 29862306a36Sopenharmony_ci static const u8 get_hwid[] = { RM_BOOT_CMD_READHWID, 29962306a36Sopenharmony_ci 0x10, 0xc0, 0x01, 0x00, 0x04, 0x00 }; 30062306a36Sopenharmony_ci u8 rbuf[5] = { 0 }; 30162306a36Sopenharmony_ci u32 hw_ver; 30262306a36Sopenharmony_ci int error; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, 30562306a36Sopenharmony_ci get_hwid, sizeof(get_hwid)); 30662306a36Sopenharmony_ci if (error) { 30762306a36Sopenharmony_ci dev_err(&client->dev, "WRT HWID command failed: %d\n", error); 30862306a36Sopenharmony_ci return error; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, rbuf, 1); 31262306a36Sopenharmony_ci if (error) { 31362306a36Sopenharmony_ci dev_err(&client->dev, "Ack HWID command failed: %d\n", error); 31462306a36Sopenharmony_ci return error; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, rbuf, sizeof(rbuf)); 31862306a36Sopenharmony_ci if (error) { 31962306a36Sopenharmony_ci dev_err(&client->dev, "Read HWID command failed: %d (%4ph)\n", 32062306a36Sopenharmony_ci error, rbuf + 1); 32162306a36Sopenharmony_ci hw_ver = 0xffffffffUL; 32262306a36Sopenharmony_ci } else { 32362306a36Sopenharmony_ci hw_ver = get_unaligned_be32(rbuf + 1); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci ts->info.hw_ver = cpu_to_le32(hw_ver); 32762306a36Sopenharmony_ci ts->info.main_ver = 0xff; 32862306a36Sopenharmony_ci ts->info.sub_ver = 0xff; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return error; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int raydium_i2c_query_ts_info(struct raydium_data *ts) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct i2c_client *client = ts->client; 33662306a36Sopenharmony_ci struct raydium_data_info data_info; 33762306a36Sopenharmony_ci __le32 query_bank_addr; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci int error, retry_cnt; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) { 34262306a36Sopenharmony_ci error = raydium_i2c_read(client, RM_CMD_DATA_BANK, 34362306a36Sopenharmony_ci &data_info, sizeof(data_info)); 34462306a36Sopenharmony_ci if (error) 34562306a36Sopenharmony_ci continue; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* 34862306a36Sopenharmony_ci * Warn user if we already allocated memory for reports and 34962306a36Sopenharmony_ci * then the size changed (due to firmware update?) and keep 35062306a36Sopenharmony_ci * old size instead. 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci if (ts->report_data && ts->pkg_size != data_info.pkg_size) { 35362306a36Sopenharmony_ci dev_warn(&client->dev, 35462306a36Sopenharmony_ci "report size changes, was: %d, new: %d\n", 35562306a36Sopenharmony_ci ts->pkg_size, data_info.pkg_size); 35662306a36Sopenharmony_ci } else { 35762306a36Sopenharmony_ci ts->pkg_size = data_info.pkg_size; 35862306a36Sopenharmony_ci ts->report_size = ts->pkg_size - RM_PACKET_CRC_SIZE; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ts->contact_size = data_info.tp_info_size; 36262306a36Sopenharmony_ci ts->data_bank_addr = le32_to_cpu(data_info.data_bank_addr); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci dev_dbg(&client->dev, 36562306a36Sopenharmony_ci "data_bank_addr: %#08x, report_size: %d, contact_size: %d\n", 36662306a36Sopenharmony_ci ts->data_bank_addr, ts->report_size, ts->contact_size); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci error = raydium_i2c_read(client, RM_CMD_QUERY_BANK, 36962306a36Sopenharmony_ci &query_bank_addr, 37062306a36Sopenharmony_ci sizeof(query_bank_addr)); 37162306a36Sopenharmony_ci if (error) 37262306a36Sopenharmony_ci continue; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci error = raydium_i2c_read(client, le32_to_cpu(query_bank_addr), 37562306a36Sopenharmony_ci &ts->info, sizeof(ts->info)); 37662306a36Sopenharmony_ci if (error) 37762306a36Sopenharmony_ci continue; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci dev_err(&client->dev, "failed to query device parameters: %d\n", error); 38362306a36Sopenharmony_ci return error; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic int raydium_i2c_check_fw_status(struct raydium_data *ts) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct i2c_client *client = ts->client; 38962306a36Sopenharmony_ci static const u8 bl_ack = 0x62; 39062306a36Sopenharmony_ci static const u8 main_ack = 0x66; 39162306a36Sopenharmony_ci u8 buf[4]; 39262306a36Sopenharmony_ci int error; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci error = raydium_i2c_read(client, RM_CMD_BOOT_READ, buf, sizeof(buf)); 39562306a36Sopenharmony_ci if (!error) { 39662306a36Sopenharmony_ci if (buf[0] == bl_ack) 39762306a36Sopenharmony_ci ts->boot_mode = RAYDIUM_TS_BLDR; 39862306a36Sopenharmony_ci else if (buf[0] == main_ack) 39962306a36Sopenharmony_ci ts->boot_mode = RAYDIUM_TS_MAIN; 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return error; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int raydium_i2c_initialize(struct raydium_data *ts) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct i2c_client *client = ts->client; 40962306a36Sopenharmony_ci int error, retry_cnt; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) { 41262306a36Sopenharmony_ci /* Wait for Hello packet */ 41362306a36Sopenharmony_ci msleep(RM_BOOT_DELAY_MS); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci error = raydium_i2c_check_fw_status(ts); 41662306a36Sopenharmony_ci if (error) { 41762306a36Sopenharmony_ci dev_err(&client->dev, 41862306a36Sopenharmony_ci "failed to read 'hello' packet: %d\n", error); 41962306a36Sopenharmony_ci continue; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (ts->boot_mode == RAYDIUM_TS_BLDR || 42362306a36Sopenharmony_ci ts->boot_mode == RAYDIUM_TS_MAIN) { 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (error) 42962306a36Sopenharmony_ci ts->boot_mode = RAYDIUM_TS_BLDR; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (ts->boot_mode == RAYDIUM_TS_BLDR) 43262306a36Sopenharmony_ci raydium_i2c_query_ts_bootloader_info(ts); 43362306a36Sopenharmony_ci else 43462306a36Sopenharmony_ci raydium_i2c_query_ts_info(ts); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return error; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int raydium_i2c_bl_chk_state(struct i2c_client *client, 44062306a36Sopenharmony_ci enum raydium_bl_ack state) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci static const u8 ack_ok[] = { 0xFF, 0x39, 0x30, 0x30, 0x54 }; 44362306a36Sopenharmony_ci u8 rbuf[sizeof(ack_ok)]; 44462306a36Sopenharmony_ci u8 retry; 44562306a36Sopenharmony_ci int error; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci for (retry = 0; retry < RM_MAX_FW_RETRIES; retry++) { 44862306a36Sopenharmony_ci switch (state) { 44962306a36Sopenharmony_ci case RAYDIUM_ACK_NULL: 45062306a36Sopenharmony_ci return 0; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci case RAYDIUM_WAIT_READY: 45362306a36Sopenharmony_ci error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, 45462306a36Sopenharmony_ci &rbuf[0], 1); 45562306a36Sopenharmony_ci if (!error && rbuf[0] == RM_BOOT_RDY) 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci case RAYDIUM_PATH_READY: 46162306a36Sopenharmony_ci error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, 46262306a36Sopenharmony_ci rbuf, sizeof(rbuf)); 46362306a36Sopenharmony_ci if (!error && !memcmp(rbuf, ack_ok, sizeof(ack_ok))) 46462306a36Sopenharmony_ci return 0; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci default: 46962306a36Sopenharmony_ci dev_err(&client->dev, "%s: invalid target state %d\n", 47062306a36Sopenharmony_ci __func__, state); 47162306a36Sopenharmony_ci return -EINVAL; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci msleep(20); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci return -ETIMEDOUT; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int raydium_i2c_write_object(struct i2c_client *client, 48162306a36Sopenharmony_ci const void *data, size_t len, 48262306a36Sopenharmony_ci enum raydium_bl_ack state) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci int error; 48562306a36Sopenharmony_ci static const u8 cmd[] = { 0xFF, 0x39 }; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len); 48862306a36Sopenharmony_ci if (error) { 48962306a36Sopenharmony_ci dev_err(&client->dev, "WRT obj command failed: %d\n", 49062306a36Sopenharmony_ci error); 49162306a36Sopenharmony_ci return error; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, cmd, sizeof(cmd)); 49562306a36Sopenharmony_ci if (error) { 49662306a36Sopenharmony_ci dev_err(&client->dev, "Ack obj command failed: %d\n", error); 49762306a36Sopenharmony_ci return error; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci error = raydium_i2c_bl_chk_state(client, state); 50162306a36Sopenharmony_ci if (error) { 50262306a36Sopenharmony_ci dev_err(&client->dev, "BL check state failed: %d\n", error); 50362306a36Sopenharmony_ci return error; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci return 0; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int raydium_i2c_boot_trigger(struct i2c_client *client) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci static const u8 cmd[7][6] = { 51162306a36Sopenharmony_ci { 0x08, 0x0C, 0x09, 0x00, 0x50, 0xD7 }, 51262306a36Sopenharmony_ci { 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 }, 51362306a36Sopenharmony_ci { 0x08, 0x04, 0x09, 0x00, 0x50, 0x00 }, 51462306a36Sopenharmony_ci { 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 }, 51562306a36Sopenharmony_ci { 0x08, 0x0C, 0x09, 0x00, 0x50, 0x00 }, 51662306a36Sopenharmony_ci { 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 }, 51762306a36Sopenharmony_ci { 0x02, 0xA2, 0x00, 0x00, 0x00, 0x00 }, 51862306a36Sopenharmony_ci }; 51962306a36Sopenharmony_ci int i; 52062306a36Sopenharmony_ci int error; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci for (i = 0; i < 7; i++) { 52362306a36Sopenharmony_ci error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]), 52462306a36Sopenharmony_ci RAYDIUM_WAIT_READY); 52562306a36Sopenharmony_ci if (error) { 52662306a36Sopenharmony_ci dev_err(&client->dev, 52762306a36Sopenharmony_ci "boot trigger failed at step %d: %d\n", 52862306a36Sopenharmony_ci i, error); 52962306a36Sopenharmony_ci return error; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return 0; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic int raydium_i2c_fw_trigger(struct i2c_client *client) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci static const u8 cmd[5][11] = { 53962306a36Sopenharmony_ci { 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0xD7, 0, 0, 0 }, 54062306a36Sopenharmony_ci { 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 }, 54162306a36Sopenharmony_ci { 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 }, 54262306a36Sopenharmony_ci { 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 }, 54362306a36Sopenharmony_ci { 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 }, 54462306a36Sopenharmony_ci }; 54562306a36Sopenharmony_ci int i; 54662306a36Sopenharmony_ci int error; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 54962306a36Sopenharmony_ci error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]), 55062306a36Sopenharmony_ci RAYDIUM_ACK_NULL); 55162306a36Sopenharmony_ci if (error) { 55262306a36Sopenharmony_ci dev_err(&client->dev, 55362306a36Sopenharmony_ci "fw trigger failed at step %d: %d\n", 55462306a36Sopenharmony_ci i, error); 55562306a36Sopenharmony_ci return error; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return 0; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic int raydium_i2c_check_path(struct i2c_client *client) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci static const u8 cmd[] = { 0x09, 0x00, 0x09, 0x00, 0x50, 0x10, 0x00 }; 56562306a36Sopenharmony_ci int error; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci error = raydium_i2c_write_object(client, cmd, sizeof(cmd), 56862306a36Sopenharmony_ci RAYDIUM_PATH_READY); 56962306a36Sopenharmony_ci if (error) { 57062306a36Sopenharmony_ci dev_err(&client->dev, "check path command failed: %d\n", error); 57162306a36Sopenharmony_ci return error; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci return 0; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int raydium_i2c_enter_bl(struct i2c_client *client) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci static const u8 cal_cmd[] = { 0x00, 0x01, 0x52 }; 58062306a36Sopenharmony_ci int error; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd), 58362306a36Sopenharmony_ci RAYDIUM_ACK_NULL); 58462306a36Sopenharmony_ci if (error) { 58562306a36Sopenharmony_ci dev_err(&client->dev, "enter bl command failed: %d\n", error); 58662306a36Sopenharmony_ci return error; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci msleep(RM_BOOT_DELAY_MS); 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic int raydium_i2c_leave_bl(struct i2c_client *client) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci static const u8 leave_cmd[] = { 0x05, 0x00 }; 59662306a36Sopenharmony_ci int error; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci error = raydium_i2c_write_object(client, leave_cmd, sizeof(leave_cmd), 59962306a36Sopenharmony_ci RAYDIUM_ACK_NULL); 60062306a36Sopenharmony_ci if (error) { 60162306a36Sopenharmony_ci dev_err(&client->dev, "leave bl command failed: %d\n", error); 60262306a36Sopenharmony_ci return error; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci msleep(RM_BOOT_DELAY_MS); 60662306a36Sopenharmony_ci return 0; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int raydium_i2c_write_checksum(struct i2c_client *client, 61062306a36Sopenharmony_ci size_t length, u16 checksum) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci u8 checksum_cmd[] = { 0x00, 0x05, 0x6D, 0x00, 0x00, 0x00, 0x00 }; 61362306a36Sopenharmony_ci int error; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci put_unaligned_le16(length, &checksum_cmd[3]); 61662306a36Sopenharmony_ci put_unaligned_le16(checksum, &checksum_cmd[5]); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci error = raydium_i2c_write_object(client, 61962306a36Sopenharmony_ci checksum_cmd, sizeof(checksum_cmd), 62062306a36Sopenharmony_ci RAYDIUM_ACK_NULL); 62162306a36Sopenharmony_ci if (error) { 62262306a36Sopenharmony_ci dev_err(&client->dev, "failed to write checksum: %d\n", 62362306a36Sopenharmony_ci error); 62462306a36Sopenharmony_ci return error; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci return 0; 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic int raydium_i2c_disable_watch_dog(struct i2c_client *client) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci static const u8 cmd[] = { 0x0A, 0xAA }; 63362306a36Sopenharmony_ci int error; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci error = raydium_i2c_write_object(client, cmd, sizeof(cmd), 63662306a36Sopenharmony_ci RAYDIUM_WAIT_READY); 63762306a36Sopenharmony_ci if (error) { 63862306a36Sopenharmony_ci dev_err(&client->dev, "disable watchdog command failed: %d\n", 63962306a36Sopenharmony_ci error); 64062306a36Sopenharmony_ci return error; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int raydium_i2c_fw_write_page(struct i2c_client *client, 64762306a36Sopenharmony_ci u16 page_idx, const void *data, size_t len) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci u8 buf[RM_BL_WRT_LEN]; 65062306a36Sopenharmony_ci size_t xfer_len; 65162306a36Sopenharmony_ci int error; 65262306a36Sopenharmony_ci int i; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci BUILD_BUG_ON((RM_FW_PAGE_SIZE % RM_BL_WRT_PKG_SIZE) != 0); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci for (i = 0; i < RM_FW_PAGE_SIZE / RM_BL_WRT_PKG_SIZE; i++) { 65762306a36Sopenharmony_ci buf[BL_HEADER] = RM_CMD_BOOT_PAGE_WRT; 65862306a36Sopenharmony_ci buf[BL_PAGE_STR] = page_idx ? 0xff : 0; 65962306a36Sopenharmony_ci buf[BL_PKG_IDX] = i + 1; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci xfer_len = min_t(size_t, len, RM_BL_WRT_PKG_SIZE); 66262306a36Sopenharmony_ci memcpy(&buf[BL_DATA_STR], data, xfer_len); 66362306a36Sopenharmony_ci if (len < RM_BL_WRT_PKG_SIZE) 66462306a36Sopenharmony_ci memset(&buf[BL_DATA_STR + xfer_len], 0xff, 66562306a36Sopenharmony_ci RM_BL_WRT_PKG_SIZE - xfer_len); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci error = raydium_i2c_write_object(client, buf, RM_BL_WRT_LEN, 66862306a36Sopenharmony_ci RAYDIUM_WAIT_READY); 66962306a36Sopenharmony_ci if (error) { 67062306a36Sopenharmony_ci dev_err(&client->dev, 67162306a36Sopenharmony_ci "page write command failed for page %d, chunk %d: %d\n", 67262306a36Sopenharmony_ci page_idx, i, error); 67362306a36Sopenharmony_ci return error; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci data += xfer_len; 67762306a36Sopenharmony_ci len -= xfer_len; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return error; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic u16 raydium_calc_chksum(const u8 *buf, u16 len) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci u16 checksum = 0; 68662306a36Sopenharmony_ci u16 i; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci for (i = 0; i < len; i++) 68962306a36Sopenharmony_ci checksum += buf[i]; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return checksum; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int raydium_i2c_do_update_firmware(struct raydium_data *ts, 69562306a36Sopenharmony_ci const struct firmware *fw) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct i2c_client *client = ts->client; 69862306a36Sopenharmony_ci const void *data; 69962306a36Sopenharmony_ci size_t data_len; 70062306a36Sopenharmony_ci size_t len; 70162306a36Sopenharmony_ci int page_nr; 70262306a36Sopenharmony_ci int i; 70362306a36Sopenharmony_ci int error; 70462306a36Sopenharmony_ci u16 fw_checksum; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (fw->size == 0 || fw->size > RM_MAX_FW_SIZE) { 70762306a36Sopenharmony_ci dev_err(&client->dev, "Invalid firmware length\n"); 70862306a36Sopenharmony_ci return -EINVAL; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci error = raydium_i2c_check_fw_status(ts); 71262306a36Sopenharmony_ci if (error) { 71362306a36Sopenharmony_ci dev_err(&client->dev, "Unable to access IC %d\n", error); 71462306a36Sopenharmony_ci return error; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (ts->boot_mode == RAYDIUM_TS_MAIN) { 71862306a36Sopenharmony_ci for (i = 0; i < RM_MAX_RETRIES; i++) { 71962306a36Sopenharmony_ci error = raydium_i2c_enter_bl(client); 72062306a36Sopenharmony_ci if (!error) { 72162306a36Sopenharmony_ci error = raydium_i2c_check_fw_status(ts); 72262306a36Sopenharmony_ci if (error) { 72362306a36Sopenharmony_ci dev_err(&client->dev, 72462306a36Sopenharmony_ci "unable to access IC: %d\n", 72562306a36Sopenharmony_ci error); 72662306a36Sopenharmony_ci return error; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (ts->boot_mode == RAYDIUM_TS_BLDR) 73062306a36Sopenharmony_ci break; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (ts->boot_mode == RAYDIUM_TS_MAIN) { 73562306a36Sopenharmony_ci dev_err(&client->dev, 73662306a36Sopenharmony_ci "failed to jump to boot loader: %d\n", 73762306a36Sopenharmony_ci error); 73862306a36Sopenharmony_ci return -EIO; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci error = raydium_i2c_disable_watch_dog(client); 74362306a36Sopenharmony_ci if (error) 74462306a36Sopenharmony_ci return error; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci error = raydium_i2c_check_path(client); 74762306a36Sopenharmony_ci if (error) 74862306a36Sopenharmony_ci return error; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci error = raydium_i2c_boot_trigger(client); 75162306a36Sopenharmony_ci if (error) { 75262306a36Sopenharmony_ci dev_err(&client->dev, "send boot trigger fail: %d\n", error); 75362306a36Sopenharmony_ci return error; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci msleep(RM_BOOT_DELAY_MS); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci data = fw->data; 75962306a36Sopenharmony_ci data_len = fw->size; 76062306a36Sopenharmony_ci page_nr = 0; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci while (data_len) { 76362306a36Sopenharmony_ci len = min_t(size_t, data_len, RM_FW_PAGE_SIZE); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci error = raydium_i2c_fw_write_page(client, page_nr++, data, len); 76662306a36Sopenharmony_ci if (error) 76762306a36Sopenharmony_ci return error; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci msleep(20); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci data += len; 77262306a36Sopenharmony_ci data_len -= len; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci error = raydium_i2c_leave_bl(client); 77662306a36Sopenharmony_ci if (error) { 77762306a36Sopenharmony_ci dev_err(&client->dev, 77862306a36Sopenharmony_ci "failed to leave boot loader: %d\n", error); 77962306a36Sopenharmony_ci return error; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci dev_dbg(&client->dev, "left boot loader mode\n"); 78362306a36Sopenharmony_ci msleep(RM_BOOT_DELAY_MS); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci error = raydium_i2c_check_fw_status(ts); 78662306a36Sopenharmony_ci if (error) { 78762306a36Sopenharmony_ci dev_err(&client->dev, 78862306a36Sopenharmony_ci "failed to check fw status after write: %d\n", 78962306a36Sopenharmony_ci error); 79062306a36Sopenharmony_ci return error; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (ts->boot_mode != RAYDIUM_TS_MAIN) { 79462306a36Sopenharmony_ci dev_err(&client->dev, 79562306a36Sopenharmony_ci "failed to switch to main fw after writing firmware: %d\n", 79662306a36Sopenharmony_ci error); 79762306a36Sopenharmony_ci return -EINVAL; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci error = raydium_i2c_fw_trigger(client); 80162306a36Sopenharmony_ci if (error) { 80262306a36Sopenharmony_ci dev_err(&client->dev, "failed to trigger fw: %d\n", error); 80362306a36Sopenharmony_ci return error; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci fw_checksum = raydium_calc_chksum(fw->data, fw->size); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci error = raydium_i2c_write_checksum(client, fw->size, fw_checksum); 80962306a36Sopenharmony_ci if (error) 81062306a36Sopenharmony_ci return error; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic int raydium_i2c_fw_update(struct raydium_data *ts) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci struct i2c_client *client = ts->client; 81862306a36Sopenharmony_ci const struct firmware *fw = NULL; 81962306a36Sopenharmony_ci char *fw_file; 82062306a36Sopenharmony_ci int error; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci fw_file = kasprintf(GFP_KERNEL, "raydium_%#04x.fw", 82362306a36Sopenharmony_ci le32_to_cpu(ts->info.hw_ver)); 82462306a36Sopenharmony_ci if (!fw_file) 82562306a36Sopenharmony_ci return -ENOMEM; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci dev_dbg(&client->dev, "firmware name: %s\n", fw_file); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci error = request_firmware(&fw, fw_file, &client->dev); 83062306a36Sopenharmony_ci if (error) { 83162306a36Sopenharmony_ci dev_err(&client->dev, "Unable to open firmware %s\n", fw_file); 83262306a36Sopenharmony_ci goto out_free_fw_file; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci disable_irq(client->irq); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci error = raydium_i2c_do_update_firmware(ts, fw); 83862306a36Sopenharmony_ci if (error) { 83962306a36Sopenharmony_ci dev_err(&client->dev, "firmware update failed: %d\n", error); 84062306a36Sopenharmony_ci ts->boot_mode = RAYDIUM_TS_BLDR; 84162306a36Sopenharmony_ci goto out_enable_irq; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci error = raydium_i2c_initialize(ts); 84562306a36Sopenharmony_ci if (error) { 84662306a36Sopenharmony_ci dev_err(&client->dev, 84762306a36Sopenharmony_ci "failed to initialize device after firmware update: %d\n", 84862306a36Sopenharmony_ci error); 84962306a36Sopenharmony_ci ts->boot_mode = RAYDIUM_TS_BLDR; 85062306a36Sopenharmony_ci goto out_enable_irq; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci ts->boot_mode = RAYDIUM_TS_MAIN; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ciout_enable_irq: 85662306a36Sopenharmony_ci enable_irq(client->irq); 85762306a36Sopenharmony_ci msleep(100); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci release_firmware(fw); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ciout_free_fw_file: 86262306a36Sopenharmony_ci kfree(fw_file); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci return error; 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic void raydium_mt_event(struct raydium_data *ts) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci int i; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci for (i = 0; i < ts->report_size / ts->contact_size; i++) { 87262306a36Sopenharmony_ci u8 *contact = &ts->report_data[ts->contact_size * i]; 87362306a36Sopenharmony_ci bool state = contact[RM_CONTACT_STATE_POS]; 87462306a36Sopenharmony_ci u8 wx, wy; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci input_mt_slot(ts->input, i); 87762306a36Sopenharmony_ci input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, state); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (!state) 88062306a36Sopenharmony_ci continue; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_POSITION_X, 88362306a36Sopenharmony_ci get_unaligned_le16(&contact[RM_CONTACT_X_POS])); 88462306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_POSITION_Y, 88562306a36Sopenharmony_ci get_unaligned_le16(&contact[RM_CONTACT_Y_POS])); 88662306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_PRESSURE, 88762306a36Sopenharmony_ci contact[RM_CONTACT_PRESSURE_POS]); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci wx = contact[RM_CONTACT_WIDTH_X_POS]; 89062306a36Sopenharmony_ci wy = contact[RM_CONTACT_WIDTH_Y_POS]; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, max(wx, wy)); 89362306a36Sopenharmony_ci input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, min(wx, wy)); 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci input_mt_sync_frame(ts->input); 89762306a36Sopenharmony_ci input_sync(ts->input); 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cistatic irqreturn_t raydium_i2c_irq(int irq, void *_dev) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci struct raydium_data *ts = _dev; 90362306a36Sopenharmony_ci int error; 90462306a36Sopenharmony_ci u16 fw_crc; 90562306a36Sopenharmony_ci u16 calc_crc; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (ts->boot_mode != RAYDIUM_TS_MAIN) 90862306a36Sopenharmony_ci goto out; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci error = raydium_i2c_read(ts->client, ts->data_bank_addr, 91162306a36Sopenharmony_ci ts->report_data, ts->pkg_size); 91262306a36Sopenharmony_ci if (error) 91362306a36Sopenharmony_ci goto out; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci fw_crc = get_unaligned_le16(&ts->report_data[ts->report_size]); 91662306a36Sopenharmony_ci calc_crc = raydium_calc_chksum(ts->report_data, ts->report_size); 91762306a36Sopenharmony_ci if (unlikely(fw_crc != calc_crc)) { 91862306a36Sopenharmony_ci dev_warn(&ts->client->dev, 91962306a36Sopenharmony_ci "%s: invalid packet crc %#04x vs %#04x\n", 92062306a36Sopenharmony_ci __func__, calc_crc, fw_crc); 92162306a36Sopenharmony_ci goto out; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci raydium_mt_event(ts); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ciout: 92762306a36Sopenharmony_ci return IRQ_HANDLED; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic ssize_t raydium_i2c_fw_ver_show(struct device *dev, 93162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 93462306a36Sopenharmony_ci struct raydium_data *ts = i2c_get_clientdata(client); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci return sprintf(buf, "%d.%d\n", ts->info.main_ver, ts->info.sub_ver); 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic ssize_t raydium_i2c_hw_ver_show(struct device *dev, 94062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 94362306a36Sopenharmony_ci struct raydium_data *ts = i2c_get_clientdata(client); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci return sprintf(buf, "%#04x\n", le32_to_cpu(ts->info.hw_ver)); 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic ssize_t raydium_i2c_boot_mode_show(struct device *dev, 94962306a36Sopenharmony_ci struct device_attribute *attr, 95062306a36Sopenharmony_ci char *buf) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 95362306a36Sopenharmony_ci struct raydium_data *ts = i2c_get_clientdata(client); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci return sprintf(buf, "%s\n", 95662306a36Sopenharmony_ci ts->boot_mode == RAYDIUM_TS_MAIN ? 95762306a36Sopenharmony_ci "Normal" : "Recovery"); 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic ssize_t raydium_i2c_update_fw_store(struct device *dev, 96162306a36Sopenharmony_ci struct device_attribute *attr, 96262306a36Sopenharmony_ci const char *buf, size_t count) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 96562306a36Sopenharmony_ci struct raydium_data *ts = i2c_get_clientdata(client); 96662306a36Sopenharmony_ci int error; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci error = mutex_lock_interruptible(&ts->sysfs_mutex); 96962306a36Sopenharmony_ci if (error) 97062306a36Sopenharmony_ci return error; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci error = raydium_i2c_fw_update(ts); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci mutex_unlock(&ts->sysfs_mutex); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci return error ?: count; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic ssize_t raydium_i2c_calibrate_store(struct device *dev, 98062306a36Sopenharmony_ci struct device_attribute *attr, 98162306a36Sopenharmony_ci const char *buf, size_t count) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 98462306a36Sopenharmony_ci struct raydium_data *ts = i2c_get_clientdata(client); 98562306a36Sopenharmony_ci static const u8 cal_cmd[] = { 0x00, 0x01, 0x9E }; 98662306a36Sopenharmony_ci int error; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci error = mutex_lock_interruptible(&ts->sysfs_mutex); 98962306a36Sopenharmony_ci if (error) 99062306a36Sopenharmony_ci return error; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd), 99362306a36Sopenharmony_ci RAYDIUM_WAIT_READY); 99462306a36Sopenharmony_ci if (error) 99562306a36Sopenharmony_ci dev_err(&client->dev, "calibrate command failed: %d\n", error); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci mutex_unlock(&ts->sysfs_mutex); 99862306a36Sopenharmony_ci return error ?: count; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic DEVICE_ATTR(fw_version, S_IRUGO, raydium_i2c_fw_ver_show, NULL); 100262306a36Sopenharmony_cistatic DEVICE_ATTR(hw_version, S_IRUGO, raydium_i2c_hw_ver_show, NULL); 100362306a36Sopenharmony_cistatic DEVICE_ATTR(boot_mode, S_IRUGO, raydium_i2c_boot_mode_show, NULL); 100462306a36Sopenharmony_cistatic DEVICE_ATTR(update_fw, S_IWUSR, NULL, raydium_i2c_update_fw_store); 100562306a36Sopenharmony_cistatic DEVICE_ATTR(calibrate, S_IWUSR, NULL, raydium_i2c_calibrate_store); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_cistatic struct attribute *raydium_i2c_attributes[] = { 100862306a36Sopenharmony_ci &dev_attr_update_fw.attr, 100962306a36Sopenharmony_ci &dev_attr_boot_mode.attr, 101062306a36Sopenharmony_ci &dev_attr_fw_version.attr, 101162306a36Sopenharmony_ci &dev_attr_hw_version.attr, 101262306a36Sopenharmony_ci &dev_attr_calibrate.attr, 101362306a36Sopenharmony_ci NULL 101462306a36Sopenharmony_ci}; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic const struct attribute_group raydium_i2c_attribute_group = { 101762306a36Sopenharmony_ci .attrs = raydium_i2c_attributes, 101862306a36Sopenharmony_ci}; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_cistatic int raydium_i2c_power_on(struct raydium_data *ts) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci int error; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (!ts->reset_gpio) 102562306a36Sopenharmony_ci return 0; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci gpiod_set_value_cansleep(ts->reset_gpio, 1); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci error = regulator_enable(ts->avdd); 103062306a36Sopenharmony_ci if (error) { 103162306a36Sopenharmony_ci dev_err(&ts->client->dev, 103262306a36Sopenharmony_ci "failed to enable avdd regulator: %d\n", error); 103362306a36Sopenharmony_ci goto release_reset_gpio; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci error = regulator_enable(ts->vccio); 103762306a36Sopenharmony_ci if (error) { 103862306a36Sopenharmony_ci regulator_disable(ts->avdd); 103962306a36Sopenharmony_ci dev_err(&ts->client->dev, 104062306a36Sopenharmony_ci "failed to enable vccio regulator: %d\n", error); 104162306a36Sopenharmony_ci goto release_reset_gpio; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci udelay(RM_POWERON_DELAY_USEC); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cirelease_reset_gpio: 104762306a36Sopenharmony_ci gpiod_set_value_cansleep(ts->reset_gpio, 0); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (error) 105062306a36Sopenharmony_ci return error; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci msleep(RM_RESET_DELAY_MSEC); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci return 0; 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic void raydium_i2c_power_off(void *_data) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct raydium_data *ts = _data; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (ts->reset_gpio) { 106262306a36Sopenharmony_ci gpiod_set_value_cansleep(ts->reset_gpio, 1); 106362306a36Sopenharmony_ci regulator_disable(ts->vccio); 106462306a36Sopenharmony_ci regulator_disable(ts->avdd); 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic int raydium_i2c_probe(struct i2c_client *client) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci union i2c_smbus_data dummy; 107162306a36Sopenharmony_ci struct raydium_data *ts; 107262306a36Sopenharmony_ci int error; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 107562306a36Sopenharmony_ci dev_err(&client->dev, 107662306a36Sopenharmony_ci "i2c check functionality error (need I2C_FUNC_I2C)\n"); 107762306a36Sopenharmony_ci return -ENXIO; 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); 108162306a36Sopenharmony_ci if (!ts) 108262306a36Sopenharmony_ci return -ENOMEM; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci mutex_init(&ts->sysfs_mutex); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci ts->client = client; 108762306a36Sopenharmony_ci i2c_set_clientdata(client, ts); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci ts->avdd = devm_regulator_get(&client->dev, "avdd"); 109062306a36Sopenharmony_ci if (IS_ERR(ts->avdd)) 109162306a36Sopenharmony_ci return dev_err_probe(&client->dev, PTR_ERR(ts->avdd), 109262306a36Sopenharmony_ci "Failed to get 'avdd' regulator\n"); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci ts->vccio = devm_regulator_get(&client->dev, "vccio"); 109562306a36Sopenharmony_ci if (IS_ERR(ts->vccio)) 109662306a36Sopenharmony_ci return dev_err_probe(&client->dev, PTR_ERR(ts->vccio), 109762306a36Sopenharmony_ci "Failed to get 'vccio' regulator\n"); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", 110062306a36Sopenharmony_ci GPIOD_OUT_LOW); 110162306a36Sopenharmony_ci if (IS_ERR(ts->reset_gpio)) 110262306a36Sopenharmony_ci return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio), 110362306a36Sopenharmony_ci "Failed to get reset gpio\n"); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci error = raydium_i2c_power_on(ts); 110662306a36Sopenharmony_ci if (error) 110762306a36Sopenharmony_ci return error; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci error = devm_add_action_or_reset(&client->dev, 111062306a36Sopenharmony_ci raydium_i2c_power_off, ts); 111162306a36Sopenharmony_ci if (error) { 111262306a36Sopenharmony_ci dev_err(&client->dev, 111362306a36Sopenharmony_ci "failed to install power off action: %d\n", error); 111462306a36Sopenharmony_ci return error; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* Make sure there is something at this address */ 111862306a36Sopenharmony_ci if (i2c_smbus_xfer(client->adapter, client->addr, 0, 111962306a36Sopenharmony_ci I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { 112062306a36Sopenharmony_ci dev_err(&client->dev, "nothing at this address\n"); 112162306a36Sopenharmony_ci return -ENXIO; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci error = raydium_i2c_initialize(ts); 112562306a36Sopenharmony_ci if (error) { 112662306a36Sopenharmony_ci dev_err(&client->dev, "failed to initialize: %d\n", error); 112762306a36Sopenharmony_ci return error; 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci ts->report_data = devm_kmalloc(&client->dev, 113162306a36Sopenharmony_ci ts->pkg_size, GFP_KERNEL); 113262306a36Sopenharmony_ci if (!ts->report_data) 113362306a36Sopenharmony_ci return -ENOMEM; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci ts->input = devm_input_allocate_device(&client->dev); 113662306a36Sopenharmony_ci if (!ts->input) { 113762306a36Sopenharmony_ci dev_err(&client->dev, "Failed to allocate input device\n"); 113862306a36Sopenharmony_ci return -ENOMEM; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci ts->input->name = "Raydium Touchscreen"; 114262306a36Sopenharmony_ci ts->input->id.bustype = BUS_I2C; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci input_set_abs_params(ts->input, ABS_MT_POSITION_X, 114562306a36Sopenharmony_ci 0, le16_to_cpu(ts->info.x_max), 0, 0); 114662306a36Sopenharmony_ci input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 114762306a36Sopenharmony_ci 0, le16_to_cpu(ts->info.y_max), 0, 0); 114862306a36Sopenharmony_ci input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->info.x_res); 114962306a36Sopenharmony_ci input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->info.y_res); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); 115262306a36Sopenharmony_ci input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci error = input_mt_init_slots(ts->input, RM_MAX_TOUCH_NUM, 115562306a36Sopenharmony_ci INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 115662306a36Sopenharmony_ci if (error) { 115762306a36Sopenharmony_ci dev_err(&client->dev, 115862306a36Sopenharmony_ci "failed to initialize MT slots: %d\n", error); 115962306a36Sopenharmony_ci return error; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci error = input_register_device(ts->input); 116362306a36Sopenharmony_ci if (error) { 116462306a36Sopenharmony_ci dev_err(&client->dev, 116562306a36Sopenharmony_ci "unable to register input device: %d\n", error); 116662306a36Sopenharmony_ci return error; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci error = devm_request_threaded_irq(&client->dev, client->irq, 117062306a36Sopenharmony_ci NULL, raydium_i2c_irq, 117162306a36Sopenharmony_ci IRQF_ONESHOT, client->name, ts); 117262306a36Sopenharmony_ci if (error) { 117362306a36Sopenharmony_ci dev_err(&client->dev, "Failed to register interrupt\n"); 117462306a36Sopenharmony_ci return error; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci error = devm_device_add_group(&client->dev, 117862306a36Sopenharmony_ci &raydium_i2c_attribute_group); 117962306a36Sopenharmony_ci if (error) { 118062306a36Sopenharmony_ci dev_err(&client->dev, "failed to create sysfs attributes: %d\n", 118162306a36Sopenharmony_ci error); 118262306a36Sopenharmony_ci return error; 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci return 0; 118662306a36Sopenharmony_ci} 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_cistatic void raydium_enter_sleep(struct i2c_client *client) 118962306a36Sopenharmony_ci{ 119062306a36Sopenharmony_ci static const u8 sleep_cmd[] = { 0x5A, 0xff, 0x00, 0x0f }; 119162306a36Sopenharmony_ci int error; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci error = raydium_i2c_send(client, RM_CMD_ENTER_SLEEP, 119462306a36Sopenharmony_ci sleep_cmd, sizeof(sleep_cmd)); 119562306a36Sopenharmony_ci if (error) 119662306a36Sopenharmony_ci dev_err(&client->dev, 119762306a36Sopenharmony_ci "sleep command failed: %d\n", error); 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic int raydium_i2c_suspend(struct device *dev) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 120362306a36Sopenharmony_ci struct raydium_data *ts = i2c_get_clientdata(client); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci /* Sleep is not available in BLDR recovery mode */ 120662306a36Sopenharmony_ci if (ts->boot_mode != RAYDIUM_TS_MAIN) 120762306a36Sopenharmony_ci return -EBUSY; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci disable_irq(client->irq); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (device_may_wakeup(dev)) { 121262306a36Sopenharmony_ci raydium_enter_sleep(client); 121362306a36Sopenharmony_ci } else { 121462306a36Sopenharmony_ci raydium_i2c_power_off(ts); 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci return 0; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_cistatic int raydium_i2c_resume(struct device *dev) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 122362306a36Sopenharmony_ci struct raydium_data *ts = i2c_get_clientdata(client); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci if (device_may_wakeup(dev)) { 122662306a36Sopenharmony_ci raydium_i2c_sw_reset(client); 122762306a36Sopenharmony_ci } else { 122862306a36Sopenharmony_ci raydium_i2c_power_on(ts); 122962306a36Sopenharmony_ci raydium_i2c_initialize(ts); 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci enable_irq(client->irq); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci return 0; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops, 123862306a36Sopenharmony_ci raydium_i2c_suspend, raydium_i2c_resume); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_cistatic const struct i2c_device_id raydium_i2c_id[] = { 124162306a36Sopenharmony_ci { "raydium_i2c", 0 }, 124262306a36Sopenharmony_ci { "rm32380", 0 }, 124362306a36Sopenharmony_ci { /* sentinel */ } 124462306a36Sopenharmony_ci}; 124562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, raydium_i2c_id); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci#ifdef CONFIG_ACPI 124862306a36Sopenharmony_cistatic const struct acpi_device_id raydium_acpi_id[] = { 124962306a36Sopenharmony_ci { "RAYD0001", 0 }, 125062306a36Sopenharmony_ci { /* sentinel */ } 125162306a36Sopenharmony_ci}; 125262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, raydium_acpi_id); 125362306a36Sopenharmony_ci#endif 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci#ifdef CONFIG_OF 125662306a36Sopenharmony_cistatic const struct of_device_id raydium_of_match[] = { 125762306a36Sopenharmony_ci { .compatible = "raydium,rm32380", }, 125862306a36Sopenharmony_ci { /* sentinel */ } 125962306a36Sopenharmony_ci}; 126062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, raydium_of_match); 126162306a36Sopenharmony_ci#endif 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_cistatic struct i2c_driver raydium_i2c_driver = { 126462306a36Sopenharmony_ci .probe = raydium_i2c_probe, 126562306a36Sopenharmony_ci .id_table = raydium_i2c_id, 126662306a36Sopenharmony_ci .driver = { 126762306a36Sopenharmony_ci .name = "raydium_ts", 126862306a36Sopenharmony_ci .pm = pm_sleep_ptr(&raydium_i2c_pm_ops), 126962306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(raydium_acpi_id), 127062306a36Sopenharmony_ci .of_match_table = of_match_ptr(raydium_of_match), 127162306a36Sopenharmony_ci }, 127262306a36Sopenharmony_ci}; 127362306a36Sopenharmony_cimodule_i2c_driver(raydium_i2c_driver); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ciMODULE_AUTHOR("Raydium"); 127662306a36Sopenharmony_ciMODULE_DESCRIPTION("Raydium I2c Touchscreen driver"); 127762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1278