/* tc3xxk.c -- Linux driver for coreriver chip as grip * * Copyright (C) 2013 Samsung Electronics Co.Ltd * Author: Junkyeong Kim * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_BATTERY_SAMSUNG extern unsigned int lpcharge; #endif #include "tc3xxk.h" #if defined (CONFIG_VBUS_NOTIFIER) #if defined(CONFIG_USE_MUIC_LEGO) #include #include #else #include #include #endif /* CONFIG_USE_MUIC_LEGO */ #include #endif #define IDLE 0 #define ACTIVE 1 /* registers */ #define TC300K_FWVER 0x01 #define TC300K_MDVER 0x02 #define TC300K_MODE 0x03 #define TC300K_CHECKS_H 0x04 #define TC300K_CHECKS_L 0x05 /* registers for grip sensor */ #define TC305K_GRIPCODE 0x0F #define TC305K_GRIP_THD_PRESS 0x00 #define TC305K_GRIP_THD_RELEASE 0x02 #define TC305K_GRIP_THD_NOISE 0x04 #define TC305K_GRIP_CH_PERCENT 0x06 #define TC305K_GRIP_DIFF_DATA 0x08 #define TC305K_GRIP_RAW_DATA 0x0A #define TC305K_GRIP_BASELINE 0x0C #define TC305K_GRIP_TOTAL_CAP 0x0E #define TC305K_GRIP_REF_CAP 0x70 #define TC305K_1GRIP 0x30 #define TC305K_2GRIP 0x40 #define TC305K_3GRIP 0x50 #define TC305K_4GRIP 0x60 #define TC350K_DATA_SIZE 0x02 #define TC350K_DATA_H_OFFSET 0x00 #define TC350K_DATA_L_OFFSET 0x01 /* command */ #define TC300K_CMD_ADDR 0x00 #define TC300K_CMD_TA_ON 0x50 #define TC300K_CMD_TA_OFF 0x60 #define TC300K_CMD_CAL_CHECKSUM 0x70 #define TC300K_CMD_STOP_MODE 0x90 #define TC300K_CMD_NORMAL_MODE 0x91 #define TC300K_CMD_SAR_DISABLE 0xA0 #define TC300K_CMD_SAR_ENABLE 0xA1 #define TC300K_CMD_GRIP_BASELINE_CAL 0xC0 #define TC300K_CMD_WAKE_UP 0xF0 #define TC300K_CMD_DELAY 50 /* mode status bit */ #define TC300K_MODE_RUN (1 << 1) #define TC300K_MODE_SAR (1 << 2) /* firmware */ #define TC300K_FW_PATH_SDCARD "/sdcard/tc3xxk.bin" #define HALL_PATH "/sys/class/sec/hall_ic/hall_detect" #define HALL_CLOSE_STATE 1 #define TK_UPDATE_PASS 0 #define TK_UPDATE_DOWN 1 #define TK_UPDATE_FAIL 2 /* ISP command */ #define TC300K_CSYNC1 0xA3 #define TC300K_CSYNC2 0xAC #define TC300K_CSYNC3 0xA5 #define TC300K_CCFG 0x92 #define TC300K_PRDATA 0x81 #define TC300K_PEDATA 0x82 #define TC300K_PWDATA 0x83 #define TC300K_PECHIP 0x8A #define TC300K_PEDISC 0xB0 #define TC300K_LDDATA 0xB2 #define TC300K_LDMODE 0xB8 #define TC300K_RDDATA 0xB9 #define TC300K_PCRST 0xB4 #define TC300K_PCRED 0xB5 #define TC300K_PCINC 0xB6 #define TC300K_RDPCH 0xBD /* ISP delay */ #define TC300K_TSYNC1 300 /* us */ #define TC300K_TSYNC2 50 /* 1ms~50ms */ #define TC300K_TSYNC3 100 /* us */ #define TC300K_TDLY1 1 /* us */ #define TC300K_TDLY2 2 /* us */ #define TC300K_TFERASE 10 /* ms */ #define TC300K_TPROG 20 /* us */ #define TC300K_CHECKSUM_DELAY 500 enum { FW_INKERNEL, FW_SDCARD, }; struct fw_image { u8 hdr_ver; u8 hdr_len; u16 first_fw_ver; u16 second_fw_ver; u16 third_ver; u32 fw_len; u16 checksum; u16 alignment_dummy; u8 data[0]; } __attribute__ ((packed)); #define GRIP_RELEASE 0x00 #define GRIP_PRESS 0x01 struct grip_event_val { u16 grip_bitmap; u8 grip_status; char* grip_name; }; struct grip_event_val grip_ev[4] = { {0x01 << 0, GRIP_PRESS, "grip1"}, {0x01 << 1, GRIP_PRESS, "grip2"}, {0x01 << 4, GRIP_RELEASE, "grip1"}, {0x01 << 5, GRIP_RELEASE, "grip2"}, }; struct tc3xxk_data { struct device *dev; struct i2c_client *client; struct input_dev *input_dev; struct tc3xxk_platform_data *pdata; struct mutex lock_fac; struct fw_image *fw_img; const struct firmware *fw; char phys[32]; int irq; bool irq_check; u16 checksum; u16 threhold; int mode; int (*power) (bool on); u8 fw_ver; u8 fw_ver_bin; u8 md_ver; u8 md_ver_bin; u8 fw_update_status; bool enabled; bool fw_downloading; struct pinctrl *pinctrl_i2c; struct pinctrl *pinctrl_irq; struct pinctrl_state *pin_state[4]; struct wake_lock grip_wake_lock; u16 grip_p_thd; u16 grip_r_thd; u16 grip_n_thd; u16 grip_s1; u16 grip_s2; u16 grip_baseline; u16 grip_raw1; u16 grip_raw2; u16 grip_event; bool sar_enable; bool sar_enable_off; int grip_num; struct grip_event_val *grip_ev_val; struct delayed_work debug_work; s32 diff; #ifdef CONFIG_SEC_FACTORY int irq_count; int abnormal_mode; s32 max_diff; #endif #if defined (CONFIG_VBUS_NOTIFIER) bool ignore_vbus_event; struct notifier_block vbus_nb; #endif }; extern struct class *sec_class; char *str_states[] = {"on_irq", "off_irq", "on_i2c", "off_i2c"}; enum { I_STATE_ON_IRQ = 0, I_STATE_OFF_IRQ, I_STATE_ON_I2C, I_STATE_OFF_I2C, }; static bool tc3xxk_power_enabled; const char *regulator_ic; static int tc3xxk_pinctrl_init(struct tc3xxk_data *data); static void tc3xxk_config_gpio_i2c(struct tc3xxk_data *data, int onoff); static int tc3xxk_pinctrl(struct tc3xxk_data *data, int status); static int read_tc3xxk_register_data(struct tc3xxk_data *data, int read_key_num, int read_offset); static int tc3xxk_mode_enable(struct i2c_client *client, u8 cmd); static void tc3xxk_grip_cal_reset(struct tc3xxk_data *data); static int tc3xxk_get_hallic_state(struct tc3xxk_data *data) { char hall_buf[6]; int ret = -ENODEV; int hall_state = -1; mm_segment_t old_fs; struct file *filep; memset(hall_buf, 0, sizeof(hall_buf)); old_fs = get_fs(); set_fs(KERNEL_DS); filep = filp_open(HALL_PATH, O_RDONLY, 0666); if (IS_ERR(filep)) { set_fs(old_fs); return hall_state; } ret = filep->f_op->read(filep, hall_buf, sizeof(hall_buf) - 1, &filep->f_pos); if (ret != sizeof(hall_buf) - 1) goto exit; if (strcmp(hall_buf, "CLOSE") == 0) hall_state = HALL_CLOSE_STATE; exit: filp_close(filep, current->files); set_fs(old_fs); return hall_state; } static void tc3xxk_debug_work_func(struct work_struct *work) { struct tc3xxk_data *data = container_of((struct delayed_work *)work, struct tc3xxk_data, debug_work); static int hall_prev_state; int hall_state; hall_state = tc3xxk_get_hallic_state(data); if (hall_state == HALL_CLOSE_STATE && hall_prev_state != hall_state) { SENSOR_INFO("%s - hall is closed\n", __func__); tc3xxk_grip_cal_reset(data); } hall_prev_state = hall_state; #ifdef CONFIG_SEC_FACTORY if (data->abnormal_mode) { data->diff = read_tc3xxk_register_data(data, TC305K_1GRIP, TC305K_GRIP_DIFF_DATA); if (data->max_diff < data->diff) data->max_diff = data->diff; } #endif schedule_delayed_work(&data->debug_work, msecs_to_jiffies(2000)); } static int tc3xxk_mode_check(struct i2c_client *client) { int mode = i2c_smbus_read_byte_data(client, TC300K_MODE); if (mode < 0) SENSOR_ERR("failed to read mode (%d)\n", mode); return mode; } static int tc3xxk_wake_up(struct i2c_client *client, u8 cmd) { //If stop mode enabled, touch key IC need wake_up CMD //After wake_up CMD, IC need 10ms delay int ret; SENSOR_INFO("Send WAKE UP cmd: 0x%02x \n", cmd); ret = i2c_smbus_write_byte_data(client, TC300K_CMD_ADDR, TC300K_CMD_WAKE_UP); usleep_range(10000, 10000); return ret; } static void grip_sar_sensing(struct tc3xxk_data *data, bool on) { int ret; if(on) { SENSOR_INFO("Earjack attach\n"); ret = tc3xxk_wake_up(data->client, TC300K_CMD_WAKE_UP); ret = tc3xxk_mode_enable(data->client, TC300K_CMD_TA_ON); if (ret < 0) SENSOR_ERR("TA mode ON fail(%d)\n", ret); } else { SENSOR_INFO("Earjack detach\n"); ret = tc3xxk_wake_up(data->client, TC300K_CMD_WAKE_UP); ret = tc3xxk_mode_enable(data->client, TC300K_CMD_TA_OFF); if (ret < 0) SENSOR_ERR("TA mode OFF fail(%d)\n", ret); } } static void tc3xxk_grip_cal_reset(struct tc3xxk_data *data) { /* calibrate grip sensor chn */ struct i2c_client *client = data->client; SENSOR_INFO("\n"); i2c_smbus_write_byte_data(client, TC300K_CMD_ADDR, TC300K_CMD_GRIP_BASELINE_CAL); msleep(TC300K_CMD_DELAY); } static void tc3xxk_reset(struct tc3xxk_data *data) { SENSOR_INFO("\n"); if (data->irq_check) { data->irq_check = false; disable_irq_wake(data->client->irq); disable_irq_nosync(data->client->irq); } data->pdata->power(data, false); msleep(50); data->pdata->power(data, true); msleep(200); if (data->sar_enable) tc3xxk_mode_enable(data->client, TC300K_CMD_SAR_ENABLE); if (!data->irq_check) { data->irq_check = true; enable_irq(data->client->irq); enable_irq_wake(data->client->irq); } } static void tc3xxk_reset_probe(struct tc3xxk_data *data) { data->pdata->power(data, false); msleep(50); data->pdata->power(data, true); msleep(200); } int tc3xxk_get_fw_version(struct tc3xxk_data *data, bool probe) { struct i2c_client *client = data->client; int retry = 3; int buf; if ((!data->enabled) || data->fw_downloading) { SENSOR_ERR("can't excute\n"); return -1; } buf = i2c_smbus_read_byte_data(client, TC300K_FWVER); if (buf < 0) { while (retry--) { SENSOR_ERR("read fail(%d, %d)\n", buf, retry); if (probe) tc3xxk_reset_probe(data); else tc3xxk_reset(data); buf = i2c_smbus_read_byte_data(client, TC300K_FWVER); if (buf > 0) break; } if (retry <= 0) { SENSOR_ERR("read fail\n"); data->fw_ver = 0; return -1; } } data->fw_ver = (u8)buf; SENSOR_INFO( "fw_ver : 0x%x\n", data->fw_ver); return 0; } int tc3xxk_get_md_version(struct tc3xxk_data *data, bool probe) { struct i2c_client *client = data->client; int retry = 3; int buf; if ((!data->enabled) || data->fw_downloading) { SENSOR_ERR("can't excute\n"); return -1; } buf = i2c_smbus_read_byte_data(client, TC300K_MDVER); if (buf < 0) { while (retry--) { SENSOR_ERR("read fail(%d)\n", retry); if (probe) tc3xxk_reset_probe(data); else tc3xxk_reset(data); buf = i2c_smbus_read_byte_data(client, TC300K_MDVER); if (buf > 0) break; } if (retry <= 0) { SENSOR_ERR("read fail\n"); data->md_ver = 0; return -1; } } data->md_ver = (u8)buf; SENSOR_INFO( "md_ver : 0x%x\n", data->md_ver); return 0; } static void tc3xxk_gpio_request(struct tc3xxk_data *data) { int ret = 0; SENSOR_INFO("\n"); if (!data->pdata->i2c_gpio) { ret = gpio_request(data->pdata->gpio_scl, "grip_scl"); if (ret) { SENSOR_ERR("unable to request grip_scl [%d]\n", data->pdata->gpio_scl); } ret = gpio_request(data->pdata->gpio_sda, "grip_sda"); if (ret) { SENSOR_ERR("unable to request grip_sda [%d]\n", data->pdata->gpio_sda); } } ret = gpio_request(data->pdata->gpio_int, "grip_irq"); if (ret) { SENSOR_ERR("unable to request grip_irq [%d]\n", data->pdata->gpio_int); } } static int tc3xxk_parse_dt(struct device *dev, struct tc3xxk_platform_data *pdata) { struct device_node *np = dev->of_node; int ret; enum of_gpio_flags flags; of_property_read_u32(np, "coreriver,use_bitmap", &pdata->use_bitmap); SENSOR_INFO("%s protocol.\n", pdata->use_bitmap ? "Use Bit-map" : "Use OLD"); pdata->gpio_scl = of_get_named_gpio_flags(np, "coreriver,scl-gpio", 0, &pdata->scl_gpio_flags); pdata->gpio_sda = of_get_named_gpio_flags(np, "coreriver,sda-gpio", 0, &pdata->sda_gpio_flags); pdata->gpio_int = of_get_named_gpio_flags(np, "coreriver,irq-gpio", 0, &pdata->irq_gpio_flags); pdata->ldo_en = of_get_named_gpio_flags(np, "coreriver,ldo_en", 0, &flags); if (pdata->ldo_en < 0) { SENSOR_ERR("fail to get ldo_en\n"); pdata->ldo_en = 0; if (of_property_read_string(np, "coreriver,regulator_ic", &pdata->regulator_ic)) { SENSOR_ERR("Failed to get regulator_ic name property\n"); return -EINVAL; } regulator_ic = pdata->regulator_ic; } else { ret = gpio_request(pdata->ldo_en, "grip_ldo_en"); if (ret < 0) { SENSOR_ERR("gpio %d request failed %d\n", pdata->ldo_en, ret); return ret; } gpio_direction_output(pdata->ldo_en, 0); } pdata->boot_on_ldo = of_property_read_bool(np, "coreriver,boot-on-ldo"); pdata->i2c_gpio = of_property_read_bool(np, "coreriver,i2c-gpio"); if (of_property_read_string(np, "coreriver,fw_name", &pdata->fw_name)) { SENSOR_ERR("Failed to get fw_name property\n"); return -EINVAL; } else { SENSOR_INFO("fw_name %s\n", pdata->fw_name); } pdata->bringup = of_property_read_bool(np, "coreriver,bringup"); if (pdata->bringup < 0) pdata->bringup = 0; SENSOR_INFO("grip_int:%d, ldo_en:%d\n", pdata->gpio_int, pdata->ldo_en); return 0; } int tc3xxk_grip_power(void *info, bool on) { struct tc3xxk_data *data = (struct tc3xxk_data *)info; struct regulator *regulator; int ret = 0; if (tc3xxk_power_enabled == on) return 0; SENSOR_INFO("%s\n", on ? "on" : "off"); /* ldo control*/ if (data->pdata->ldo_en) { gpio_set_value(data->pdata->ldo_en, on); SENSOR_INFO("ldo_en power %d\n", on); tc3xxk_power_enabled = on; return 0; } /*regulator control*/ regulator = regulator_get(NULL, regulator_ic); if (IS_ERR(regulator)){ SENSOR_ERR("regulator_ic get failed\n"); return -EIO; } if (on) { ret = regulator_enable(regulator); if (ret) { SENSOR_ERR("regulator_ic enable failed\n"); return ret; } } else { if (regulator_is_enabled(regulator)){ regulator_disable(regulator); if (ret) { SENSOR_ERR("regulator_ic disable failed\n"); return ret; } } else regulator_force_disable(regulator); } regulator_put(regulator); tc3xxk_power_enabled = on; return 0; } static irqreturn_t tc3xxk_interrupt(int irq, void *dev_id) { struct tc3xxk_data *data = dev_id; struct i2c_client *client = data->client; int ret, retry; int i = 0; u8 grip_val; bool grip_handle_flag; wake_lock(&data->grip_wake_lock); SENSOR_INFO("\n"); if ((!data->enabled) || data->fw_downloading) { SENSOR_ERR("can't excute\n"); wake_unlock(&data->grip_wake_lock); return IRQ_HANDLED; } ret = tc3xxk_wake_up(client, TC300K_CMD_WAKE_UP); ret = i2c_smbus_read_byte_data(client, TC305K_GRIPCODE); if (ret < 0) { retry = 3; while (retry--) { SENSOR_ERR("read fail ret=%d(retry:%d)\n", ret, retry); msleep(10); ret = i2c_smbus_read_byte_data(client, TC305K_GRIPCODE); if (ret > 0) break; } if (retry <= 0) { tc3xxk_reset(data); wake_unlock(&data->grip_wake_lock); return IRQ_HANDLED; } } grip_val = (u8)ret; for (i = 0 ; i < data->grip_num * 2 ; i++){ //use 2 grip chanel if (data->pdata->use_bitmap) grip_handle_flag = (grip_val & data->grip_ev_val[i].grip_bitmap); else grip_handle_flag = (grip_val == data->grip_ev_val[i].grip_bitmap); if (grip_handle_flag) { data->diff = read_tc3xxk_register_data(data, TC305K_1GRIP, TC305K_GRIP_DIFF_DATA); #ifdef CONFIG_SEC_FACTORY if (data->abnormal_mode) { if (data->grip_event) { if (data->max_diff < data->diff) data->max_diff = data->diff; data->irq_count++; } } #endif if(data->grip_ev_val[i].grip_status == ACTIVE){ data->grip_event = ACTIVE; input_report_rel(data->input_dev, REL_MISC, 1); } else { data->grip_event = IDLE; input_report_rel(data->input_dev, REL_MISC, 2); } SENSOR_INFO("%s : %s(0x%02X), diff : %d, ver0x%02x\n", data->grip_ev_val[i].grip_status? "P" : "R", data->grip_ev_val[i].grip_name, grip_val, data->diff, data->fw_ver); } } input_sync(data->input_dev); wake_unlock(&data->grip_wake_lock); return IRQ_HANDLED; } static int load_fw_in_kernel(struct tc3xxk_data *data) { struct i2c_client *client = data->client; int ret; ret = request_firmware(&data->fw, data->pdata->fw_name, &client->dev); if (ret) { SENSOR_ERR("fail(%d)\n", ret); return -1; } data->fw_img = (struct fw_image *)data->fw->data; SENSOR_INFO( "0x%x 0x%x firm (size=%d)\n", data->fw_img->first_fw_ver, data->fw_img->second_fw_ver, data->fw_img->fw_len); SENSOR_INFO("done\n"); return 0; } static int load_fw_sdcard(struct tc3xxk_data *data) { struct file *fp; mm_segment_t old_fs; long fsize, nread; int ret = 0; old_fs = get_fs(); set_fs(get_ds()); fp = filp_open(TC300K_FW_PATH_SDCARD, O_RDONLY, S_IRUSR); if (IS_ERR(fp)) { SENSOR_ERR("%s open error\n", TC300K_FW_PATH_SDCARD); ret = -ENOENT; goto fail_sdcard_open; } fsize = fp->f_path.dentry->d_inode->i_size; data->fw_img = kzalloc((size_t)fsize, GFP_KERNEL); if (!data->fw_img) { SENSOR_ERR("fail to kzalloc for fw\n"); filp_close(fp, current->files); ret = -ENOMEM; goto fail_sdcard_kzalloc; } nread = vfs_read(fp, (char __user *)data->fw_img, fsize, &fp->f_pos); if (nread != fsize) { SENSOR_ERR("fail to vfs_read file\n"); ret = -EINVAL; goto fail_sdcard_size; } filp_close(fp, current->files); set_fs(old_fs); SENSOR_INFO("fw_size : %lu\n", nread); SENSOR_INFO("done\n"); return ret; fail_sdcard_size: kfree(&data->fw_img); fail_sdcard_kzalloc: filp_close(fp, current->files); fail_sdcard_open: set_fs(old_fs); return ret; } static inline void setsda(struct tc3xxk_data *data, int state) { if (state) gpio_direction_output(data->pdata->gpio_sda, 1); else gpio_direction_output(data->pdata->gpio_sda, 0); } static inline void setscl(struct tc3xxk_data *data, int state) { if (state) gpio_direction_output(data->pdata->gpio_scl, 1); else gpio_direction_output(data->pdata->gpio_scl, 0); } static inline int getsda(struct tc3xxk_data *data) { return gpio_get_value(data->pdata->gpio_sda); } static inline int getscl(struct tc3xxk_data *data) { return gpio_get_value(data->pdata->gpio_scl); } static void send_9bit(struct tc3xxk_data *data, u8 buff) { int i; setscl(data, 1); ndelay(20); setsda(data, 0); ndelay(20); setscl(data, 0); ndelay(20); for (i = 0; i < 8; i++) { setscl(data, 1); ndelay(20); setsda(data, (buff >> i) & 0x01); ndelay(20); setscl(data, 0); ndelay(20); } setsda(data, 0); } static u8 wait_9bit(struct tc3xxk_data *data) { int i; int buf; u8 send_buf = 0; gpio_direction_input(data->pdata->gpio_sda); getsda(data); ndelay(10); setscl(data, 1); ndelay(40); setscl(data, 0); ndelay(20); for (i = 0; i < 8; i++) { setscl(data, 1); ndelay(20); buf = getsda(data); ndelay(20); setscl(data, 0); ndelay(20); send_buf |= (buf & 0x01) << i; } setsda(data, 0); return send_buf; } static void tc3xxk_reset_for_isp(struct tc3xxk_data *data, bool start) { if (start) { setscl(data, 0); setsda(data, 0); data->pdata->power(data, false); msleep(100); data->pdata->power(data, true); usleep_range(5000, 6000); } else { data->pdata->power(data, false); msleep(100); data->pdata->power(data, true); msleep(120); gpio_direction_input(data->pdata->gpio_sda); gpio_direction_input(data->pdata->gpio_scl); } } static void load(struct tc3xxk_data *data, u8 buff) { send_9bit(data, TC300K_LDDATA); udelay(1); send_9bit(data, buff); udelay(1); } static void step(struct tc3xxk_data *data, u8 buff) { send_9bit(data, TC300K_CCFG); udelay(1); send_9bit(data, buff); udelay(2); } static void setpc(struct tc3xxk_data *data, u16 addr) { u8 buf[4]; int i; buf[0] = 0x02; buf[1] = addr >> 8; buf[2] = addr & 0xff; buf[3] = 0x00; for (i = 0; i < 4; i++) step(data, buf[i]); } static void configure_isp(struct tc3xxk_data *data) { u8 buf[7]; int i; buf[0] = 0x75; buf[1] = 0xFC; buf[2] = 0xAC; buf[3] = 0x75; buf[4] = 0xFC; buf[5] = 0x35; buf[6] = 0x00; /* Step(cmd) */ for (i = 0; i < 7; i++) step(data, buf[i]); } static int tc3xxk_erase_fw(struct tc3xxk_data *data) { int i; u8 state = 0; tc3xxk_reset_for_isp(data, true); /* isp_enable_condition */ send_9bit(data, TC300K_CSYNC1); udelay(9); send_9bit(data, TC300K_CSYNC2); udelay(9); send_9bit(data, TC300K_CSYNC3); usleep_range(150, 160); state = wait_9bit(data); if (state != 0x01) { SENSOR_ERR("isp enable error %d\n", state); return -1; } configure_isp(data); /* Full Chip Erase */ send_9bit(data, TC300K_PCRST); udelay(1); send_9bit(data, TC300K_PECHIP); usleep_range(15000, 15500); state = 0; for (i = 0; i < 100; i++) { udelay(2); send_9bit(data, TC300K_CSYNC3); udelay(1); state = wait_9bit(data); if ((state & 0x04) == 0x00) break; } if (i == 100) { SENSOR_ERR("fail\n"); return -1; } SENSOR_INFO("success\n"); return 0; } static int tc3xxk_write_fw(struct tc3xxk_data *data) { u16 addr = 0; u8 code_data; setpc(data, addr); load(data, TC300K_PWDATA); send_9bit(data, TC300K_LDMODE); udelay(1); while (addr < data->fw_img->fw_len) { code_data = data->fw_img->data[addr++]; load(data, code_data); usleep_range(20, 21); } send_9bit(data, TC300K_PEDISC); udelay(1); return 0; } static int tc3xxk_verify_fw(struct tc3xxk_data *data) { u16 addr = 0; u8 code_data; setpc(data, addr); SENSOR_INFO( "fw code size = %#x (%u)", data->fw_img->fw_len, data->fw_img->fw_len); while (addr < data->fw_img->fw_len) { if ((addr % 0x40) == 0) SENSOR_INFO("fw verify addr = %#x\n", addr); send_9bit(data, TC300K_PRDATA); udelay(2); code_data = wait_9bit(data); udelay(1); if (code_data != data->fw_img->data[addr++]) { SENSOR_ERR("addr : %#x data error (0x%2x)\n", addr - 1, code_data ); return -1; } } SENSOR_INFO("success\n"); return 0; } static void t300k_release_fw(struct tc3xxk_data *data, u8 fw_path) { if (fw_path == FW_INKERNEL) release_firmware(data->fw); else if (fw_path == FW_SDCARD) kfree(data->fw_img); } static int tc3xxk_flash_fw(struct tc3xxk_data *data, u8 fw_path) { int retry = 5; int ret; tc3xxk_config_gpio_i2c(data, 0); do { ret = tc3xxk_erase_fw(data); if (ret) SENSOR_ERR("erase fail(retry=%d)\n", retry); else break; } while (retry-- > 0); if (retry < 0) goto err_tc3xxk_flash_fw; retry = 5; do { tc3xxk_write_fw(data); ret = tc3xxk_verify_fw(data); if (ret) SENSOR_ERR("verify fail(retry=%d)\n", retry); else break; } while (retry-- > 0); tc3xxk_reset_for_isp(data, false); tc3xxk_config_gpio_i2c(data, 1); if (retry < 0) goto err_tc3xxk_flash_fw; return 0; err_tc3xxk_flash_fw: return -1; } static int tc3xxk_crc_check(struct tc3xxk_data *data) { struct i2c_client *client = data->client; int ret; u8 cmd; u8 checksum_h, checksum_l; if ((!data->enabled) || data->fw_downloading) { SENSOR_ERR("can't excute\n"); return -1; } cmd = TC300K_CMD_CAL_CHECKSUM; ret = i2c_smbus_write_byte_data(client, TC300K_CMD_ADDR, cmd); if (ret) { SENSOR_ERR("command fail (%d)\n", ret); return ret; } msleep(TC300K_CHECKSUM_DELAY); ret = i2c_smbus_read_byte_data(client, TC300K_CHECKS_H); if (ret < 0) { SENSOR_ERR("failed to read checksum_h (%d)\n", ret); return ret; } checksum_h = ret; ret = i2c_smbus_read_byte_data(client, TC300K_CHECKS_L); if (ret < 0) { SENSOR_ERR("failed to read checksum_l (%d)\n", ret); return ret; } checksum_l = ret; data->checksum = (checksum_h << 8) | checksum_l; if (data->fw_img->checksum != data->checksum) { SENSOR_ERR("checksum fail - firm checksum(%d), compute checksum(%d)\n", data->fw_img->checksum, data->checksum); return -1; } SENSOR_INFO("success (%d)\n", data->checksum); return 0; } static int tc3xxk_fw_update(struct tc3xxk_data *data, u8 fw_path, bool force, bool probe) { int retry = 4; int ret; if (fw_path == FW_INKERNEL) { ret = load_fw_in_kernel(data); if (ret) return -1; data->fw_ver_bin = data->fw_img->first_fw_ver; data->md_ver_bin = data->fw_img->second_fw_ver; /* read model ver */ ret = tc3xxk_get_md_version(data, probe); if (ret) { SENSOR_ERR("get md version fail\n"); force = 1; } if (data->md_ver != data->md_ver_bin) { SENSOR_INFO( "fw model number = %x ic model number = %x \n", data->md_ver_bin, data->md_ver); force = 1; } if (!force && (data->fw_ver >= data->fw_ver_bin)) { SENSOR_INFO( "do not need firm update (IC:0x%x, BIN:0x%x)(MD IC:0x%x, BIN:0x%x)\n", data->fw_ver, data->fw_ver_bin, data->md_ver, data->md_ver_bin); t300k_release_fw(data, fw_path); return 0; } } else if (fw_path == FW_SDCARD) { ret = load_fw_sdcard(data); if (ret) return -1; } while (retry--) { data->fw_downloading = true; ret = tc3xxk_flash_fw(data, fw_path); data->fw_downloading = false; if (ret) { SENSOR_ERR("tc3xxk_flash_fw fail (%d)\n", retry); continue; } ret = tc3xxk_get_fw_version(data, probe); if (ret) { SENSOR_ERR("tc3xxk_get_fw_version fail (%d)\n", retry); continue; } if (data->fw_ver != data->fw_img->first_fw_ver) { SENSOR_ERR("fw version fail (0x%x, 0x%x)(%d)\n", data->fw_ver, data->fw_img->first_fw_ver, retry); continue; } ret = tc3xxk_get_md_version(data, probe); if (ret) { SENSOR_ERR("tc3xxk_get_md_version fail (%d)\n", retry); continue; } if (data->md_ver != data->fw_img->second_fw_ver) { SENSOR_ERR("md version fail (0x%x, 0x%x)(%d)\n", data->md_ver, data->fw_img->second_fw_ver, retry); continue; } ret = tc3xxk_crc_check(data); if (ret) { SENSOR_ERR("crc check fail (%d)\n", retry); continue; } break; } if (retry > 0) SENSOR_INFO("success\n"); t300k_release_fw(data, fw_path); return ret; } /* * Fw update by parameters: * s | S = TSK FW from kernel binary and compare fw version. * i | I = TSK FW from SD Card and Not compare fw version. * f | F = TSK FW from kernel binary and Not compare fw version. */ static ssize_t tc3xxk_update_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tc3xxk_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int ret; u8 fw_path; bool fw_update_force = false; switch(*buf) { case 's': case 'S': fw_path = FW_INKERNEL; fw_update_force = true; break; case 'i': case 'I': fw_path = FW_SDCARD; break; case 'f': case 'F': fw_path = FW_INKERNEL; fw_update_force = true; break; default: SENSOR_ERR("wrong command fail\n"); data->fw_update_status = TK_UPDATE_FAIL; return count; } data->fw_update_status = TK_UPDATE_DOWN; if (data->irq_check) { data->irq_check = false; disable_irq_wake(client->irq); disable_irq(client->irq); } ret = tc3xxk_fw_update(data, fw_path, fw_update_force, false); if (!data->irq_check) { data->irq_check = true; enable_irq(client->irq); enable_irq_wake(client->irq); } if (ret < 0) { SENSOR_ERR("fail\n"); data->fw_update_status = TK_UPDATE_FAIL; } else data->fw_update_status = TK_UPDATE_PASS; return count; } static ssize_t tc3xxk_firm_status_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; if (data->fw_update_status == TK_UPDATE_PASS) ret = sprintf(buf, "PASS\n"); else if (data->fw_update_status == TK_UPDATE_DOWN) ret = sprintf(buf, "DOWNLOADING\n"); else if (data->fw_update_status == TK_UPDATE_FAIL) ret = sprintf(buf, "FAIL\n"); else ret = sprintf(buf, "NG\n"); return ret; } static ssize_t tc3xxk_firm_version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); return sprintf(buf, "0x%02x%02x\n", data->md_ver_bin, data->fw_ver_bin); } static ssize_t tc3xxk_md_version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); return sprintf(buf, "0x%02x\n", data->md_ver_bin); } static ssize_t tc3xxk_firm_version_read_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = tc3xxk_get_fw_version(data, false); if (ret < 0) SENSOR_ERR("failed to read firmware version (%d)\n", ret); ret = tc3xxk_get_md_version(data, false); if (ret < 0) SENSOR_ERR("failed to read md version (%d)\n", ret); return sprintf(buf, "0x%02x%02x\n", data->md_ver, data->fw_ver); } static ssize_t tc3xxk_md_version_read_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = tc3xxk_get_md_version(data, false); if (ret < 0) SENSOR_ERR("failed to read md version (%d)\n", ret); return sprintf(buf, "0x%02x\n", data->md_ver); } static int read_tc3xxk_register_data(struct tc3xxk_data *data, int read_key_num, int read_offset) { struct i2c_client *client = data->client; int ret; u8 buff[2]; int value; mutex_lock(&data->lock_fac); ret = i2c_smbus_read_i2c_block_data(client, read_key_num + read_offset, TC350K_DATA_SIZE, buff); if (ret != TC350K_DATA_SIZE) { SENSOR_ERR("read fail(%d)\n", ret); value = 0; goto exit; } value = (buff[TC350K_DATA_H_OFFSET] << 8) | buff[TC350K_DATA_L_OFFSET]; SENSOR_INFO("read key num/offset = [0x%X/0x%X], value : [%d]\n", read_key_num, read_offset, value); exit: mutex_unlock(&data->lock_fac); return value; } static int tc3xxk_mode_enable(struct i2c_client *client, u8 cmd) { int ret; ret = i2c_smbus_write_byte_data(client, TC300K_CMD_ADDR, cmd); msleep(15); return ret; } static ssize_t tc3xxk_sar_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%u\n", !data->sar_enable_off); } static ssize_t tc3xxk_sar_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tc3xxk_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int buff; int ret; bool on; int cmd; ret = sscanf(buf, "%d", &buff); if (ret != 1) { SENSOR_ERR("cmd read err\n"); return count; } SENSOR_INFO(" (%d) \n", buff); if (!(buff >= 0 && buff <= 3)) { SENSOR_ERR("wrong command(%d)\n", buff); return count; } /* sar enable param * 0 off * 1 on * 2 force off * 3 force off -> on */ if (data->sar_enable && buff == 1) { SENSOR_INFO("Grip sensor already ON\n"); return count; } else if (!data->sar_enable && buff == 0) { SENSOR_INFO("Grip sensor already OFF\n"); return count; } if (buff == 3) { data->sar_enable_off = 0; SENSOR_INFO("Power back off _ force off -> on (%d)\n", data->sar_enable); if (!data->sar_enable) buff = 1; else return count; } if (data->sar_enable_off) { if (buff == 1) data->sar_enable = true; else data->sar_enable = false; SENSOR_INFO("skip, Power back off _ force off mode (%d)\n", data->sar_enable); return count; } if (buff == 1) { on = true; if (!data->irq_check) { data->irq_check = true; enable_irq(client->irq); enable_irq_wake(client->irq); } cmd = TC300K_CMD_SAR_ENABLE; } else if (buff == 2) { on = false; data->sar_enable_off = 1; if (data->irq_check) { data->irq_check = false; disable_irq_wake(client->irq); disable_irq(client->irq); } cmd = TC300K_CMD_SAR_DISABLE; } else { on = false; if (data->irq_check) { data->irq_check = false; disable_irq_wake(client->irq); disable_irq(client->irq); } cmd = TC300K_CMD_SAR_DISABLE; } ret = tc3xxk_wake_up(data->client, TC300K_CMD_WAKE_UP); ret = tc3xxk_mode_enable(data->client, cmd); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); return count; } if (buff == 1) { data->sar_enable = true; } else { input_report_rel(data->input_dev, REL_MISC, 2); input_sync(data->input_dev); data->grip_event = 0; data->sar_enable = false; } SENSOR_INFO("data:%d on:%d\n", buff, on); return count; } static ssize_t tc3xxk_grip1_threshold_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = read_tc3xxk_register_data(data, TC305K_1GRIP, TC305K_GRIP_THD_PRESS); if (ret < 0) { SENSOR_ERR("fail to read press thd(%d)\n", ret); data->grip_p_thd = 0; return sprintf(buf, "%d\n", 0); } data->grip_p_thd = ret; ret = read_tc3xxk_register_data(data, TC305K_1GRIP, TC305K_GRIP_THD_RELEASE); if (ret < 0) { SENSOR_ERR("fail to read release thd(%d)\n", ret); data->grip_r_thd = 0; return sprintf(buf, "%d\n", 0); } data->grip_r_thd = ret; ret = read_tc3xxk_register_data(data, TC305K_1GRIP, TC305K_GRIP_THD_NOISE); if (ret < 0) { SENSOR_ERR("fail to read noise thd(%d)\n", ret); data->grip_n_thd = 0; return sprintf(buf, "%d\n", 0); } data->grip_n_thd = ret; return sprintf(buf, "%d,%d,%d\n", data->grip_p_thd, data->grip_r_thd, data->grip_n_thd ); } static ssize_t tc3xxk_grip2_threshold_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = read_tc3xxk_register_data(data, TC305K_2GRIP, TC305K_GRIP_THD_PRESS); if (ret < 0) { SENSOR_ERR("fail to read press thd(%d)\n", ret); data->grip_p_thd = 0; return sprintf(buf, "%d\n", 0); } data->grip_p_thd = ret; ret = read_tc3xxk_register_data(data, TC305K_2GRIP, TC305K_GRIP_THD_RELEASE); if (ret < 0) { SENSOR_ERR("fail to read release thd(%d)\n", ret); data->grip_r_thd = 0; return sprintf(buf, "%d\n", 0); } data->grip_r_thd = ret; ret = read_tc3xxk_register_data(data, TC305K_2GRIP, TC305K_GRIP_THD_NOISE); if (ret < 0) { SENSOR_ERR("fail to read noise thd(%d)\n", ret); data->grip_n_thd = 0; return sprintf(buf, "%d\n", 0); } data->grip_n_thd = ret; return sprintf(buf, "%d,%d,%d\n", data->grip_p_thd, data->grip_r_thd, data->grip_n_thd ); } static ssize_t tc3xxk_total_cap1_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int ret; ret = i2c_smbus_read_byte_data(client, TC305K_1GRIP + TC305K_GRIP_TOTAL_CAP); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); return sprintf(buf, "%d\n", 0); } return sprintf(buf, "%d\n", ret); } static ssize_t tc3xxk_total_cap2_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int ret; ret = i2c_smbus_read_byte_data(client, TC305K_2GRIP + TC305K_GRIP_TOTAL_CAP); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); return sprintf(buf, "%d\n", 0); } return sprintf(buf, "%d\n", ret); } static ssize_t grip_ref_cap_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int ret; ret = i2c_smbus_read_byte_data(client, TC305K_GRIP_REF_CAP); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); return sprintf(buf, "%d\n", 0); } return sprintf(buf, "%d\n", ret); } static ssize_t tc3xxk_grip1_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = read_tc3xxk_register_data(data, TC305K_1GRIP, TC305K_GRIP_DIFF_DATA); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); data->grip_s1 = 0; return sprintf(buf, "%d\n", 0); } data->grip_s1 = ret; return sprintf(buf, "%d\n", data->grip_s1); } static ssize_t tc3xxk_grip2_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = read_tc3xxk_register_data(data, TC305K_2GRIP, TC305K_GRIP_DIFF_DATA); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); data->grip_s1 = 0; return sprintf(buf, "%d\n", 0); } data->grip_s1 = ret; return sprintf(buf, "%d\n", data->grip_s1); } static ssize_t tc3xxk_grip1_baseline_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = read_tc3xxk_register_data(data, TC305K_1GRIP, TC305K_GRIP_BASELINE); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); data->grip_baseline = 0; return sprintf(buf, "%d\n", 0); } data->grip_baseline = ret; return sprintf(buf, "%d\n", data->grip_baseline); } static ssize_t tc3xxk_grip2_baseline_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = read_tc3xxk_register_data(data, TC305K_2GRIP, TC305K_GRIP_BASELINE); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); data->grip_baseline = 0; return sprintf(buf, "%d\n", 0); } data->grip_baseline = ret; return sprintf(buf, "%d\n", data->grip_baseline); } static ssize_t tc3xxk_grip1_raw_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = read_tc3xxk_register_data(data, TC305K_1GRIP, TC305K_GRIP_RAW_DATA); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); data->grip_raw1 = 0; data->grip_raw2 = 0; return sprintf(buf, "%d\n", 0); } data->grip_raw1 = ret; data->grip_raw2 = 0; return sprintf(buf, "%d,%d\n", data->grip_raw1, data->grip_raw2); } static ssize_t tc3xxk_grip2_raw_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = read_tc3xxk_register_data(data, TC305K_2GRIP, TC305K_GRIP_RAW_DATA); if (ret < 0) { SENSOR_ERR("fail(%d)\n", ret); data->grip_raw1 = 0; data->grip_raw2 = 0; return sprintf(buf, "%d\n", 0); } data->grip_raw1 = ret; data->grip_raw2 = 0; return sprintf(buf, "%d,%d\n", data->grip_raw1, data->grip_raw2); } static ssize_t tc3xxk_grip_gain_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d,%d,%d,%d\n", 0, 0, 0, 0); } static ssize_t tc3xxk_grip_check_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); SENSOR_ERR("event:%d, diff: %d\n", data->grip_event, data->diff); return sprintf(buf, "%d\n", data->grip_event); } static ssize_t tc3xxk_grip_sw_reset(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tc3xxk_data *data = dev_get_drvdata(dev); int buff; int ret; ret = sscanf(buf, "%d", &buff); if (ret != 1) { SENSOR_ERR("cmd read err\n"); return count; } if (!(buff == 1)) { SENSOR_ERR("wrong command(%d)\n", buff); return count; } data->grip_event = 0; SENSOR_INFO("data(%d)\n", buff); tc3xxk_grip_cal_reset(data); return count; } static ssize_t grip_sensing_change(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret, buff; ret = sscanf(buf, "%d", &buff); if (ret != 1) { SENSOR_ERR("cmd read err\n"); return count; } if (!(buff == 0 || buff == 1)) { SENSOR_ERR("wrong command(%d)\n", buff); return count; } grip_sar_sensing(data, buff); SENSOR_INFO("earjack (%d)\n", buff); return count; } #ifdef CONFIG_SEC_FACTORY static ssize_t tc3xxk_grip_irq_count_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int result = 0; if (data->irq_count) result = -1; SENSOR_INFO("\n"); return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", result, data->irq_count, data->max_diff); } static ssize_t tc3xxk_grip_irq_count_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tc3xxk_data *data = dev_get_drvdata(dev); u8 onoff; int ret; ret = kstrtou8(buf, 10, &onoff); if (ret < 0) { SENSOR_ERR("kstrtou8 failed.(%d)\n", ret); return count; } mutex_lock(&data->lock_fac); if (onoff == 0) { data->abnormal_mode = 0; } else if (onoff == 1) { data->abnormal_mode = 1; data->irq_count = 0; data->max_diff = 0; } else { SENSOR_ERR("unknown value %d\n", onoff); } mutex_unlock(&data->lock_fac); SENSOR_INFO("%d\n", onoff); return count; } #endif //#ifdef CONFIG_SEC_FACTORY static ssize_t grip_chip_name(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", MODEL_NAME); } static ssize_t grip_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", VENDOR_NAME); } static ssize_t grip_crc_check_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); int ret; ret = tc3xxk_crc_check(data); return sprintf(buf, (ret == 0) ? "OK,%x\n" : "NG,%x\n", data->checksum); } static ssize_t tc3xxk_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tc3xxk_data *data = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%d\n", data->sar_enable); } static DEVICE_ATTR(grip_firm_update, 0220, NULL, tc3xxk_update_store); static DEVICE_ATTR(grip_firm_update_status, 0444, tc3xxk_firm_status_show, NULL); static DEVICE_ATTR(grip_firm_version_phone, 0444, tc3xxk_firm_version_show, NULL); static DEVICE_ATTR(grip_firm_version_panel, 0444, tc3xxk_firm_version_read_show, NULL); static DEVICE_ATTR(grip_md_version_phone, 0444, tc3xxk_md_version_show, NULL); static DEVICE_ATTR(grip_md_version_panel, 0444, tc3xxk_md_version_read_show, NULL); static DEVICE_ATTR(grip_threshold, 0444, tc3xxk_grip1_threshold_show, NULL); static DEVICE_ATTR(grip2ch_threshold, 0444, tc3xxk_grip2_threshold_show, NULL); static DEVICE_ATTR(grip_total_cap, 0444, tc3xxk_total_cap1_show, NULL); static DEVICE_ATTR(grip_total_cap2ch, 0444, tc3xxk_total_cap2_show, NULL); static DEVICE_ATTR(grip_sar_enable, 0664, tc3xxk_sar_enable_show, tc3xxk_sar_enable_store); static DEVICE_ATTR(grip_sw_reset, 0220, NULL, tc3xxk_grip_sw_reset); static DEVICE_ATTR(grip_earjack, 0220, NULL, grip_sensing_change); static DEVICE_ATTR(grip, 0444, tc3xxk_grip1_show, NULL); static DEVICE_ATTR(grip2ch, 0444, tc3xxk_grip2_show, NULL); static DEVICE_ATTR(grip_baseline, 0444, tc3xxk_grip1_baseline_show, NULL); static DEVICE_ATTR(grip2ch_baseline, 0444, tc3xxk_grip2_baseline_show, NULL); static DEVICE_ATTR(grip_raw, 0444, tc3xxk_grip1_raw_show, NULL); static DEVICE_ATTR(grip2ch_raw, 0444, tc3xxk_grip2_raw_show, NULL); static DEVICE_ATTR(grip_gain, 0444, tc3xxk_grip_gain_show, NULL); static DEVICE_ATTR(grip_check, 0444, tc3xxk_grip_check_show, NULL); #ifdef CONFIG_SEC_FACTORY static DEVICE_ATTR(grip_irq_count, 0664, tc3xxk_grip_irq_count_show, tc3xxk_grip_irq_count_store); #endif static DEVICE_ATTR(grip_ref_cap, 0444, grip_ref_cap_show, NULL); static DEVICE_ATTR(name, 0444, grip_chip_name, NULL); static DEVICE_ATTR(vendor, 0444, grip_vendor_show, NULL); static DEVICE_ATTR(grip_crc_check, 0444, grip_crc_check_show, NULL); static struct device_attribute *sec_grip_attributes[] = { &dev_attr_grip_firm_update, &dev_attr_grip_firm_update_status, &dev_attr_grip_firm_version_phone, &dev_attr_grip_firm_version_panel, &dev_attr_grip_md_version_phone, &dev_attr_grip_md_version_panel, &dev_attr_grip_threshold, &dev_attr_grip2ch_threshold, &dev_attr_grip_total_cap, &dev_attr_grip_total_cap2ch, &dev_attr_grip_sar_enable, &dev_attr_grip_sw_reset, &dev_attr_grip_earjack, &dev_attr_grip, &dev_attr_grip2ch, &dev_attr_grip_baseline, &dev_attr_grip2ch_baseline, &dev_attr_grip_raw, &dev_attr_grip2ch_raw, &dev_attr_grip_gain, &dev_attr_grip_check, #ifdef CONFIG_SEC_FACTORY &dev_attr_grip_irq_count, #endif &dev_attr_grip_ref_cap, &dev_attr_name, &dev_attr_vendor, &dev_attr_grip_crc_check, NULL, }; static DEVICE_ATTR(enable, 0664, tc3xxk_enable_show, tc3xxk_sar_enable_store); static struct attribute *tc3xxk_attributes[] = { &dev_attr_enable.attr, NULL }; static struct attribute_group tc3xxk_attribute_group = { .attrs = tc3xxk_attributes }; #if defined (CONFIG_VBUS_NOTIFIER) static int tc3xxk_vbus_notification(struct notifier_block *nb, unsigned long cmd, void *data) { struct tc3xxk_data *tkey_data = container_of(nb, struct tc3xxk_data, vbus_nb); struct i2c_client *client = tkey_data->client; vbus_status_t vbus_type = *(vbus_status_t *)data; int ret; static int pre_attach; if (pre_attach == vbus_type) return 0; SENSOR_INFO("cmd=%lu, vbus_type=%d, ignore=%d\n", cmd, vbus_type, tkey_data->ignore_vbus_event); if (tkey_data->ignore_vbus_event) { tkey_data->ignore_vbus_event = false; return 0; } switch (vbus_type) { case STATUS_VBUS_HIGH: SENSOR_INFO("attach\n"); ret = tc3xxk_wake_up(client, TC300K_CMD_WAKE_UP); ret = tc3xxk_mode_enable(client, TC300K_CMD_TA_ON); if (ret < 0) SENSOR_ERR("TA mode ON fail(%d)\n", ret); break; case STATUS_VBUS_LOW: SENSOR_INFO("detach\n"); ret = tc3xxk_wake_up(client, TC300K_CMD_WAKE_UP); ret = tc3xxk_mode_enable(client, TC300K_CMD_TA_OFF); if (ret < 0) SENSOR_ERR("TA mode OFF fail(%d)\n", ret); break; default: break; } pre_attach = vbus_type; return 0; } #endif static int tc3xxk_fw_check(struct tc3xxk_data *data) { int ret; if (data->pdata->bringup) { SENSOR_INFO("firmware update skip, bring up\n"); return 0; } ret = tc3xxk_get_fw_version(data, true); if (ret < 0) { SENSOR_ERR("i2c fail...[%d], addr[%d]\n", ret, data->client->addr); data->fw_ver = 0xFF; SENSOR_INFO("firmware is blank or i2c fail, try flash firmware to grip\n"); } if (data->fw_ver == 0xFF) { SENSOR_INFO( "fw version 0xFF, Excute firmware update!\n"); ret = tc3xxk_fw_update(data, FW_INKERNEL, true, true); if (ret) return -1; } else { ret = tc3xxk_fw_update(data, FW_INKERNEL, false, true); if (ret) return -1; } return 0; } static int tc3xxk_pinctrl_init(struct tc3xxk_data *data) { struct device *dev = &data->client->dev; int i; SENSOR_INFO("\n"); // IRQ data->pinctrl_irq = devm_pinctrl_get(dev); if (IS_ERR(data->pinctrl_irq)) { SENSOR_INFO("Failed to get irq pinctrl\n"); data->pinctrl_irq = NULL; goto i2c_pinctrl_get; } #if 0 for (i = 0; i < 2; ++i) { data->pin_state[i] = pinctrl_lookup_state(data->pinctrl_irq, str_states[i]); if (IS_ERR(data->pin_state[i])) { SENSOR_INFO("Failed to get irq pinctrl state\n"); devm_pinctrl_put(data->pinctrl_irq); data->pinctrl_irq = NULL; goto i2c_pinctrl_get; } } #endif i2c_pinctrl_get: /* for h/w i2c */ dev = data->client->dev.parent->parent; SENSOR_INFO("use dev's parent\n"); // I2C data->pinctrl_i2c = devm_pinctrl_get(dev); if (IS_ERR(data->pinctrl_i2c)) { SENSOR_ERR("Failed to get i2c pinctrl\n"); goto err_pinctrl_get_i2c; } for (i = 2; i < 4; ++i) { data->pin_state[i] = pinctrl_lookup_state(data->pinctrl_i2c, str_states[i]); if (IS_ERR(data->pin_state[i])) { SENSOR_ERR("Failed to get i2c pinctrl state\n"); goto err_pinctrl_get_state_i2c; } } return 0; err_pinctrl_get_state_i2c: devm_pinctrl_put(data->pinctrl_i2c); err_pinctrl_get_i2c: return -ENODEV; } static int tc3xxk_pinctrl(struct tc3xxk_data *data, int state) { struct pinctrl *pinctrl_i2c = data->pinctrl_i2c; struct pinctrl *pinctrl_irq = data->pinctrl_irq; int ret=0; switch (state) { case I_STATE_ON_IRQ: case I_STATE_OFF_IRQ: if (pinctrl_irq) ret = pinctrl_select_state(pinctrl_irq, data->pin_state[state]); break; case I_STATE_ON_I2C: case I_STATE_OFF_I2C: if (pinctrl_i2c) ret = pinctrl_select_state(pinctrl_i2c, data->pin_state[state]); break; } if (ret < 0) { SENSOR_ERR( "Failed to configure tc3xxk_pinctrl state[%d]\n", state); return ret; } return 0; } static void tc3xxk_config_gpio_i2c(struct tc3xxk_data *data, int onoff) { SENSOR_ERR("\n"); tc3xxk_pinctrl(data, onoff ? I_STATE_ON_I2C : I_STATE_OFF_I2C); mdelay(100); } static int tc3xxk_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tc3xxk_platform_data *pdata; struct tc3xxk_data *data; struct input_dev *input_dev; int ret = 0; SENSOR_INFO("\n"); #ifdef CONFIG_BATTERY_SAMSUNG if (lpcharge == 1) { SENSOR_ERR("Do not load driver due to : lpm %d\n", lpcharge); return -ENODEV; } #endif if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { SENSOR_ERR("i2c_check_functionality fail\n"); return -EIO; } if (client->dev.of_node) { pdata = devm_kzalloc(&client->dev, sizeof(struct tc3xxk_platform_data), GFP_KERNEL); if (!pdata) { SENSOR_ERR("Failed to allocate memory\n"); ret = -ENOMEM; goto err_alloc_data; } ret = tc3xxk_parse_dt(&client->dev, pdata); if (ret) goto err_alloc_data; }else pdata = client->dev.platform_data; data = kzalloc(sizeof(struct tc3xxk_data), GFP_KERNEL); if (!data) { SENSOR_ERR("Failed to allocate memory\n"); ret = -ENOMEM; goto err_alloc_data; } data->pdata = pdata; input_dev = input_allocate_device(); if (!input_dev) { SENSOR_ERR("Failed to allocate memory for input device\n"); ret = -ENOMEM; goto err_alloc_input; } data->input_dev = input_dev; data->client = client; if (data->pdata == NULL) { SENSOR_ERR("failed to get platform data\n"); input_free_device(input_dev); ret = -EINVAL; goto err_platform_data; } data->irq = -1; mutex_init(&data->lock_fac); wake_lock_init(&data->grip_wake_lock, WAKE_LOCK_SUSPEND, "grip wake lock"); INIT_DELAYED_WORK(&data->debug_work, tc3xxk_debug_work_func); pdata->power = tc3xxk_grip_power; i2c_set_clientdata(client, data); tc3xxk_gpio_request(data); ret = tc3xxk_pinctrl_init(data); if (ret < 0) { SENSOR_ERR( "Failed to init pinctrl: %d\n", ret); goto err_pinctrl_init; } if(pdata->boot_on_ldo){ data->pdata->power(data, true); } else { data->pdata->power(data, true); msleep(200); } data->enabled = true; client->irq = gpio_to_irq(pdata->gpio_int); ret = tc3xxk_fw_check(data); if (ret) { SENSOR_ERR( "failed to firmware check(%d)\n", ret); goto err_fw_check; } snprintf(data->phys, sizeof(data->phys), "%s/input0", dev_name(&client->dev)); input_dev->name = MODULE_NAME; // TSN : TRY to parse form Match table input_dev->id.bustype = BUS_I2C; data->grip_ev_val = grip_ev; data->grip_num = ARRAY_SIZE(grip_ev)/2; SENSOR_INFO( "number of grips = %d\n", data->grip_num); input_set_capability(input_dev, EV_REL, REL_MISC); input_set_drvdata(input_dev, data); ret = input_register_device(input_dev); if (ret) { SENSOR_ERR("fail to register input_dev (%d)\n", ret); goto err_register_input_dev; } ret = sensors_create_symlink(&data->input_dev->dev.kobj, data->input_dev->name); if (ret < 0) { SENSOR_ERR("Failed to create sysfs symlink\n"); goto err_sysfs_symlink; } ret = sysfs_create_group(&data->input_dev->dev.kobj, &tc3xxk_attribute_group); if (ret < 0) { SENSOR_ERR("Failed to create sysfs group\n"); goto err_sysfs_group; } ret = sensors_register(&data->dev, data, sec_grip_attributes, MODULE_NAME); if (ret) { SENSOR_ERR("could not register grip_sensor(%d)\n", ret); goto err_sensor_register; } data->dev = &client->dev; #if defined (CONFIG_VBUS_NOTIFIER) //ignore the 1st vbus detach event when probe done data->ignore_vbus_event = true; vbus_notifier_register(&data->vbus_nb, tc3xxk_vbus_notification, VBUS_NOTIFY_DEV_CHARGER); #endif ret = request_threaded_irq(client->irq, NULL, tc3xxk_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, MODEL_NAME, data); if (ret < 0) { SENSOR_ERR("fail to request irq (%d).\n", pdata->gpio_int); goto err_request_irq; } disable_irq(client->irq); data->irq = pdata->gpio_int; data->irq_check = false; // default working on stop mode ret = tc3xxk_wake_up(data->client, TC300K_CMD_WAKE_UP); ret = tc3xxk_mode_enable(data->client, TC300K_CMD_SAR_DISABLE); if (ret < 0) { SENSOR_ERR("Change mode fail(%d)\n", ret); } ret = tc3xxk_mode_check(client); if (ret >= 0) { data->sar_enable = !!(ret & TC300K_MODE_SAR); SENSOR_INFO("mode %d, sar %d\n", ret, data->sar_enable); } device_init_wakeup(&client->dev, true); schedule_delayed_work(&data->debug_work, msecs_to_jiffies(20000)); SENSOR_INFO("done\n"); return 0; err_request_irq: sensors_unregister(data->dev, sec_grip_attributes); err_sensor_register: sysfs_remove_group(&input_dev->dev.kobj, &tc3xxk_attribute_group); err_sysfs_group: sensors_remove_symlink(&data->input_dev->dev.kobj, input_dev->name); err_sysfs_symlink: input_unregister_device(input_dev); input_dev = NULL; err_register_input_dev: err_fw_check: data->pdata->power(data, false); err_pinctrl_init: mutex_destroy(&data->lock_fac); wake_lock_destroy(&data->grip_wake_lock); err_platform_data: err_alloc_input: kfree(data); err_alloc_data: SENSOR_ERR("failed\n"); return ret; } static int tc3xxk_remove(struct i2c_client *client) { struct tc3xxk_data *data = i2c_get_clientdata(client); device_init_wakeup(&client->dev, false); wake_lock_destroy(&data->grip_wake_lock); free_irq(client->irq, data); input_unregister_device(data->input_dev); mutex_destroy(&data->lock_fac); data->pdata->power(data, false); gpio_free(data->pdata->gpio_int); gpio_free(data->pdata->gpio_sda); gpio_free(data->pdata->gpio_scl); kfree(data); return 0; } static void tc3xxk_shutdown(struct i2c_client *client) { struct tc3xxk_data *data = i2c_get_clientdata(client); SENSOR_INFO("\n"); cancel_delayed_work_sync(&data->debug_work); device_init_wakeup(&client->dev, false); wake_lock_destroy(&data->grip_wake_lock); disable_irq(client->irq); data->pdata->power(data, false); } static int tc3xxk_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct tc3xxk_data *data = i2c_get_clientdata(client); SENSOR_INFO("sar_enable(%d)\n", data->sar_enable); cancel_delayed_work_sync(&data->debug_work); return 0; } static int tc3xxk_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct tc3xxk_data *data = i2c_get_clientdata(client); SENSOR_INFO("sar_enable(%d)\n", data->sar_enable); schedule_delayed_work(&data->debug_work, msecs_to_jiffies(1000)); return 0; } static const struct i2c_device_id tc3xxk_id[] = { {MODEL_NAME, 0}, { } }; MODULE_DEVICE_TABLE(i2c, tc3xxk_id); static struct of_device_id coreriver_match_table[] = { { .compatible = "coreriver,tc3xx-grip",}, { }, }; static const struct dev_pm_ops tc3xxk_pm_ops = { .suspend = tc3xxk_suspend, .resume = tc3xxk_resume, }; static struct i2c_driver tc3xxk_driver = { .probe = tc3xxk_probe, .remove = tc3xxk_remove, .shutdown = tc3xxk_shutdown, .driver = { .name = MODEL_NAME, .owner = THIS_MODULE, .pm = &tc3xxk_pm_ops, .of_match_table = coreriver_match_table, }, .id_table = tc3xxk_id, }; static int __init tc3xxk_init(void) { return i2c_add_driver(&tc3xxk_driver); } static void __exit tc3xxk_exit(void) { i2c_del_driver(&tc3xxk_driver); } module_init(tc3xxk_init); module_exit(tc3xxk_exit); MODULE_AUTHOR("Samsung Electronics"); MODULE_DESCRIPTION("Grip Sensor driver for Coreriver TC3XXK"); MODULE_LICENSE("GPL");