blob: 3cef753d3f193270cad2e2b3cd0d729094e4681e [file] [log] [blame]
/* tc3xxk.c -- Linux driver for coreriver chip as grip
*
* Copyright (C) 2013 Samsung Electronics Co.Ltd
* Author: Junkyeong Kim <jk0430.kim@samsung.com>
*
* 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 <linux/delay.h>
#include <linux/firmware.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/wakelock.h>
#include <linux/workqueue.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/regulator/consumer.h>
#include <linux/sec_class.h>
#include <linux/pinctrl/consumer.h>
#ifdef CONFIG_BATTERY_SAMSUNG
#include <linux/sec_batt.h>
#endif
#include "tc3xxk.h"
#if defined (CONFIG_VBUS_NOTIFIER)
#include <linux/muic/muic.h>
#include <linux/muic/muic_notifier.h>
#include <linux/vbus_notifier.h>
#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/sec_key/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;
#ifdef CONFIG_SEC_FACTORY
int irq_count;
int abnormal_mode;
s32 diff;
s32 max_diff;
#endif
#if defined (CONFIG_VBUS_NOTIFIER)
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);
msleep(10);
return ret;
}
static void grip_sar_sensing(struct tc3xxk_data *data, bool on)
{
/* enable/disable sar sensing
* need to disable when earjack is connected (FM radio can't work normally)
*/
}
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)\n", 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){
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(
"grip %s : %s(0x%02X) ver0x%02x\n",
data->grip_ev_val[i].grip_status? "P" : "R",
data->grip_ev_val[i].grip_name, grip_val,
data->fw_ver);
#ifdef CONFIG_SEC_FACTORY
data->diff = read_tc3xxk_register_data(data, TC305K_1GRIP, TC305K_GRIP_DIFF_DATA);
if (data->abnormal_mode) {
if (data->grip_event) {
if (data->max_diff < data->diff)
data->max_diff = data->diff;
data->irq_count++;
}
}
#endif
}
}
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)
{
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, false);
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, false);
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, false);
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);
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];
mutex_unlock(&data->lock_fac);
SENSOR_INFO("read key num/offset = [0x%X/0x%X], value : [%d]\n",
read_key_num, read_offset, value);
exit:
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\n", data->grip_event);
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;
SENSOR_INFO("cmd=%lu, vbus_type=%d\n", cmd, vbus_type);
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;
}
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);
if (ret)
return -1;
} else {
ret = tc3xxk_fw_update(data, FW_INKERNEL, false);
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;
}
input_dev->name = MODULE_NAME;
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(input_dev);
if (ret < 0) {
SENSOR_ERR("Failed to create sysfs symlink\n");
goto err_sysfs_symlink;
}
ret = sysfs_create_group(&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)
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(input_dev);
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");