1*48a2b783SJeffrey Lin /* 2*48a2b783SJeffrey Lin * Raydium touchscreen I2C driver. 3*48a2b783SJeffrey Lin * 4*48a2b783SJeffrey Lin * Copyright (C) 2012-2014, Raydium Semiconductor Corporation. 5*48a2b783SJeffrey Lin * 6*48a2b783SJeffrey Lin * This program is free software; you can redistribute it and/or 7*48a2b783SJeffrey Lin * modify it under the terms of the GNU General Public License 8*48a2b783SJeffrey Lin * version 2, and only version 2, as published by the 9*48a2b783SJeffrey Lin * Free Software Foundation. 10*48a2b783SJeffrey Lin * 11*48a2b783SJeffrey Lin * This program is distributed in the hope that it will be useful, 12*48a2b783SJeffrey Lin * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*48a2b783SJeffrey Lin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*48a2b783SJeffrey Lin * GNU General Public License for more details. 15*48a2b783SJeffrey Lin * 16*48a2b783SJeffrey Lin * Raydium reserves the right to make changes without further notice 17*48a2b783SJeffrey Lin * to the materials described herein. Raydium does not assume any 18*48a2b783SJeffrey Lin * liability arising out of the application described herein. 19*48a2b783SJeffrey Lin * 20*48a2b783SJeffrey Lin * Contact Raydium Semiconductor Corporation at www.rad-ic.com 21*48a2b783SJeffrey Lin */ 22*48a2b783SJeffrey Lin 23*48a2b783SJeffrey Lin #include <linux/acpi.h> 24*48a2b783SJeffrey Lin #include <linux/delay.h> 25*48a2b783SJeffrey Lin #include <linux/firmware.h> 26*48a2b783SJeffrey Lin #include <linux/gpio/consumer.h> 27*48a2b783SJeffrey Lin #include <linux/i2c.h> 28*48a2b783SJeffrey Lin #include <linux/input.h> 29*48a2b783SJeffrey Lin #include <linux/input/mt.h> 30*48a2b783SJeffrey Lin #include <linux/interrupt.h> 31*48a2b783SJeffrey Lin #include <linux/module.h> 32*48a2b783SJeffrey Lin #include <linux/of.h> 33*48a2b783SJeffrey Lin #include <linux/regulator/consumer.h> 34*48a2b783SJeffrey Lin #include <linux/slab.h> 35*48a2b783SJeffrey Lin #include <asm/unaligned.h> 36*48a2b783SJeffrey Lin 37*48a2b783SJeffrey Lin /* Slave I2C mode */ 38*48a2b783SJeffrey Lin #define RM_BOOT_BLDR 0x02 39*48a2b783SJeffrey Lin #define RM_BOOT_MAIN 0x03 40*48a2b783SJeffrey Lin 41*48a2b783SJeffrey Lin /* I2C bootoloader commands */ 42*48a2b783SJeffrey Lin #define RM_CMD_BOOT_PAGE_WRT 0x0B /* send bl page write */ 43*48a2b783SJeffrey Lin #define RM_CMD_BOOT_WRT 0x11 /* send bl write */ 44*48a2b783SJeffrey Lin #define RM_CMD_BOOT_ACK 0x22 /* send ack*/ 45*48a2b783SJeffrey Lin #define RM_CMD_BOOT_CHK 0x33 /* send data check */ 46*48a2b783SJeffrey Lin #define RM_CMD_BOOT_READ 0x44 /* send wait bl data ready*/ 47*48a2b783SJeffrey Lin 48*48a2b783SJeffrey Lin #define RM_BOOT_RDY 0xFF /* bl data ready */ 49*48a2b783SJeffrey Lin 50*48a2b783SJeffrey Lin /* I2C main commands */ 51*48a2b783SJeffrey Lin #define RM_CMD_QUERY_BANK 0x2B 52*48a2b783SJeffrey Lin #define RM_CMD_DATA_BANK 0x4D 53*48a2b783SJeffrey Lin #define RM_CMD_ENTER_SLEEP 0x4E 54*48a2b783SJeffrey Lin #define RM_CMD_BANK_SWITCH 0xAA 55*48a2b783SJeffrey Lin 56*48a2b783SJeffrey Lin #define RM_RESET_MSG_ADDR 0x40000004 57*48a2b783SJeffrey Lin 58*48a2b783SJeffrey Lin #define RM_MAX_READ_SIZE 56 59*48a2b783SJeffrey Lin 60*48a2b783SJeffrey Lin /* Touch relative info */ 61*48a2b783SJeffrey Lin #define RM_MAX_RETRIES 3 62*48a2b783SJeffrey Lin #define RM_MAX_TOUCH_NUM 10 63*48a2b783SJeffrey Lin #define RM_BOOT_DELAY_MS 100 64*48a2b783SJeffrey Lin 65*48a2b783SJeffrey Lin /* Offsets in contact data */ 66*48a2b783SJeffrey Lin #define RM_CONTACT_STATE_POS 0 67*48a2b783SJeffrey Lin #define RM_CONTACT_X_POS 1 68*48a2b783SJeffrey Lin #define RM_CONTACT_Y_POS 3 69*48a2b783SJeffrey Lin #define RM_CONTACT_PRESSURE_POS 5 70*48a2b783SJeffrey Lin #define RM_CONTACT_WIDTH_X_POS 6 71*48a2b783SJeffrey Lin #define RM_CONTACT_WIDTH_Y_POS 7 72*48a2b783SJeffrey Lin 73*48a2b783SJeffrey Lin /* Bootloader relative info */ 74*48a2b783SJeffrey Lin #define RM_BL_WRT_CMD_SIZE 3 /* bl flash wrt cmd size */ 75*48a2b783SJeffrey Lin #define RM_BL_WRT_PKG_SIZE 32 /* bl wrt pkg size */ 76*48a2b783SJeffrey Lin #define RM_BL_WRT_LEN (RM_BL_WRT_PKG_SIZE + RM_BL_WRT_CMD_SIZE) 77*48a2b783SJeffrey Lin #define RM_FW_PAGE_SIZE 128 78*48a2b783SJeffrey Lin #define RM_MAX_FW_RETRIES 30 79*48a2b783SJeffrey Lin #define RM_MAX_FW_SIZE 0xD000 80*48a2b783SJeffrey Lin 81*48a2b783SJeffrey Lin #define RM_POWERON_DELAY_USEC 500 82*48a2b783SJeffrey Lin #define RM_RESET_DELAY_MSEC 50 83*48a2b783SJeffrey Lin 84*48a2b783SJeffrey Lin enum raydium_bl_cmd { 85*48a2b783SJeffrey Lin BL_HEADER = 0, 86*48a2b783SJeffrey Lin BL_PAGE_STR, 87*48a2b783SJeffrey Lin BL_PKG_IDX, 88*48a2b783SJeffrey Lin BL_DATA_STR, 89*48a2b783SJeffrey Lin }; 90*48a2b783SJeffrey Lin 91*48a2b783SJeffrey Lin enum raydium_bl_ack { 92*48a2b783SJeffrey Lin RAYDIUM_ACK_NULL = 0, 93*48a2b783SJeffrey Lin RAYDIUM_WAIT_READY, 94*48a2b783SJeffrey Lin RAYDIUM_PATH_READY, 95*48a2b783SJeffrey Lin }; 96*48a2b783SJeffrey Lin 97*48a2b783SJeffrey Lin enum raydium_boot_mode { 98*48a2b783SJeffrey Lin RAYDIUM_TS_MAIN = 0, 99*48a2b783SJeffrey Lin RAYDIUM_TS_BLDR, 100*48a2b783SJeffrey Lin }; 101*48a2b783SJeffrey Lin 102*48a2b783SJeffrey Lin /* Response to RM_CMD_DATA_BANK request */ 103*48a2b783SJeffrey Lin struct raydium_data_info { 104*48a2b783SJeffrey Lin __le32 data_bank_addr; 105*48a2b783SJeffrey Lin u8 pkg_size; 106*48a2b783SJeffrey Lin u8 tp_info_size; 107*48a2b783SJeffrey Lin }; 108*48a2b783SJeffrey Lin 109*48a2b783SJeffrey Lin struct raydium_info { 110*48a2b783SJeffrey Lin __le32 hw_ver; /*device version */ 111*48a2b783SJeffrey Lin u8 main_ver; 112*48a2b783SJeffrey Lin u8 sub_ver; 113*48a2b783SJeffrey Lin __le16 ft_ver; /* test version */ 114*48a2b783SJeffrey Lin u8 x_num; 115*48a2b783SJeffrey Lin u8 y_num; 116*48a2b783SJeffrey Lin __le16 x_max; 117*48a2b783SJeffrey Lin __le16 y_max; 118*48a2b783SJeffrey Lin u8 x_res; /* units/mm */ 119*48a2b783SJeffrey Lin u8 y_res; /* units/mm */ 120*48a2b783SJeffrey Lin }; 121*48a2b783SJeffrey Lin 122*48a2b783SJeffrey Lin /* struct raydium_data - represents state of Raydium touchscreen device */ 123*48a2b783SJeffrey Lin struct raydium_data { 124*48a2b783SJeffrey Lin struct i2c_client *client; 125*48a2b783SJeffrey Lin struct input_dev *input; 126*48a2b783SJeffrey Lin 127*48a2b783SJeffrey Lin struct regulator *avdd; 128*48a2b783SJeffrey Lin struct regulator *vccio; 129*48a2b783SJeffrey Lin struct gpio_desc *reset_gpio; 130*48a2b783SJeffrey Lin 131*48a2b783SJeffrey Lin struct raydium_info info; 132*48a2b783SJeffrey Lin 133*48a2b783SJeffrey Lin struct mutex sysfs_mutex; 134*48a2b783SJeffrey Lin 135*48a2b783SJeffrey Lin u8 *report_data; 136*48a2b783SJeffrey Lin 137*48a2b783SJeffrey Lin u32 data_bank_addr; 138*48a2b783SJeffrey Lin u8 report_size; 139*48a2b783SJeffrey Lin u8 contact_size; 140*48a2b783SJeffrey Lin 141*48a2b783SJeffrey Lin enum raydium_boot_mode boot_mode; 142*48a2b783SJeffrey Lin 143*48a2b783SJeffrey Lin bool wake_irq_enabled; 144*48a2b783SJeffrey Lin }; 145*48a2b783SJeffrey Lin 146*48a2b783SJeffrey Lin static int raydium_i2c_send(struct i2c_client *client, 147*48a2b783SJeffrey Lin u8 addr, const void *data, size_t len) 148*48a2b783SJeffrey Lin { 149*48a2b783SJeffrey Lin u8 *buf; 150*48a2b783SJeffrey Lin int tries = 0; 151*48a2b783SJeffrey Lin int ret; 152*48a2b783SJeffrey Lin 153*48a2b783SJeffrey Lin buf = kmalloc(len + 1, GFP_KERNEL); 154*48a2b783SJeffrey Lin if (!buf) 155*48a2b783SJeffrey Lin return -ENOMEM; 156*48a2b783SJeffrey Lin 157*48a2b783SJeffrey Lin buf[0] = addr; 158*48a2b783SJeffrey Lin memcpy(buf + 1, data, len); 159*48a2b783SJeffrey Lin 160*48a2b783SJeffrey Lin do { 161*48a2b783SJeffrey Lin ret = i2c_master_send(client, buf, len + 1); 162*48a2b783SJeffrey Lin if (likely(ret == len + 1)) 163*48a2b783SJeffrey Lin break; 164*48a2b783SJeffrey Lin 165*48a2b783SJeffrey Lin msleep(20); 166*48a2b783SJeffrey Lin } while (++tries < RM_MAX_RETRIES); 167*48a2b783SJeffrey Lin 168*48a2b783SJeffrey Lin kfree(buf); 169*48a2b783SJeffrey Lin 170*48a2b783SJeffrey Lin if (unlikely(ret != len + 1)) { 171*48a2b783SJeffrey Lin if (ret >= 0) 172*48a2b783SJeffrey Lin ret = -EIO; 173*48a2b783SJeffrey Lin dev_err(&client->dev, "%s failed: %d\n", __func__, ret); 174*48a2b783SJeffrey Lin return ret; 175*48a2b783SJeffrey Lin } 176*48a2b783SJeffrey Lin 177*48a2b783SJeffrey Lin return 0; 178*48a2b783SJeffrey Lin } 179*48a2b783SJeffrey Lin 180*48a2b783SJeffrey Lin static int raydium_i2c_read(struct i2c_client *client, 181*48a2b783SJeffrey Lin u8 addr, void *data, size_t len) 182*48a2b783SJeffrey Lin { 183*48a2b783SJeffrey Lin struct i2c_msg xfer[] = { 184*48a2b783SJeffrey Lin { 185*48a2b783SJeffrey Lin .addr = client->addr, 186*48a2b783SJeffrey Lin .len = 1, 187*48a2b783SJeffrey Lin .buf = &addr, 188*48a2b783SJeffrey Lin }, 189*48a2b783SJeffrey Lin { 190*48a2b783SJeffrey Lin .addr = client->addr, 191*48a2b783SJeffrey Lin .flags = I2C_M_RD, 192*48a2b783SJeffrey Lin .len = len, 193*48a2b783SJeffrey Lin .buf = data, 194*48a2b783SJeffrey Lin } 195*48a2b783SJeffrey Lin }; 196*48a2b783SJeffrey Lin int ret; 197*48a2b783SJeffrey Lin 198*48a2b783SJeffrey Lin ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer)); 199*48a2b783SJeffrey Lin if (unlikely(ret != ARRAY_SIZE(xfer))) 200*48a2b783SJeffrey Lin return ret < 0 ? ret : -EIO; 201*48a2b783SJeffrey Lin 202*48a2b783SJeffrey Lin return 0; 203*48a2b783SJeffrey Lin } 204*48a2b783SJeffrey Lin 205*48a2b783SJeffrey Lin static int raydium_i2c_read_message(struct i2c_client *client, 206*48a2b783SJeffrey Lin u32 addr, void *data, size_t len) 207*48a2b783SJeffrey Lin { 208*48a2b783SJeffrey Lin __be32 be_addr; 209*48a2b783SJeffrey Lin size_t xfer_len; 210*48a2b783SJeffrey Lin int error; 211*48a2b783SJeffrey Lin 212*48a2b783SJeffrey Lin while (len) { 213*48a2b783SJeffrey Lin xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE); 214*48a2b783SJeffrey Lin 215*48a2b783SJeffrey Lin be_addr = cpu_to_be32(addr); 216*48a2b783SJeffrey Lin 217*48a2b783SJeffrey Lin error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH, 218*48a2b783SJeffrey Lin &be_addr, sizeof(be_addr)); 219*48a2b783SJeffrey Lin if (!error) 220*48a2b783SJeffrey Lin error = raydium_i2c_read(client, addr & 0xff, 221*48a2b783SJeffrey Lin data, xfer_len); 222*48a2b783SJeffrey Lin if (error) 223*48a2b783SJeffrey Lin return error; 224*48a2b783SJeffrey Lin 225*48a2b783SJeffrey Lin len -= xfer_len; 226*48a2b783SJeffrey Lin data += xfer_len; 227*48a2b783SJeffrey Lin addr += xfer_len; 228*48a2b783SJeffrey Lin } 229*48a2b783SJeffrey Lin 230*48a2b783SJeffrey Lin return 0; 231*48a2b783SJeffrey Lin } 232*48a2b783SJeffrey Lin 233*48a2b783SJeffrey Lin static int raydium_i2c_send_message(struct i2c_client *client, 234*48a2b783SJeffrey Lin u32 addr, const void *data, size_t len) 235*48a2b783SJeffrey Lin { 236*48a2b783SJeffrey Lin __be32 be_addr = cpu_to_be32(addr); 237*48a2b783SJeffrey Lin int error; 238*48a2b783SJeffrey Lin 239*48a2b783SJeffrey Lin error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH, 240*48a2b783SJeffrey Lin &be_addr, sizeof(be_addr)); 241*48a2b783SJeffrey Lin if (!error) 242*48a2b783SJeffrey Lin error = raydium_i2c_send(client, addr & 0xff, data, len); 243*48a2b783SJeffrey Lin 244*48a2b783SJeffrey Lin return error; 245*48a2b783SJeffrey Lin } 246*48a2b783SJeffrey Lin 247*48a2b783SJeffrey Lin static int raydium_i2c_sw_reset(struct i2c_client *client) 248*48a2b783SJeffrey Lin { 249*48a2b783SJeffrey Lin const u8 soft_rst_cmd = 0x01; 250*48a2b783SJeffrey Lin int error; 251*48a2b783SJeffrey Lin 252*48a2b783SJeffrey Lin error = raydium_i2c_send_message(client, RM_RESET_MSG_ADDR, 253*48a2b783SJeffrey Lin &soft_rst_cmd, sizeof(soft_rst_cmd)); 254*48a2b783SJeffrey Lin if (error) { 255*48a2b783SJeffrey Lin dev_err(&client->dev, "software reset failed: %d\n", error); 256*48a2b783SJeffrey Lin return error; 257*48a2b783SJeffrey Lin } 258*48a2b783SJeffrey Lin 259*48a2b783SJeffrey Lin msleep(RM_RESET_DELAY_MSEC); 260*48a2b783SJeffrey Lin 261*48a2b783SJeffrey Lin return 0; 262*48a2b783SJeffrey Lin } 263*48a2b783SJeffrey Lin 264*48a2b783SJeffrey Lin static int raydium_i2c_query_ts_info(struct raydium_data *ts) 265*48a2b783SJeffrey Lin { 266*48a2b783SJeffrey Lin struct i2c_client *client = ts->client; 267*48a2b783SJeffrey Lin struct raydium_data_info data_info; 268*48a2b783SJeffrey Lin __le32 query_bank_addr; 269*48a2b783SJeffrey Lin 270*48a2b783SJeffrey Lin int error, retry_cnt; 271*48a2b783SJeffrey Lin 272*48a2b783SJeffrey Lin for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) { 273*48a2b783SJeffrey Lin error = raydium_i2c_read(client, RM_CMD_DATA_BANK, 274*48a2b783SJeffrey Lin &data_info, sizeof(data_info)); 275*48a2b783SJeffrey Lin if (error) 276*48a2b783SJeffrey Lin continue; 277*48a2b783SJeffrey Lin 278*48a2b783SJeffrey Lin /* 279*48a2b783SJeffrey Lin * Warn user if we already allocated memory for reports and 280*48a2b783SJeffrey Lin * then the size changed (due to firmware update?) and keep 281*48a2b783SJeffrey Lin * old size instead. 282*48a2b783SJeffrey Lin */ 283*48a2b783SJeffrey Lin if (ts->report_data && ts->report_size != data_info.pkg_size) 284*48a2b783SJeffrey Lin dev_warn(&client->dev, 285*48a2b783SJeffrey Lin "report size changes, was: %d, new: %d\n", 286*48a2b783SJeffrey Lin ts->report_size, data_info.pkg_size); 287*48a2b783SJeffrey Lin else 288*48a2b783SJeffrey Lin ts->report_size = data_info.pkg_size; 289*48a2b783SJeffrey Lin 290*48a2b783SJeffrey Lin ts->contact_size = data_info.tp_info_size; 291*48a2b783SJeffrey Lin ts->data_bank_addr = le32_to_cpu(data_info.data_bank_addr); 292*48a2b783SJeffrey Lin 293*48a2b783SJeffrey Lin dev_dbg(&client->dev, 294*48a2b783SJeffrey Lin "data_bank_addr: %#08x, report_size: %d, contact_size: %d\n", 295*48a2b783SJeffrey Lin ts->data_bank_addr, ts->report_size, ts->contact_size); 296*48a2b783SJeffrey Lin 297*48a2b783SJeffrey Lin error = raydium_i2c_read(client, RM_CMD_QUERY_BANK, 298*48a2b783SJeffrey Lin &query_bank_addr, 299*48a2b783SJeffrey Lin sizeof(query_bank_addr)); 300*48a2b783SJeffrey Lin if (error) 301*48a2b783SJeffrey Lin continue; 302*48a2b783SJeffrey Lin 303*48a2b783SJeffrey Lin error = raydium_i2c_read_message(client, 304*48a2b783SJeffrey Lin le32_to_cpu(query_bank_addr), 305*48a2b783SJeffrey Lin &ts->info, sizeof(ts->info)); 306*48a2b783SJeffrey Lin if (error) 307*48a2b783SJeffrey Lin continue; 308*48a2b783SJeffrey Lin 309*48a2b783SJeffrey Lin return 0; 310*48a2b783SJeffrey Lin } 311*48a2b783SJeffrey Lin 312*48a2b783SJeffrey Lin dev_err(&client->dev, "failed to query device parameters: %d\n", error); 313*48a2b783SJeffrey Lin return error; 314*48a2b783SJeffrey Lin } 315*48a2b783SJeffrey Lin 316*48a2b783SJeffrey Lin static int raydium_i2c_check_fw_status(struct raydium_data *ts) 317*48a2b783SJeffrey Lin { 318*48a2b783SJeffrey Lin struct i2c_client *client = ts->client; 319*48a2b783SJeffrey Lin static const u8 bl_ack = 0x62; 320*48a2b783SJeffrey Lin static const u8 main_ack = 0x66; 321*48a2b783SJeffrey Lin u8 buf[4]; 322*48a2b783SJeffrey Lin int error; 323*48a2b783SJeffrey Lin 324*48a2b783SJeffrey Lin error = raydium_i2c_read(client, RM_CMD_BOOT_READ, buf, sizeof(buf)); 325*48a2b783SJeffrey Lin if (!error) { 326*48a2b783SJeffrey Lin if (buf[0] == bl_ack) 327*48a2b783SJeffrey Lin ts->boot_mode = RAYDIUM_TS_BLDR; 328*48a2b783SJeffrey Lin else if (buf[0] == main_ack) 329*48a2b783SJeffrey Lin ts->boot_mode = RAYDIUM_TS_MAIN; 330*48a2b783SJeffrey Lin return 0; 331*48a2b783SJeffrey Lin } 332*48a2b783SJeffrey Lin 333*48a2b783SJeffrey Lin return error; 334*48a2b783SJeffrey Lin } 335*48a2b783SJeffrey Lin 336*48a2b783SJeffrey Lin static int raydium_i2c_initialize(struct raydium_data *ts) 337*48a2b783SJeffrey Lin { 338*48a2b783SJeffrey Lin struct i2c_client *client = ts->client; 339*48a2b783SJeffrey Lin int error, retry_cnt; 340*48a2b783SJeffrey Lin 341*48a2b783SJeffrey Lin for (retry_cnt = 0; retry_cnt < RM_MAX_RETRIES; retry_cnt++) { 342*48a2b783SJeffrey Lin /* Wait for Hello packet */ 343*48a2b783SJeffrey Lin msleep(RM_BOOT_DELAY_MS); 344*48a2b783SJeffrey Lin 345*48a2b783SJeffrey Lin error = raydium_i2c_check_fw_status(ts); 346*48a2b783SJeffrey Lin if (error) { 347*48a2b783SJeffrey Lin dev_err(&client->dev, 348*48a2b783SJeffrey Lin "failed to read 'hello' packet: %d\n", error); 349*48a2b783SJeffrey Lin continue; 350*48a2b783SJeffrey Lin } 351*48a2b783SJeffrey Lin 352*48a2b783SJeffrey Lin if (ts->boot_mode == RAYDIUM_TS_BLDR || 353*48a2b783SJeffrey Lin ts->boot_mode == RAYDIUM_TS_MAIN) { 354*48a2b783SJeffrey Lin break; 355*48a2b783SJeffrey Lin } 356*48a2b783SJeffrey Lin } 357*48a2b783SJeffrey Lin 358*48a2b783SJeffrey Lin if (error) 359*48a2b783SJeffrey Lin ts->boot_mode = RAYDIUM_TS_BLDR; 360*48a2b783SJeffrey Lin 361*48a2b783SJeffrey Lin if (ts->boot_mode == RAYDIUM_TS_BLDR) { 362*48a2b783SJeffrey Lin ts->info.hw_ver = cpu_to_le32(0xffffffffUL); 363*48a2b783SJeffrey Lin ts->info.main_ver = 0xff; 364*48a2b783SJeffrey Lin ts->info.sub_ver = 0xff; 365*48a2b783SJeffrey Lin } else { 366*48a2b783SJeffrey Lin raydium_i2c_query_ts_info(ts); 367*48a2b783SJeffrey Lin } 368*48a2b783SJeffrey Lin 369*48a2b783SJeffrey Lin return error; 370*48a2b783SJeffrey Lin } 371*48a2b783SJeffrey Lin 372*48a2b783SJeffrey Lin static int raydium_i2c_bl_chk_state(struct i2c_client *client, 373*48a2b783SJeffrey Lin enum raydium_bl_ack state) 374*48a2b783SJeffrey Lin { 375*48a2b783SJeffrey Lin static const u8 ack_ok[] = { 0xFF, 0x39, 0x30, 0x30, 0x54 }; 376*48a2b783SJeffrey Lin u8 rbuf[sizeof(ack_ok)]; 377*48a2b783SJeffrey Lin u8 retry; 378*48a2b783SJeffrey Lin int error; 379*48a2b783SJeffrey Lin 380*48a2b783SJeffrey Lin for (retry = 0; retry < RM_MAX_FW_RETRIES; retry++) { 381*48a2b783SJeffrey Lin switch (state) { 382*48a2b783SJeffrey Lin case RAYDIUM_ACK_NULL: 383*48a2b783SJeffrey Lin return 0; 384*48a2b783SJeffrey Lin 385*48a2b783SJeffrey Lin case RAYDIUM_WAIT_READY: 386*48a2b783SJeffrey Lin error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, 387*48a2b783SJeffrey Lin &rbuf[0], 1); 388*48a2b783SJeffrey Lin if (!error && rbuf[0] == RM_BOOT_RDY) 389*48a2b783SJeffrey Lin return 0; 390*48a2b783SJeffrey Lin 391*48a2b783SJeffrey Lin break; 392*48a2b783SJeffrey Lin 393*48a2b783SJeffrey Lin case RAYDIUM_PATH_READY: 394*48a2b783SJeffrey Lin error = raydium_i2c_read(client, RM_CMD_BOOT_CHK, 395*48a2b783SJeffrey Lin rbuf, sizeof(rbuf)); 396*48a2b783SJeffrey Lin if (!error && !memcmp(rbuf, ack_ok, sizeof(ack_ok))) 397*48a2b783SJeffrey Lin return 0; 398*48a2b783SJeffrey Lin 399*48a2b783SJeffrey Lin break; 400*48a2b783SJeffrey Lin 401*48a2b783SJeffrey Lin default: 402*48a2b783SJeffrey Lin dev_err(&client->dev, "%s: invalid target state %d\n", 403*48a2b783SJeffrey Lin __func__, state); 404*48a2b783SJeffrey Lin return -EINVAL; 405*48a2b783SJeffrey Lin } 406*48a2b783SJeffrey Lin 407*48a2b783SJeffrey Lin msleep(20); 408*48a2b783SJeffrey Lin } 409*48a2b783SJeffrey Lin 410*48a2b783SJeffrey Lin return -ETIMEDOUT; 411*48a2b783SJeffrey Lin } 412*48a2b783SJeffrey Lin 413*48a2b783SJeffrey Lin static int raydium_i2c_write_object(struct i2c_client *client, 414*48a2b783SJeffrey Lin const void *data, size_t len, 415*48a2b783SJeffrey Lin enum raydium_bl_ack state) 416*48a2b783SJeffrey Lin { 417*48a2b783SJeffrey Lin int error; 418*48a2b783SJeffrey Lin 419*48a2b783SJeffrey Lin error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len); 420*48a2b783SJeffrey Lin if (error) { 421*48a2b783SJeffrey Lin dev_err(&client->dev, "WRT obj command failed: %d\n", 422*48a2b783SJeffrey Lin error); 423*48a2b783SJeffrey Lin return error; 424*48a2b783SJeffrey Lin } 425*48a2b783SJeffrey Lin 426*48a2b783SJeffrey Lin error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, NULL, 0); 427*48a2b783SJeffrey Lin if (error) { 428*48a2b783SJeffrey Lin dev_err(&client->dev, "Ack obj command failed: %d\n", error); 429*48a2b783SJeffrey Lin return error; 430*48a2b783SJeffrey Lin } 431*48a2b783SJeffrey Lin 432*48a2b783SJeffrey Lin error = raydium_i2c_bl_chk_state(client, state); 433*48a2b783SJeffrey Lin if (error) { 434*48a2b783SJeffrey Lin dev_err(&client->dev, "BL check state failed: %d\n", error); 435*48a2b783SJeffrey Lin return error; 436*48a2b783SJeffrey Lin } 437*48a2b783SJeffrey Lin return 0; 438*48a2b783SJeffrey Lin } 439*48a2b783SJeffrey Lin 440*48a2b783SJeffrey Lin static bool raydium_i2c_boot_trigger(struct i2c_client *client) 441*48a2b783SJeffrey Lin { 442*48a2b783SJeffrey Lin static const u8 cmd[7][6] = { 443*48a2b783SJeffrey Lin { 0x08, 0x0C, 0x09, 0x00, 0x50, 0xD7 }, 444*48a2b783SJeffrey Lin { 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 }, 445*48a2b783SJeffrey Lin { 0x08, 0x04, 0x09, 0x00, 0x50, 0x00 }, 446*48a2b783SJeffrey Lin { 0x08, 0x04, 0x09, 0x00, 0x50, 0xA5 }, 447*48a2b783SJeffrey Lin { 0x08, 0x0C, 0x09, 0x00, 0x50, 0x00 }, 448*48a2b783SJeffrey Lin { 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 }, 449*48a2b783SJeffrey Lin { 0x02, 0xA2, 0x00, 0x00, 0x00, 0x00 }, 450*48a2b783SJeffrey Lin }; 451*48a2b783SJeffrey Lin int i; 452*48a2b783SJeffrey Lin int error; 453*48a2b783SJeffrey Lin 454*48a2b783SJeffrey Lin for (i = 0; i < 7; i++) { 455*48a2b783SJeffrey Lin error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]), 456*48a2b783SJeffrey Lin RAYDIUM_WAIT_READY); 457*48a2b783SJeffrey Lin if (error) { 458*48a2b783SJeffrey Lin dev_err(&client->dev, 459*48a2b783SJeffrey Lin "boot trigger failed at step %d: %d\n", 460*48a2b783SJeffrey Lin i, error); 461*48a2b783SJeffrey Lin return error; 462*48a2b783SJeffrey Lin } 463*48a2b783SJeffrey Lin } 464*48a2b783SJeffrey Lin 465*48a2b783SJeffrey Lin return 0; 466*48a2b783SJeffrey Lin } 467*48a2b783SJeffrey Lin 468*48a2b783SJeffrey Lin static bool raydium_i2c_fw_trigger(struct i2c_client *client) 469*48a2b783SJeffrey Lin { 470*48a2b783SJeffrey Lin static const u8 cmd[5][11] = { 471*48a2b783SJeffrey Lin { 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0xD7, 0, 0, 0 }, 472*48a2b783SJeffrey Lin { 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 }, 473*48a2b783SJeffrey Lin { 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 }, 474*48a2b783SJeffrey Lin { 0, 0x09, 0x71, 0x04, 0x09, 0x00, 0x50, 0xA5, 0, 0, 0 }, 475*48a2b783SJeffrey Lin { 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0x00, 0, 0, 0 }, 476*48a2b783SJeffrey Lin }; 477*48a2b783SJeffrey Lin int i; 478*48a2b783SJeffrey Lin int error; 479*48a2b783SJeffrey Lin 480*48a2b783SJeffrey Lin for (i = 0; i < 5; i++) { 481*48a2b783SJeffrey Lin error = raydium_i2c_write_object(client, cmd[i], sizeof(cmd[i]), 482*48a2b783SJeffrey Lin RAYDIUM_ACK_NULL); 483*48a2b783SJeffrey Lin if (error) { 484*48a2b783SJeffrey Lin dev_err(&client->dev, 485*48a2b783SJeffrey Lin "fw trigger failed at step %d: %d\n", 486*48a2b783SJeffrey Lin i, error); 487*48a2b783SJeffrey Lin return error; 488*48a2b783SJeffrey Lin } 489*48a2b783SJeffrey Lin } 490*48a2b783SJeffrey Lin 491*48a2b783SJeffrey Lin return 0; 492*48a2b783SJeffrey Lin } 493*48a2b783SJeffrey Lin 494*48a2b783SJeffrey Lin static int raydium_i2c_check_path(struct i2c_client *client) 495*48a2b783SJeffrey Lin { 496*48a2b783SJeffrey Lin static const u8 cmd[] = { 0x09, 0x00, 0x09, 0x00, 0x50, 0x10, 0x00 }; 497*48a2b783SJeffrey Lin int error; 498*48a2b783SJeffrey Lin 499*48a2b783SJeffrey Lin error = raydium_i2c_write_object(client, cmd, sizeof(cmd), 500*48a2b783SJeffrey Lin RAYDIUM_PATH_READY); 501*48a2b783SJeffrey Lin if (error) { 502*48a2b783SJeffrey Lin dev_err(&client->dev, "check path command failed: %d\n", error); 503*48a2b783SJeffrey Lin return error; 504*48a2b783SJeffrey Lin } 505*48a2b783SJeffrey Lin 506*48a2b783SJeffrey Lin return 0; 507*48a2b783SJeffrey Lin } 508*48a2b783SJeffrey Lin 509*48a2b783SJeffrey Lin static int raydium_i2c_enter_bl(struct i2c_client *client) 510*48a2b783SJeffrey Lin { 511*48a2b783SJeffrey Lin static const u8 cal_cmd[] = { 0x00, 0x01, 0x52 }; 512*48a2b783SJeffrey Lin int error; 513*48a2b783SJeffrey Lin 514*48a2b783SJeffrey Lin error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd), 515*48a2b783SJeffrey Lin RAYDIUM_ACK_NULL); 516*48a2b783SJeffrey Lin if (error) { 517*48a2b783SJeffrey Lin dev_err(&client->dev, "enter bl command failed: %d\n", error); 518*48a2b783SJeffrey Lin return error; 519*48a2b783SJeffrey Lin } 520*48a2b783SJeffrey Lin 521*48a2b783SJeffrey Lin msleep(RM_BOOT_DELAY_MS); 522*48a2b783SJeffrey Lin return 0; 523*48a2b783SJeffrey Lin } 524*48a2b783SJeffrey Lin 525*48a2b783SJeffrey Lin static int raydium_i2c_leave_bl(struct i2c_client *client) 526*48a2b783SJeffrey Lin { 527*48a2b783SJeffrey Lin static const u8 leave_cmd[] = { 0x05, 0x00 }; 528*48a2b783SJeffrey Lin int error; 529*48a2b783SJeffrey Lin 530*48a2b783SJeffrey Lin error = raydium_i2c_write_object(client, leave_cmd, sizeof(leave_cmd), 531*48a2b783SJeffrey Lin RAYDIUM_ACK_NULL); 532*48a2b783SJeffrey Lin if (error) { 533*48a2b783SJeffrey Lin dev_err(&client->dev, "leave bl command failed: %d\n", error); 534*48a2b783SJeffrey Lin return error; 535*48a2b783SJeffrey Lin } 536*48a2b783SJeffrey Lin 537*48a2b783SJeffrey Lin msleep(RM_BOOT_DELAY_MS); 538*48a2b783SJeffrey Lin return 0; 539*48a2b783SJeffrey Lin } 540*48a2b783SJeffrey Lin 541*48a2b783SJeffrey Lin static int raydium_i2c_write_checksum(struct i2c_client *client, 542*48a2b783SJeffrey Lin size_t length, u16 checksum) 543*48a2b783SJeffrey Lin { 544*48a2b783SJeffrey Lin u8 checksum_cmd[] = { 0x00, 0x05, 0x6D, 0x00, 0x00, 0x00, 0x00 }; 545*48a2b783SJeffrey Lin int error; 546*48a2b783SJeffrey Lin 547*48a2b783SJeffrey Lin put_unaligned_le16(length, &checksum_cmd[3]); 548*48a2b783SJeffrey Lin put_unaligned_le16(checksum, &checksum_cmd[5]); 549*48a2b783SJeffrey Lin 550*48a2b783SJeffrey Lin error = raydium_i2c_write_object(client, 551*48a2b783SJeffrey Lin checksum_cmd, sizeof(checksum_cmd), 552*48a2b783SJeffrey Lin RAYDIUM_ACK_NULL); 553*48a2b783SJeffrey Lin if (error) { 554*48a2b783SJeffrey Lin dev_err(&client->dev, "failed to write checksum: %d\n", 555*48a2b783SJeffrey Lin error); 556*48a2b783SJeffrey Lin return error; 557*48a2b783SJeffrey Lin } 558*48a2b783SJeffrey Lin 559*48a2b783SJeffrey Lin return 0; 560*48a2b783SJeffrey Lin } 561*48a2b783SJeffrey Lin 562*48a2b783SJeffrey Lin static int raydium_i2c_disable_watch_dog(struct i2c_client *client) 563*48a2b783SJeffrey Lin { 564*48a2b783SJeffrey Lin static const u8 cmd[] = { 0x0A, 0xAA }; 565*48a2b783SJeffrey Lin int error; 566*48a2b783SJeffrey Lin 567*48a2b783SJeffrey Lin error = raydium_i2c_write_object(client, cmd, sizeof(cmd), 568*48a2b783SJeffrey Lin RAYDIUM_WAIT_READY); 569*48a2b783SJeffrey Lin if (error) { 570*48a2b783SJeffrey Lin dev_err(&client->dev, "disable watchdog command failed: %d\n", 571*48a2b783SJeffrey Lin error); 572*48a2b783SJeffrey Lin return error; 573*48a2b783SJeffrey Lin } 574*48a2b783SJeffrey Lin 575*48a2b783SJeffrey Lin return 0; 576*48a2b783SJeffrey Lin } 577*48a2b783SJeffrey Lin 578*48a2b783SJeffrey Lin static int raydium_i2c_fw_write_page(struct i2c_client *client, 579*48a2b783SJeffrey Lin u16 page_idx, const void *data, size_t len) 580*48a2b783SJeffrey Lin { 581*48a2b783SJeffrey Lin u8 buf[RM_BL_WRT_LEN]; 582*48a2b783SJeffrey Lin size_t xfer_len; 583*48a2b783SJeffrey Lin int error; 584*48a2b783SJeffrey Lin int i; 585*48a2b783SJeffrey Lin 586*48a2b783SJeffrey Lin BUILD_BUG_ON((RM_FW_PAGE_SIZE % RM_BL_WRT_PKG_SIZE) != 0); 587*48a2b783SJeffrey Lin 588*48a2b783SJeffrey Lin for (i = 0; i < RM_FW_PAGE_SIZE / RM_BL_WRT_PKG_SIZE; i++) { 589*48a2b783SJeffrey Lin buf[BL_HEADER] = RM_CMD_BOOT_PAGE_WRT; 590*48a2b783SJeffrey Lin buf[BL_PAGE_STR] = page_idx ? 0xff : 0; 591*48a2b783SJeffrey Lin buf[BL_PKG_IDX] = i + 1; 592*48a2b783SJeffrey Lin 593*48a2b783SJeffrey Lin xfer_len = min_t(size_t, len, RM_BL_WRT_PKG_SIZE); 594*48a2b783SJeffrey Lin memcpy(&buf[BL_DATA_STR], data, xfer_len); 595*48a2b783SJeffrey Lin if (len < RM_BL_WRT_PKG_SIZE) 596*48a2b783SJeffrey Lin memset(&buf[BL_DATA_STR + xfer_len], 0xff, 597*48a2b783SJeffrey Lin RM_BL_WRT_PKG_SIZE - xfer_len); 598*48a2b783SJeffrey Lin 599*48a2b783SJeffrey Lin error = raydium_i2c_write_object(client, buf, RM_BL_WRT_LEN, 600*48a2b783SJeffrey Lin RAYDIUM_WAIT_READY); 601*48a2b783SJeffrey Lin if (error) { 602*48a2b783SJeffrey Lin dev_err(&client->dev, 603*48a2b783SJeffrey Lin "page write command failed for page %d, chunk %d: %d\n", 604*48a2b783SJeffrey Lin page_idx, i, error); 605*48a2b783SJeffrey Lin return error; 606*48a2b783SJeffrey Lin } 607*48a2b783SJeffrey Lin 608*48a2b783SJeffrey Lin data += xfer_len; 609*48a2b783SJeffrey Lin len -= xfer_len; 610*48a2b783SJeffrey Lin } 611*48a2b783SJeffrey Lin 612*48a2b783SJeffrey Lin return error; 613*48a2b783SJeffrey Lin } 614*48a2b783SJeffrey Lin 615*48a2b783SJeffrey Lin static int raydium_i2c_do_update_firmware(struct raydium_data *ts, 616*48a2b783SJeffrey Lin const struct firmware *fw) 617*48a2b783SJeffrey Lin { 618*48a2b783SJeffrey Lin struct i2c_client *client = ts->client; 619*48a2b783SJeffrey Lin const void *data; 620*48a2b783SJeffrey Lin size_t data_len; 621*48a2b783SJeffrey Lin size_t len; 622*48a2b783SJeffrey Lin int page_nr; 623*48a2b783SJeffrey Lin int i; 624*48a2b783SJeffrey Lin int error; 625*48a2b783SJeffrey Lin u16 fw_checksum; 626*48a2b783SJeffrey Lin 627*48a2b783SJeffrey Lin if (fw->size == 0 || fw->size > RM_MAX_FW_SIZE) { 628*48a2b783SJeffrey Lin dev_err(&client->dev, "Invalid firmware length\n"); 629*48a2b783SJeffrey Lin return -EINVAL; 630*48a2b783SJeffrey Lin } 631*48a2b783SJeffrey Lin 632*48a2b783SJeffrey Lin error = raydium_i2c_check_fw_status(ts); 633*48a2b783SJeffrey Lin if (error) { 634*48a2b783SJeffrey Lin dev_err(&client->dev, "Unable to access IC %d\n", error); 635*48a2b783SJeffrey Lin return error; 636*48a2b783SJeffrey Lin } 637*48a2b783SJeffrey Lin 638*48a2b783SJeffrey Lin if (ts->boot_mode == RAYDIUM_TS_MAIN) { 639*48a2b783SJeffrey Lin for (i = 0; i < RM_MAX_RETRIES; i++) { 640*48a2b783SJeffrey Lin error = raydium_i2c_enter_bl(client); 641*48a2b783SJeffrey Lin if (!error) { 642*48a2b783SJeffrey Lin error = raydium_i2c_check_fw_status(ts); 643*48a2b783SJeffrey Lin if (error) { 644*48a2b783SJeffrey Lin dev_err(&client->dev, 645*48a2b783SJeffrey Lin "unable to access IC: %d\n", 646*48a2b783SJeffrey Lin error); 647*48a2b783SJeffrey Lin return error; 648*48a2b783SJeffrey Lin } 649*48a2b783SJeffrey Lin 650*48a2b783SJeffrey Lin if (ts->boot_mode == RAYDIUM_TS_BLDR) 651*48a2b783SJeffrey Lin break; 652*48a2b783SJeffrey Lin } 653*48a2b783SJeffrey Lin } 654*48a2b783SJeffrey Lin 655*48a2b783SJeffrey Lin if (ts->boot_mode == RAYDIUM_TS_MAIN) { 656*48a2b783SJeffrey Lin dev_err(&client->dev, 657*48a2b783SJeffrey Lin "failied to jump to boot loader: %d\n", 658*48a2b783SJeffrey Lin error); 659*48a2b783SJeffrey Lin return -EIO; 660*48a2b783SJeffrey Lin } 661*48a2b783SJeffrey Lin } 662*48a2b783SJeffrey Lin 663*48a2b783SJeffrey Lin error = raydium_i2c_disable_watch_dog(client); 664*48a2b783SJeffrey Lin if (error) 665*48a2b783SJeffrey Lin return error; 666*48a2b783SJeffrey Lin 667*48a2b783SJeffrey Lin error = raydium_i2c_check_path(client); 668*48a2b783SJeffrey Lin if (error) 669*48a2b783SJeffrey Lin return error; 670*48a2b783SJeffrey Lin 671*48a2b783SJeffrey Lin error = raydium_i2c_boot_trigger(client); 672*48a2b783SJeffrey Lin if (error) { 673*48a2b783SJeffrey Lin dev_err(&client->dev, "send boot trigger fail: %d\n", error); 674*48a2b783SJeffrey Lin return error; 675*48a2b783SJeffrey Lin } 676*48a2b783SJeffrey Lin 677*48a2b783SJeffrey Lin msleep(RM_BOOT_DELAY_MS); 678*48a2b783SJeffrey Lin 679*48a2b783SJeffrey Lin data = fw->data; 680*48a2b783SJeffrey Lin data_len = fw->size; 681*48a2b783SJeffrey Lin page_nr = 0; 682*48a2b783SJeffrey Lin 683*48a2b783SJeffrey Lin while (data_len) { 684*48a2b783SJeffrey Lin len = min_t(size_t, data_len, RM_FW_PAGE_SIZE); 685*48a2b783SJeffrey Lin 686*48a2b783SJeffrey Lin error = raydium_i2c_fw_write_page(client, page_nr++, data, len); 687*48a2b783SJeffrey Lin if (error) 688*48a2b783SJeffrey Lin return error; 689*48a2b783SJeffrey Lin 690*48a2b783SJeffrey Lin msleep(20); 691*48a2b783SJeffrey Lin 692*48a2b783SJeffrey Lin data += len; 693*48a2b783SJeffrey Lin data_len -= len; 694*48a2b783SJeffrey Lin } 695*48a2b783SJeffrey Lin 696*48a2b783SJeffrey Lin error = raydium_i2c_leave_bl(client); 697*48a2b783SJeffrey Lin if (error) { 698*48a2b783SJeffrey Lin dev_err(&client->dev, 699*48a2b783SJeffrey Lin "failed to leave boot loader: %d\n", error); 700*48a2b783SJeffrey Lin return error; 701*48a2b783SJeffrey Lin } 702*48a2b783SJeffrey Lin 703*48a2b783SJeffrey Lin dev_dbg(&client->dev, "left boot loader mode\n"); 704*48a2b783SJeffrey Lin msleep(RM_BOOT_DELAY_MS); 705*48a2b783SJeffrey Lin 706*48a2b783SJeffrey Lin error = raydium_i2c_check_fw_status(ts); 707*48a2b783SJeffrey Lin if (error) { 708*48a2b783SJeffrey Lin dev_err(&client->dev, 709*48a2b783SJeffrey Lin "failed to check fw status after write: %d\n", 710*48a2b783SJeffrey Lin error); 711*48a2b783SJeffrey Lin return error; 712*48a2b783SJeffrey Lin } 713*48a2b783SJeffrey Lin 714*48a2b783SJeffrey Lin if (ts->boot_mode != RAYDIUM_TS_MAIN) { 715*48a2b783SJeffrey Lin dev_err(&client->dev, 716*48a2b783SJeffrey Lin "failed to switch to main fw after writing firmware: %d\n", 717*48a2b783SJeffrey Lin error); 718*48a2b783SJeffrey Lin return -EINVAL; 719*48a2b783SJeffrey Lin } 720*48a2b783SJeffrey Lin 721*48a2b783SJeffrey Lin error = raydium_i2c_fw_trigger(client); 722*48a2b783SJeffrey Lin if (error) { 723*48a2b783SJeffrey Lin dev_err(&client->dev, "failed to trigger fw: %d\n", error); 724*48a2b783SJeffrey Lin return error; 725*48a2b783SJeffrey Lin } 726*48a2b783SJeffrey Lin 727*48a2b783SJeffrey Lin fw_checksum = 0; 728*48a2b783SJeffrey Lin for (i = 0; i < fw->size; i++) 729*48a2b783SJeffrey Lin fw_checksum += fw->data[i]; 730*48a2b783SJeffrey Lin 731*48a2b783SJeffrey Lin error = raydium_i2c_write_checksum(client, fw->size, fw_checksum); 732*48a2b783SJeffrey Lin if (error) 733*48a2b783SJeffrey Lin return error; 734*48a2b783SJeffrey Lin 735*48a2b783SJeffrey Lin return 0; 736*48a2b783SJeffrey Lin } 737*48a2b783SJeffrey Lin 738*48a2b783SJeffrey Lin static int raydium_i2c_fw_update(struct raydium_data *ts) 739*48a2b783SJeffrey Lin { 740*48a2b783SJeffrey Lin struct i2c_client *client = ts->client; 741*48a2b783SJeffrey Lin const struct firmware *fw = NULL; 742*48a2b783SJeffrey Lin const char *fw_file = "raydium.fw"; 743*48a2b783SJeffrey Lin int error; 744*48a2b783SJeffrey Lin 745*48a2b783SJeffrey Lin error = request_firmware(&fw, fw_file, &client->dev); 746*48a2b783SJeffrey Lin if (error) { 747*48a2b783SJeffrey Lin dev_err(&client->dev, "Unable to open firmware %s\n", fw_file); 748*48a2b783SJeffrey Lin return error; 749*48a2b783SJeffrey Lin } 750*48a2b783SJeffrey Lin 751*48a2b783SJeffrey Lin disable_irq(client->irq); 752*48a2b783SJeffrey Lin 753*48a2b783SJeffrey Lin error = raydium_i2c_do_update_firmware(ts, fw); 754*48a2b783SJeffrey Lin if (error) { 755*48a2b783SJeffrey Lin dev_err(&client->dev, "firmware update failed: %d\n", error); 756*48a2b783SJeffrey Lin ts->boot_mode = RAYDIUM_TS_BLDR; 757*48a2b783SJeffrey Lin goto out_enable_irq; 758*48a2b783SJeffrey Lin } 759*48a2b783SJeffrey Lin 760*48a2b783SJeffrey Lin error = raydium_i2c_initialize(ts); 761*48a2b783SJeffrey Lin if (error) { 762*48a2b783SJeffrey Lin dev_err(&client->dev, 763*48a2b783SJeffrey Lin "failed to initialize device after firmware update: %d\n", 764*48a2b783SJeffrey Lin error); 765*48a2b783SJeffrey Lin ts->boot_mode = RAYDIUM_TS_BLDR; 766*48a2b783SJeffrey Lin goto out_enable_irq; 767*48a2b783SJeffrey Lin } 768*48a2b783SJeffrey Lin 769*48a2b783SJeffrey Lin ts->boot_mode = RAYDIUM_TS_MAIN; 770*48a2b783SJeffrey Lin 771*48a2b783SJeffrey Lin out_enable_irq: 772*48a2b783SJeffrey Lin enable_irq(client->irq); 773*48a2b783SJeffrey Lin msleep(100); 774*48a2b783SJeffrey Lin 775*48a2b783SJeffrey Lin release_firmware(fw); 776*48a2b783SJeffrey Lin 777*48a2b783SJeffrey Lin return error; 778*48a2b783SJeffrey Lin } 779*48a2b783SJeffrey Lin 780*48a2b783SJeffrey Lin static void raydium_mt_event(struct raydium_data *ts) 781*48a2b783SJeffrey Lin { 782*48a2b783SJeffrey Lin int i; 783*48a2b783SJeffrey Lin int error; 784*48a2b783SJeffrey Lin 785*48a2b783SJeffrey Lin error = raydium_i2c_read_message(ts->client, ts->data_bank_addr, 786*48a2b783SJeffrey Lin ts->report_data, ts->report_size); 787*48a2b783SJeffrey Lin if (error) { 788*48a2b783SJeffrey Lin dev_err(&ts->client->dev, "%s: failed to read data: %d\n", 789*48a2b783SJeffrey Lin __func__, error); 790*48a2b783SJeffrey Lin return; 791*48a2b783SJeffrey Lin } 792*48a2b783SJeffrey Lin 793*48a2b783SJeffrey Lin for (i = 0; i < ts->report_size / ts->contact_size; i++) { 794*48a2b783SJeffrey Lin u8 *contact = &ts->report_data[ts->contact_size * i]; 795*48a2b783SJeffrey Lin bool state = contact[RM_CONTACT_STATE_POS]; 796*48a2b783SJeffrey Lin u8 wx, wy; 797*48a2b783SJeffrey Lin 798*48a2b783SJeffrey Lin input_mt_slot(ts->input, i); 799*48a2b783SJeffrey Lin input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, state); 800*48a2b783SJeffrey Lin 801*48a2b783SJeffrey Lin if (!state) 802*48a2b783SJeffrey Lin continue; 803*48a2b783SJeffrey Lin 804*48a2b783SJeffrey Lin input_report_abs(ts->input, ABS_MT_POSITION_X, 805*48a2b783SJeffrey Lin get_unaligned_le16(&contact[RM_CONTACT_X_POS])); 806*48a2b783SJeffrey Lin input_report_abs(ts->input, ABS_MT_POSITION_Y, 807*48a2b783SJeffrey Lin get_unaligned_le16(&contact[RM_CONTACT_Y_POS])); 808*48a2b783SJeffrey Lin input_report_abs(ts->input, ABS_MT_PRESSURE, 809*48a2b783SJeffrey Lin contact[RM_CONTACT_PRESSURE_POS]); 810*48a2b783SJeffrey Lin 811*48a2b783SJeffrey Lin wx = contact[RM_CONTACT_WIDTH_X_POS]; 812*48a2b783SJeffrey Lin wy = contact[RM_CONTACT_WIDTH_Y_POS]; 813*48a2b783SJeffrey Lin 814*48a2b783SJeffrey Lin input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, max(wx, wy)); 815*48a2b783SJeffrey Lin input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, min(wx, wy)); 816*48a2b783SJeffrey Lin } 817*48a2b783SJeffrey Lin 818*48a2b783SJeffrey Lin input_mt_sync_frame(ts->input); 819*48a2b783SJeffrey Lin input_sync(ts->input); 820*48a2b783SJeffrey Lin } 821*48a2b783SJeffrey Lin 822*48a2b783SJeffrey Lin static irqreturn_t raydium_i2c_irq(int irq, void *_dev) 823*48a2b783SJeffrey Lin { 824*48a2b783SJeffrey Lin struct raydium_data *ts = _dev; 825*48a2b783SJeffrey Lin 826*48a2b783SJeffrey Lin if (ts->boot_mode != RAYDIUM_TS_BLDR) 827*48a2b783SJeffrey Lin raydium_mt_event(ts); 828*48a2b783SJeffrey Lin 829*48a2b783SJeffrey Lin return IRQ_HANDLED; 830*48a2b783SJeffrey Lin } 831*48a2b783SJeffrey Lin 832*48a2b783SJeffrey Lin static ssize_t raydium_i2c_fw_ver_show(struct device *dev, 833*48a2b783SJeffrey Lin struct device_attribute *attr, char *buf) 834*48a2b783SJeffrey Lin { 835*48a2b783SJeffrey Lin struct i2c_client *client = to_i2c_client(dev); 836*48a2b783SJeffrey Lin struct raydium_data *ts = i2c_get_clientdata(client); 837*48a2b783SJeffrey Lin 838*48a2b783SJeffrey Lin return sprintf(buf, "%d.%d\n", ts->info.main_ver, ts->info.sub_ver); 839*48a2b783SJeffrey Lin } 840*48a2b783SJeffrey Lin 841*48a2b783SJeffrey Lin static ssize_t raydium_i2c_hw_ver_show(struct device *dev, 842*48a2b783SJeffrey Lin struct device_attribute *attr, char *buf) 843*48a2b783SJeffrey Lin { 844*48a2b783SJeffrey Lin struct i2c_client *client = to_i2c_client(dev); 845*48a2b783SJeffrey Lin struct raydium_data *ts = i2c_get_clientdata(client); 846*48a2b783SJeffrey Lin 847*48a2b783SJeffrey Lin return sprintf(buf, "%#04x\n", le32_to_cpu(ts->info.hw_ver)); 848*48a2b783SJeffrey Lin } 849*48a2b783SJeffrey Lin 850*48a2b783SJeffrey Lin static ssize_t raydium_i2c_boot_mode_show(struct device *dev, 851*48a2b783SJeffrey Lin struct device_attribute *attr, 852*48a2b783SJeffrey Lin char *buf) 853*48a2b783SJeffrey Lin { 854*48a2b783SJeffrey Lin struct i2c_client *client = to_i2c_client(dev); 855*48a2b783SJeffrey Lin struct raydium_data *ts = i2c_get_clientdata(client); 856*48a2b783SJeffrey Lin 857*48a2b783SJeffrey Lin return sprintf(buf, "%s\n", 858*48a2b783SJeffrey Lin ts->boot_mode == RAYDIUM_TS_MAIN ? 859*48a2b783SJeffrey Lin "Normal" : "Recovery"); 860*48a2b783SJeffrey Lin } 861*48a2b783SJeffrey Lin 862*48a2b783SJeffrey Lin static ssize_t raydium_i2c_update_fw_store(struct device *dev, 863*48a2b783SJeffrey Lin struct device_attribute *attr, 864*48a2b783SJeffrey Lin const char *buf, size_t count) 865*48a2b783SJeffrey Lin { 866*48a2b783SJeffrey Lin struct i2c_client *client = to_i2c_client(dev); 867*48a2b783SJeffrey Lin struct raydium_data *ts = i2c_get_clientdata(client); 868*48a2b783SJeffrey Lin int error; 869*48a2b783SJeffrey Lin 870*48a2b783SJeffrey Lin error = mutex_lock_interruptible(&ts->sysfs_mutex); 871*48a2b783SJeffrey Lin if (error) 872*48a2b783SJeffrey Lin return error; 873*48a2b783SJeffrey Lin 874*48a2b783SJeffrey Lin error = raydium_i2c_fw_update(ts); 875*48a2b783SJeffrey Lin 876*48a2b783SJeffrey Lin mutex_unlock(&ts->sysfs_mutex); 877*48a2b783SJeffrey Lin 878*48a2b783SJeffrey Lin return error ?: count; 879*48a2b783SJeffrey Lin } 880*48a2b783SJeffrey Lin 881*48a2b783SJeffrey Lin static ssize_t raydium_i2c_calibrate_store(struct device *dev, 882*48a2b783SJeffrey Lin struct device_attribute *attr, 883*48a2b783SJeffrey Lin const char *buf, size_t count) 884*48a2b783SJeffrey Lin { 885*48a2b783SJeffrey Lin struct i2c_client *client = to_i2c_client(dev); 886*48a2b783SJeffrey Lin struct raydium_data *ts = i2c_get_clientdata(client); 887*48a2b783SJeffrey Lin static const u8 cal_cmd[] = { 0x00, 0x01, 0x9E }; 888*48a2b783SJeffrey Lin int error; 889*48a2b783SJeffrey Lin 890*48a2b783SJeffrey Lin error = mutex_lock_interruptible(&ts->sysfs_mutex); 891*48a2b783SJeffrey Lin if (error) 892*48a2b783SJeffrey Lin return error; 893*48a2b783SJeffrey Lin 894*48a2b783SJeffrey Lin error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd), 895*48a2b783SJeffrey Lin RAYDIUM_WAIT_READY); 896*48a2b783SJeffrey Lin if (error) 897*48a2b783SJeffrey Lin dev_err(&client->dev, "calibrate command failed: %d\n", error); 898*48a2b783SJeffrey Lin 899*48a2b783SJeffrey Lin mutex_unlock(&ts->sysfs_mutex); 900*48a2b783SJeffrey Lin return error ?: count; 901*48a2b783SJeffrey Lin } 902*48a2b783SJeffrey Lin 903*48a2b783SJeffrey Lin static DEVICE_ATTR(fw_version, S_IRUGO, raydium_i2c_fw_ver_show, NULL); 904*48a2b783SJeffrey Lin static DEVICE_ATTR(hw_version, S_IRUGO, raydium_i2c_hw_ver_show, NULL); 905*48a2b783SJeffrey Lin static DEVICE_ATTR(boot_mode, S_IRUGO, raydium_i2c_boot_mode_show, NULL); 906*48a2b783SJeffrey Lin static DEVICE_ATTR(update_fw, S_IWUSR, NULL, raydium_i2c_update_fw_store); 907*48a2b783SJeffrey Lin static DEVICE_ATTR(calibrate, S_IWUSR, NULL, raydium_i2c_calibrate_store); 908*48a2b783SJeffrey Lin 909*48a2b783SJeffrey Lin static struct attribute *raydium_i2c_attributes[] = { 910*48a2b783SJeffrey Lin &dev_attr_update_fw.attr, 911*48a2b783SJeffrey Lin &dev_attr_boot_mode.attr, 912*48a2b783SJeffrey Lin &dev_attr_fw_version.attr, 913*48a2b783SJeffrey Lin &dev_attr_hw_version.attr, 914*48a2b783SJeffrey Lin &dev_attr_calibrate.attr, 915*48a2b783SJeffrey Lin NULL 916*48a2b783SJeffrey Lin }; 917*48a2b783SJeffrey Lin 918*48a2b783SJeffrey Lin static struct attribute_group raydium_i2c_attribute_group = { 919*48a2b783SJeffrey Lin .attrs = raydium_i2c_attributes, 920*48a2b783SJeffrey Lin }; 921*48a2b783SJeffrey Lin 922*48a2b783SJeffrey Lin static void raydium_i2c_remove_sysfs_group(void *_data) 923*48a2b783SJeffrey Lin { 924*48a2b783SJeffrey Lin struct raydium_data *ts = _data; 925*48a2b783SJeffrey Lin 926*48a2b783SJeffrey Lin sysfs_remove_group(&ts->client->dev.kobj, &raydium_i2c_attribute_group); 927*48a2b783SJeffrey Lin } 928*48a2b783SJeffrey Lin 929*48a2b783SJeffrey Lin static int raydium_i2c_power_on(struct raydium_data *ts) 930*48a2b783SJeffrey Lin { 931*48a2b783SJeffrey Lin int error; 932*48a2b783SJeffrey Lin 933*48a2b783SJeffrey Lin if (IS_ERR_OR_NULL(ts->reset_gpio)) 934*48a2b783SJeffrey Lin return 0; 935*48a2b783SJeffrey Lin 936*48a2b783SJeffrey Lin gpiod_set_value_cansleep(ts->reset_gpio, 1); 937*48a2b783SJeffrey Lin 938*48a2b783SJeffrey Lin error = regulator_enable(ts->avdd); 939*48a2b783SJeffrey Lin if (error) { 940*48a2b783SJeffrey Lin dev_err(&ts->client->dev, 941*48a2b783SJeffrey Lin "failed to enable avdd regulator: %d\n", error); 942*48a2b783SJeffrey Lin goto release_reset_gpio; 943*48a2b783SJeffrey Lin } 944*48a2b783SJeffrey Lin 945*48a2b783SJeffrey Lin error = regulator_enable(ts->vccio); 946*48a2b783SJeffrey Lin if (error) { 947*48a2b783SJeffrey Lin regulator_disable(ts->avdd); 948*48a2b783SJeffrey Lin dev_err(&ts->client->dev, 949*48a2b783SJeffrey Lin "failed to enable vccio regulator: %d\n", error); 950*48a2b783SJeffrey Lin goto release_reset_gpio; 951*48a2b783SJeffrey Lin } 952*48a2b783SJeffrey Lin 953*48a2b783SJeffrey Lin udelay(RM_POWERON_DELAY_USEC); 954*48a2b783SJeffrey Lin 955*48a2b783SJeffrey Lin release_reset_gpio: 956*48a2b783SJeffrey Lin gpiod_set_value_cansleep(ts->reset_gpio, 0); 957*48a2b783SJeffrey Lin 958*48a2b783SJeffrey Lin if (error) 959*48a2b783SJeffrey Lin return error; 960*48a2b783SJeffrey Lin 961*48a2b783SJeffrey Lin msleep(RM_RESET_DELAY_MSEC); 962*48a2b783SJeffrey Lin 963*48a2b783SJeffrey Lin return 0; 964*48a2b783SJeffrey Lin } 965*48a2b783SJeffrey Lin 966*48a2b783SJeffrey Lin static void raydium_i2c_power_off(void *_data) 967*48a2b783SJeffrey Lin { 968*48a2b783SJeffrey Lin struct raydium_data *ts = _data; 969*48a2b783SJeffrey Lin 970*48a2b783SJeffrey Lin if (!IS_ERR_OR_NULL(ts->reset_gpio)) { 971*48a2b783SJeffrey Lin gpiod_set_value_cansleep(ts->reset_gpio, 1); 972*48a2b783SJeffrey Lin regulator_disable(ts->vccio); 973*48a2b783SJeffrey Lin regulator_disable(ts->avdd); 974*48a2b783SJeffrey Lin } 975*48a2b783SJeffrey Lin } 976*48a2b783SJeffrey Lin 977*48a2b783SJeffrey Lin static int raydium_i2c_probe(struct i2c_client *client, 978*48a2b783SJeffrey Lin const struct i2c_device_id *id) 979*48a2b783SJeffrey Lin { 980*48a2b783SJeffrey Lin union i2c_smbus_data dummy; 981*48a2b783SJeffrey Lin struct raydium_data *ts; 982*48a2b783SJeffrey Lin int error; 983*48a2b783SJeffrey Lin 984*48a2b783SJeffrey Lin if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 985*48a2b783SJeffrey Lin dev_err(&client->dev, 986*48a2b783SJeffrey Lin "i2c check functionality error (need I2C_FUNC_I2C)\n"); 987*48a2b783SJeffrey Lin return -ENXIO; 988*48a2b783SJeffrey Lin } 989*48a2b783SJeffrey Lin 990*48a2b783SJeffrey Lin ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); 991*48a2b783SJeffrey Lin if (!ts) 992*48a2b783SJeffrey Lin return -ENOMEM; 993*48a2b783SJeffrey Lin 994*48a2b783SJeffrey Lin mutex_init(&ts->sysfs_mutex); 995*48a2b783SJeffrey Lin 996*48a2b783SJeffrey Lin ts->client = client; 997*48a2b783SJeffrey Lin i2c_set_clientdata(client, ts); 998*48a2b783SJeffrey Lin 999*48a2b783SJeffrey Lin ts->avdd = devm_regulator_get(&client->dev, "avdd"); 1000*48a2b783SJeffrey Lin if (IS_ERR(ts->avdd)) { 1001*48a2b783SJeffrey Lin error = PTR_ERR(ts->avdd); 1002*48a2b783SJeffrey Lin if (error != -EPROBE_DEFER) 1003*48a2b783SJeffrey Lin dev_err(&client->dev, 1004*48a2b783SJeffrey Lin "Failed to get 'avdd' regulator: %d\n", error); 1005*48a2b783SJeffrey Lin return error; 1006*48a2b783SJeffrey Lin } 1007*48a2b783SJeffrey Lin 1008*48a2b783SJeffrey Lin ts->vccio = devm_regulator_get(&client->dev, "vccio"); 1009*48a2b783SJeffrey Lin if (IS_ERR(ts->vccio)) { 1010*48a2b783SJeffrey Lin error = PTR_ERR(ts->vccio); 1011*48a2b783SJeffrey Lin if (error != -EPROBE_DEFER) 1012*48a2b783SJeffrey Lin dev_err(&client->dev, 1013*48a2b783SJeffrey Lin "Failed to get 'vccio' regulator: %d\n", error); 1014*48a2b783SJeffrey Lin return error; 1015*48a2b783SJeffrey Lin } 1016*48a2b783SJeffrey Lin 1017*48a2b783SJeffrey Lin ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", 1018*48a2b783SJeffrey Lin GPIOD_OUT_LOW); 1019*48a2b783SJeffrey Lin if (IS_ERR(ts->reset_gpio)) { 1020*48a2b783SJeffrey Lin error = PTR_ERR(ts->reset_gpio); 1021*48a2b783SJeffrey Lin if (error != -EPROBE_DEFER) { 1022*48a2b783SJeffrey Lin dev_err(&client->dev, 1023*48a2b783SJeffrey Lin "failed to get reset gpio: %d\n", error); 1024*48a2b783SJeffrey Lin return error; 1025*48a2b783SJeffrey Lin } 1026*48a2b783SJeffrey Lin } 1027*48a2b783SJeffrey Lin 1028*48a2b783SJeffrey Lin error = raydium_i2c_power_on(ts); 1029*48a2b783SJeffrey Lin if (error) 1030*48a2b783SJeffrey Lin return error; 1031*48a2b783SJeffrey Lin 1032*48a2b783SJeffrey Lin error = devm_add_action(&client->dev, raydium_i2c_power_off, ts); 1033*48a2b783SJeffrey Lin if (error) { 1034*48a2b783SJeffrey Lin dev_err(&client->dev, 1035*48a2b783SJeffrey Lin "failed to install power off action: %d\n", error); 1036*48a2b783SJeffrey Lin raydium_i2c_power_off(ts); 1037*48a2b783SJeffrey Lin return error; 1038*48a2b783SJeffrey Lin } 1039*48a2b783SJeffrey Lin 1040*48a2b783SJeffrey Lin /* Make sure there is something at this address */ 1041*48a2b783SJeffrey Lin if (i2c_smbus_xfer(client->adapter, client->addr, 0, 1042*48a2b783SJeffrey Lin I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { 1043*48a2b783SJeffrey Lin dev_err(&client->dev, "nothing at this address\n"); 1044*48a2b783SJeffrey Lin return -ENXIO; 1045*48a2b783SJeffrey Lin } 1046*48a2b783SJeffrey Lin 1047*48a2b783SJeffrey Lin error = raydium_i2c_initialize(ts); 1048*48a2b783SJeffrey Lin if (error) { 1049*48a2b783SJeffrey Lin dev_err(&client->dev, "failed to initialize: %d\n", error); 1050*48a2b783SJeffrey Lin return error; 1051*48a2b783SJeffrey Lin } 1052*48a2b783SJeffrey Lin 1053*48a2b783SJeffrey Lin ts->report_data = devm_kmalloc(&client->dev, 1054*48a2b783SJeffrey Lin ts->report_size, GFP_KERNEL); 1055*48a2b783SJeffrey Lin if (!ts->report_data) 1056*48a2b783SJeffrey Lin return -ENOMEM; 1057*48a2b783SJeffrey Lin 1058*48a2b783SJeffrey Lin ts->input = devm_input_allocate_device(&client->dev); 1059*48a2b783SJeffrey Lin if (!ts->input) { 1060*48a2b783SJeffrey Lin dev_err(&client->dev, "Failed to allocate input device\n"); 1061*48a2b783SJeffrey Lin return -ENOMEM; 1062*48a2b783SJeffrey Lin } 1063*48a2b783SJeffrey Lin 1064*48a2b783SJeffrey Lin ts->input->name = "Raydium Touchscreen"; 1065*48a2b783SJeffrey Lin ts->input->id.bustype = BUS_I2C; 1066*48a2b783SJeffrey Lin 1067*48a2b783SJeffrey Lin input_set_drvdata(ts->input, ts); 1068*48a2b783SJeffrey Lin 1069*48a2b783SJeffrey Lin input_set_abs_params(ts->input, ABS_MT_POSITION_X, 1070*48a2b783SJeffrey Lin 0, le16_to_cpu(ts->info.x_max), 0, 0); 1071*48a2b783SJeffrey Lin input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 1072*48a2b783SJeffrey Lin 0, le16_to_cpu(ts->info.y_max), 0, 0); 1073*48a2b783SJeffrey Lin input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->info.x_res); 1074*48a2b783SJeffrey Lin input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->info.y_res); 1075*48a2b783SJeffrey Lin 1076*48a2b783SJeffrey Lin input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); 1077*48a2b783SJeffrey Lin input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); 1078*48a2b783SJeffrey Lin 1079*48a2b783SJeffrey Lin error = input_mt_init_slots(ts->input, RM_MAX_TOUCH_NUM, 1080*48a2b783SJeffrey Lin INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 1081*48a2b783SJeffrey Lin if (error) { 1082*48a2b783SJeffrey Lin dev_err(&client->dev, 1083*48a2b783SJeffrey Lin "failed to initialize MT slots: %d\n", error); 1084*48a2b783SJeffrey Lin return error; 1085*48a2b783SJeffrey Lin } 1086*48a2b783SJeffrey Lin 1087*48a2b783SJeffrey Lin error = input_register_device(ts->input); 1088*48a2b783SJeffrey Lin if (error) { 1089*48a2b783SJeffrey Lin dev_err(&client->dev, 1090*48a2b783SJeffrey Lin "unable to register input device: %d\n", error); 1091*48a2b783SJeffrey Lin return error; 1092*48a2b783SJeffrey Lin } 1093*48a2b783SJeffrey Lin 1094*48a2b783SJeffrey Lin error = devm_request_threaded_irq(&client->dev, client->irq, 1095*48a2b783SJeffrey Lin NULL, raydium_i2c_irq, 1096*48a2b783SJeffrey Lin IRQF_ONESHOT, client->name, ts); 1097*48a2b783SJeffrey Lin if (error) { 1098*48a2b783SJeffrey Lin dev_err(&client->dev, "Failed to register interrupt\n"); 1099*48a2b783SJeffrey Lin return error; 1100*48a2b783SJeffrey Lin } 1101*48a2b783SJeffrey Lin 1102*48a2b783SJeffrey Lin error = sysfs_create_group(&client->dev.kobj, 1103*48a2b783SJeffrey Lin &raydium_i2c_attribute_group); 1104*48a2b783SJeffrey Lin if (error) { 1105*48a2b783SJeffrey Lin dev_err(&client->dev, "failed to create sysfs attributes: %d\n", 1106*48a2b783SJeffrey Lin error); 1107*48a2b783SJeffrey Lin return error; 1108*48a2b783SJeffrey Lin } 1109*48a2b783SJeffrey Lin 1110*48a2b783SJeffrey Lin error = devm_add_action(&client->dev, 1111*48a2b783SJeffrey Lin raydium_i2c_remove_sysfs_group, ts); 1112*48a2b783SJeffrey Lin if (error) { 1113*48a2b783SJeffrey Lin raydium_i2c_remove_sysfs_group(ts); 1114*48a2b783SJeffrey Lin dev_err(&client->dev, 1115*48a2b783SJeffrey Lin "Failed to add sysfs cleanup action: %d\n", error); 1116*48a2b783SJeffrey Lin return error; 1117*48a2b783SJeffrey Lin } 1118*48a2b783SJeffrey Lin 1119*48a2b783SJeffrey Lin return 0; 1120*48a2b783SJeffrey Lin } 1121*48a2b783SJeffrey Lin 1122*48a2b783SJeffrey Lin static void __maybe_unused raydium_enter_sleep(struct i2c_client *client) 1123*48a2b783SJeffrey Lin { 1124*48a2b783SJeffrey Lin static const u8 sleep_cmd[] = { 0x5A, 0xff, 0x00, 0x0f }; 1125*48a2b783SJeffrey Lin int error; 1126*48a2b783SJeffrey Lin 1127*48a2b783SJeffrey Lin error = raydium_i2c_send(client, RM_CMD_ENTER_SLEEP, 1128*48a2b783SJeffrey Lin sleep_cmd, sizeof(sleep_cmd)); 1129*48a2b783SJeffrey Lin if (error) 1130*48a2b783SJeffrey Lin dev_err(&client->dev, 1131*48a2b783SJeffrey Lin "sleep command failed: %d\n", error); 1132*48a2b783SJeffrey Lin } 1133*48a2b783SJeffrey Lin 1134*48a2b783SJeffrey Lin static int __maybe_unused raydium_i2c_suspend(struct device *dev) 1135*48a2b783SJeffrey Lin { 1136*48a2b783SJeffrey Lin struct i2c_client *client = to_i2c_client(dev); 1137*48a2b783SJeffrey Lin struct raydium_data *ts = i2c_get_clientdata(client); 1138*48a2b783SJeffrey Lin 1139*48a2b783SJeffrey Lin /* Sleep is not available in BLDR recovery mode */ 1140*48a2b783SJeffrey Lin if (ts->boot_mode != RAYDIUM_TS_MAIN) 1141*48a2b783SJeffrey Lin return -ENOMEM; 1142*48a2b783SJeffrey Lin 1143*48a2b783SJeffrey Lin disable_irq(client->irq); 1144*48a2b783SJeffrey Lin 1145*48a2b783SJeffrey Lin if (device_may_wakeup(dev)) { 1146*48a2b783SJeffrey Lin raydium_enter_sleep(client); 1147*48a2b783SJeffrey Lin 1148*48a2b783SJeffrey Lin ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); 1149*48a2b783SJeffrey Lin } else { 1150*48a2b783SJeffrey Lin raydium_i2c_power_off(ts); 1151*48a2b783SJeffrey Lin } 1152*48a2b783SJeffrey Lin 1153*48a2b783SJeffrey Lin return 0; 1154*48a2b783SJeffrey Lin } 1155*48a2b783SJeffrey Lin 1156*48a2b783SJeffrey Lin static int __maybe_unused raydium_i2c_resume(struct device *dev) 1157*48a2b783SJeffrey Lin { 1158*48a2b783SJeffrey Lin struct i2c_client *client = to_i2c_client(dev); 1159*48a2b783SJeffrey Lin struct raydium_data *ts = i2c_get_clientdata(client); 1160*48a2b783SJeffrey Lin 1161*48a2b783SJeffrey Lin if (device_may_wakeup(dev)) { 1162*48a2b783SJeffrey Lin if (ts->wake_irq_enabled) 1163*48a2b783SJeffrey Lin disable_irq_wake(client->irq); 1164*48a2b783SJeffrey Lin raydium_i2c_sw_reset(client); 1165*48a2b783SJeffrey Lin } else { 1166*48a2b783SJeffrey Lin raydium_i2c_power_on(ts); 1167*48a2b783SJeffrey Lin raydium_i2c_initialize(ts); 1168*48a2b783SJeffrey Lin } 1169*48a2b783SJeffrey Lin 1170*48a2b783SJeffrey Lin enable_irq(client->irq); 1171*48a2b783SJeffrey Lin 1172*48a2b783SJeffrey Lin return 0; 1173*48a2b783SJeffrey Lin } 1174*48a2b783SJeffrey Lin 1175*48a2b783SJeffrey Lin static SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops, 1176*48a2b783SJeffrey Lin raydium_i2c_suspend, raydium_i2c_resume); 1177*48a2b783SJeffrey Lin 1178*48a2b783SJeffrey Lin static const struct i2c_device_id raydium_i2c_id[] = { 1179*48a2b783SJeffrey Lin { "raydium_i2c" , 0 }, 1180*48a2b783SJeffrey Lin { "rm32380", 0 }, 1181*48a2b783SJeffrey Lin { /* sentinel */ } 1182*48a2b783SJeffrey Lin }; 1183*48a2b783SJeffrey Lin MODULE_DEVICE_TABLE(i2c, raydium_i2c_id); 1184*48a2b783SJeffrey Lin 1185*48a2b783SJeffrey Lin #ifdef CONFIG_ACPI 1186*48a2b783SJeffrey Lin static const struct acpi_device_id raydium_acpi_id[] = { 1187*48a2b783SJeffrey Lin { "RAYD0001", 0 }, 1188*48a2b783SJeffrey Lin { /* sentinel */ } 1189*48a2b783SJeffrey Lin }; 1190*48a2b783SJeffrey Lin MODULE_DEVICE_TABLE(acpi, raydium_acpi_id); 1191*48a2b783SJeffrey Lin #endif 1192*48a2b783SJeffrey Lin 1193*48a2b783SJeffrey Lin #ifdef CONFIG_OF 1194*48a2b783SJeffrey Lin static const struct of_device_id raydium_of_match[] = { 1195*48a2b783SJeffrey Lin { .compatible = "raydium,rm32380", }, 1196*48a2b783SJeffrey Lin { /* sentinel */ } 1197*48a2b783SJeffrey Lin }; 1198*48a2b783SJeffrey Lin MODULE_DEVICE_TABLE(of, raydium_of_match); 1199*48a2b783SJeffrey Lin #endif 1200*48a2b783SJeffrey Lin 1201*48a2b783SJeffrey Lin static struct i2c_driver raydium_i2c_driver = { 1202*48a2b783SJeffrey Lin .probe = raydium_i2c_probe, 1203*48a2b783SJeffrey Lin .id_table = raydium_i2c_id, 1204*48a2b783SJeffrey Lin .driver = { 1205*48a2b783SJeffrey Lin .name = "raydium_ts", 1206*48a2b783SJeffrey Lin .pm = &raydium_i2c_pm_ops, 1207*48a2b783SJeffrey Lin .acpi_match_table = ACPI_PTR(raydium_acpi_id), 1208*48a2b783SJeffrey Lin .of_match_table = of_match_ptr(raydium_of_match), 1209*48a2b783SJeffrey Lin }, 1210*48a2b783SJeffrey Lin }; 1211*48a2b783SJeffrey Lin module_i2c_driver(raydium_i2c_driver); 1212*48a2b783SJeffrey Lin 1213*48a2b783SJeffrey Lin MODULE_AUTHOR("Raydium"); 1214*48a2b783SJeffrey Lin MODULE_DESCRIPTION("Raydium I2c Touchscreen driver"); 1215*48a2b783SJeffrey Lin MODULE_LICENSE("GPL v2"); 1216