// 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 <linux/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_WORK_MODE 0x081e#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.len) + sizeof(packet->header.addr), .buf = &packet->header.len, }, { .addr = ts->client->addr, .flags = I2C_M_RD, .len = len, .buf = (u8 *)data, }, }; int ret; if (len > HIDEEP_NVM_PAGE_SIZE) return -EINVAL; packet->header.len = count - 1; packet->header.addr = cpu_to_be32(addr); ret = i2c_transfer(ts->client->adapter, msg, ARRAY_SIZE(msg)); if (ret != ARRAY_SIZE(msg)) return ret < 0 ? ret : -EIO; return 0;} static int hideep_pgm_r_reg(struct hideep_ts *ts, u32 addr, u32 *val){ __be32 data; int error; error = hideep_pgm_r_mem(ts, addr, &data, 1); if (error) { dev_err(&ts->client->dev, "read of register %#08x failed: %d\n", addr, error); return error; } *val = be32_to_cpu(data); return 0;} static int hideep_pgm_w_reg(struct hideep_ts *ts, u32 addr, u32 val){ __be32 data = cpu_to_be32(val); int error; error = hideep_pgm_w_mem(ts, addr, &data, 1); if (error) { dev_err(&ts->client->dev, "write to register %#08x (%#08x) failed: %d\n", addr, val, error); return error; } return 0;} #define SW_RESET_IN_PGM(clk) \{ \ __be32 data = cpu_to_be32(0x01); \ hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CNT, (clk)); \ hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x03); \ /* \ * The first write may already cause a reset, use a raw \ * write for the second write to avoid error logging. \ */ \ hideep_pgm_w_mem(ts, HIDEEP_SYSCON_WDT_CON, &data, 1); \} #define SET_FLASH_PIO(ce) \ hideep_pgm_w_reg(ts, HIDEEP_FLASH_CON, \ 0x01 | ((ce) << 1)) #define SET_PIO_SIG(x, y) \ hideep_pgm_w_reg(ts, HIDEEP_FLASH_PIO_SIG + (x), (y)) #define SET_FLASH_HWCONTROL() \ hideep_pgm_w_reg(ts, HIDEEP_FLASH_CON, 0x00) #define NVM_W_SFR(x, y) \{ \ SET_FLASH_PIO(1); \ SET_PIO_SIG(x, y); \ SET_FLASH_PIO(0); \} static void hideep_pgm_set(struct hideep_ts *ts){ hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x00); hideep_pgm_w_reg(ts, HIDEEP_SYSCON_SPC_CON, 0x00); hideep_pgm_w_reg(ts, HIDEEP_SYSCON_CLK_ENA, 0xFF); hideep_pgm_w_reg(ts, HIDEEP_SYSCON_CLK_CON, 0x01); hideep_pgm_w_reg(ts, HIDEEP_SYSCON_PWR_CON, 0x01); hideep_pgm_w_reg(ts, HIDEEP_FLASH_TIM, 0x03); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CACHE_CFG, 0x00);} static int hideep_pgm_get_pattern(struct hideep_ts *ts, u32 *pattern){ u16 p1 = 0xAF39; u16 p2 = 0xDF9D; int error; error = regmap_bulk_write(ts->reg, p1, &p2, 1); if (error) { dev_err(&ts->client->dev, "%s: regmap_bulk_write() failed with %d\n", __func__, error); return error; } usleep_range(1000, 1100); /* flush invalid Tx load register */ error = hideep_pgm_w_reg(ts, HIDEEP_ESI_TX_INVALID, 0x01); if (error) return error; error = hideep_pgm_r_reg(ts, HIDEEP_SYSCON_PGM_ID, pattern); if (error) return error; return 0;} static int hideep_enter_pgm(struct hideep_ts *ts){ int retry_count = 10; u32 pattern; int error; while (retry_count--) { error = hideep_pgm_get_pattern(ts, &pattern); if (error) { dev_err(&ts->client->dev, "hideep_pgm_get_pattern failed: %d\n", error); } else if (pattern != 0x39AF9DDF) { dev_err(&ts->client->dev, "%s: bad pattern: %#08x\n", __func__, pattern); } else { dev_dbg(&ts->client->dev, "found magic code"); hideep_pgm_set(ts); usleep_range(1000, 1100); return 0; } } dev_err(&ts->client->dev, "failed to enter pgm mode\n"); SW_RESET_IN_PGM(1000); return -EIO;} static int hideep_nvm_unlock(struct hideep_ts *ts){ u32 unmask_code; int error; hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_SFR_RPAGE); error = hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE); if (error) return error; /* make it unprotected code */ unmask_code &= ~HIDEEP_PROT_MODE; /* compare unmask code */ if (unmask_code != ts->nvm_mask) dev_warn(&ts->client->dev, "read mask code different %#08x vs %#08x", unmask_code, ts->nvm_mask); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_SFR_WPAGE); SET_FLASH_PIO(0); NVM_W_SFR(HIDEEP_NVM_MASK_OFS, ts->nvm_mask); SET_FLASH_HWCONTROL(); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE); return 0;} static int hideep_check_status(struct hideep_ts *ts){ int time_out = 100; int status; int error; while (time_out--) { error = hideep_pgm_r_reg(ts, HIDEEP_FLASH_STA, &status); if (!error && status) return 0; usleep_range(1000, 1100); } return -ETIMEDOUT;} static int hideep_program_page(struct hideep_ts *ts, u32 addr, const __be32 *ucode, size_t xfer_count){ u32 val; int error; error = hideep_check_status(ts); if (error) return -EBUSY; addr &= ~(HIDEEP_NVM_PAGE_SIZE - 1); SET_FLASH_PIO(0); SET_FLASH_PIO(1); /* erase page */ SET_PIO_SIG(HIDEEP_PERASE | addr, 0xFFFFFFFF); SET_FLASH_PIO(0); error = hideep_check_status(ts); if (error) return -EBUSY; /* write page */ SET_FLASH_PIO(1); val = be32_to_cpu(ucode[0]); SET_PIO_SIG(HIDEEP_WRONLY | addr, val); hideep_pgm_w_mem(ts, HIDEEP_FLASH_PIO_SIG | HIDEEP_WRONLY, ucode, xfer_count); val = be32_to_cpu(ucode[xfer_count - 1]); SET_PIO_SIG(124, val); SET_FLASH_PIO(0); usleep_range(1000, 1100); error = hideep_check_status(ts); if (error) return -EBUSY; SET_FLASH_HWCONTROL(); return 0;} static int hideep_program_nvm(struct hideep_ts *ts, const __be32 *ucode, size_t ucode_len){ struct pgm_packet *packet_r = (void *)ts->xfer_buf; __be32 *current_ucode = packet_r->payload; size_t xfer_len; size_t xfer_count; u32 addr = 0; int error; error = hideep_nvm_unlock(ts); if (error) return error; while (ucode_len > 0) { xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE); xfer_count = xfer_len / sizeof(*ucode); error = hideep_pgm_r_mem(ts, 0x00000000 + addr, current_ucode, xfer_count); if (error) { dev_err(&ts->client->dev, "%s: failed to read page at offset %#08x: %d\n", __func__, addr, error); return error; } /* See if the page needs updating */ if (memcmp(ucode, current_ucode, xfer_len)) { error = hideep_program_page(ts, addr, ucode, xfer_count); if (error) { dev_err(&ts->client->dev, "%s: iwrite failure @%#08x: %d\n", __func__, addr, error);Lines 1–500 of 1121. Load more
// 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 <linux/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_WORK_MODE 0x081e #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.len) + sizeof(packet->header.addr), .buf = &packet->header.len, }, { .addr = ts->client->addr, .flags = I2C_M_RD, .len = len, .buf = (u8 *)data, }, }; int ret; if (len > HIDEEP_NVM_PAGE_SIZE) return -EINVAL; packet->header.len = count - 1; packet->header.addr = cpu_to_be32(addr); ret = i2c_transfer(ts->client->adapter, msg, ARRAY_SIZE(msg)); if (ret != ARRAY_SIZE(msg)) return ret < 0 ? ret : -EIO; return 0; } static int hideep_pgm_r_reg(struct hideep_ts *ts, u32 addr, u32 *val) { __be32 data; int error; error = hideep_pgm_r_mem(ts, addr, &data, 1); if (error) { dev_err(&ts->client->dev, "read of register %#08x failed: %d\n", addr, error); return error; } *val = be32_to_cpu(data); return 0; } static int hideep_pgm_w_reg(struct hideep_ts *ts, u32 addr, u32 val) { __be32 data = cpu_to_be32(val); int error; error = hideep_pgm_w_mem(ts, addr, &data, 1); if (error) { dev_err(&ts->client->dev, "write to register %#08x (%#08x) failed: %d\n", addr, val, error); return error; } return 0; } #define SW_RESET_IN_PGM(clk) \ { \ __be32 data = cpu_to_be32(0x01); \ hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CNT, (clk)); \ hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x03); \ /* \ * The first write may already cause a reset, use a raw \ * write for the second write to avoid error logging. \ */ \ hideep_pgm_w_mem(ts, HIDEEP_SYSCON_WDT_CON, &data, 1); \ } #define SET_FLASH_PIO(ce) \ hideep_pgm_w_reg(ts, HIDEEP_FLASH_CON, \ 0x01 | ((ce) << 1)) #define SET_PIO_SIG(x, y) \ hideep_pgm_w_reg(ts, HIDEEP_FLASH_PIO_SIG + (x), (y)) #define SET_FLASH_HWCONTROL() \ hideep_pgm_w_reg(ts, HIDEEP_FLASH_CON, 0x00) #define NVM_W_SFR(x, y) \ { \ SET_FLASH_PIO(1); \ SET_PIO_SIG(x, y); \ SET_FLASH_PIO(0); \ } static void hideep_pgm_set(struct hideep_ts *ts) { hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x00); hideep_pgm_w_reg(ts, HIDEEP_SYSCON_SPC_CON, 0x00); hideep_pgm_w_reg(ts, HIDEEP_SYSCON_CLK_ENA, 0xFF); hideep_pgm_w_reg(ts, HIDEEP_SYSCON_CLK_CON, 0x01); hideep_pgm_w_reg(ts, HIDEEP_SYSCON_PWR_CON, 0x01); hideep_pgm_w_reg(ts, HIDEEP_FLASH_TIM, 0x03); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CACHE_CFG, 0x00); } static int hideep_pgm_get_pattern(struct hideep_ts *ts, u32 *pattern) { u16 p1 = 0xAF39; u16 p2 = 0xDF9D; int error; error = regmap_bulk_write(ts->reg, p1, &p2, 1); if (error) { dev_err(&ts->client->dev, "%s: regmap_bulk_write() failed with %d\n", __func__, error); return error; } usleep_range(1000, 1100); /* flush invalid Tx load register */ error = hideep_pgm_w_reg(ts, HIDEEP_ESI_TX_INVALID, 0x01); if (error) return error; error = hideep_pgm_r_reg(ts, HIDEEP_SYSCON_PGM_ID, pattern); if (error) return error; return 0; } static int hideep_enter_pgm(struct hideep_ts *ts) { int retry_count = 10; u32 pattern; int error; while (retry_count--) { error = hideep_pgm_get_pattern(ts, &pattern); if (error) { dev_err(&ts->client->dev, "hideep_pgm_get_pattern failed: %d\n", error); } else if (pattern != 0x39AF9DDF) { dev_err(&ts->client->dev, "%s: bad pattern: %#08x\n", __func__, pattern); } else { dev_dbg(&ts->client->dev, "found magic code"); hideep_pgm_set(ts); usleep_range(1000, 1100); return 0; } } dev_err(&ts->client->dev, "failed to enter pgm mode\n"); SW_RESET_IN_PGM(1000); return -EIO; } static int hideep_nvm_unlock(struct hideep_ts *ts) { u32 unmask_code; int error; hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_SFR_RPAGE); error = hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE); if (error) return error; /* make it unprotected code */ unmask_code &= ~HIDEEP_PROT_MODE; /* compare unmask code */ if (unmask_code != ts->nvm_mask) dev_warn(&ts->client->dev, "read mask code different %#08x vs %#08x", unmask_code, ts->nvm_mask); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_SFR_WPAGE); SET_FLASH_PIO(0); NVM_W_SFR(HIDEEP_NVM_MASK_OFS, ts->nvm_mask); SET_FLASH_HWCONTROL(); hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE); return 0; } static int hideep_check_status(struct hideep_ts *ts) { int time_out = 100; int status; int error; while (time_out--) { error = hideep_pgm_r_reg(ts, HIDEEP_FLASH_STA, &status); if (!error && status) return 0; usleep_range(1000, 1100); } return -ETIMEDOUT; } static int hideep_program_page(struct hideep_ts *ts, u32 addr, const __be32 *ucode, size_t xfer_count) { u32 val; int error; error = hideep_check_status(ts); if (error) return -EBUSY; addr &= ~(HIDEEP_NVM_PAGE_SIZE - 1); SET_FLASH_PIO(0); SET_FLASH_PIO(1); /* erase page */ SET_PIO_SIG(HIDEEP_PERASE | addr, 0xFFFFFFFF); SET_FLASH_PIO(0); error = hideep_check_status(ts); if (error) return -EBUSY; /* write page */ SET_FLASH_PIO(1); val = be32_to_cpu(ucode[0]); SET_PIO_SIG(HIDEEP_WRONLY | addr, val); hideep_pgm_w_mem(ts, HIDEEP_FLASH_PIO_SIG | HIDEEP_WRONLY, ucode, xfer_count); val = be32_to_cpu(ucode[xfer_count - 1]); SET_PIO_SIG(124, val); SET_FLASH_PIO(0); usleep_range(1000, 1100); error = hideep_check_status(ts); if (error) return -EBUSY; SET_FLASH_HWCONTROL(); return 0; } static int hideep_program_nvm(struct hideep_ts *ts, const __be32 *ucode, size_t ucode_len) { struct pgm_packet *packet_r = (void *)ts->xfer_buf; __be32 *current_ucode = packet_r->payload; size_t xfer_len; size_t xfer_count; u32 addr = 0; int error; error = hideep_nvm_unlock(ts); if (error) return error; while (ucode_len > 0) { xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE); xfer_count = xfer_len / sizeof(*ucode); error = hideep_pgm_r_mem(ts, 0x00000000 + addr, current_ucode, xfer_count); if (error) { dev_err(&ts->client->dev, "%s: failed to read page at offset %#08x: %d\n", __func__, addr, error); return error; } /* See if the page needs updating */ if (memcmp(ucode, current_ucode, xfer_len)) { error = hideep_program_page(ts, addr, ucode, xfer_count); if (error) { dev_err(&ts->client->dev, "%s: iwrite failure @%#08x: %d\n", __func__, addr, error);