diff options
Diffstat (limited to 'drivers/input/misc/ewtsa.c')
| -rw-r--r-- | drivers/input/misc/ewtsa.c | 2763 |
1 files changed, 2763 insertions, 0 deletions
diff --git a/drivers/input/misc/ewtsa.c b/drivers/input/misc/ewtsa.c new file mode 100644 index 00000000..bdb0b973 --- /dev/null +++ b/drivers/input/misc/ewtsa.c @@ -0,0 +1,2763 @@ +/* + * linux/drivers/input/misc/ewtsa.c + * + * Copyright 2010-2011 Panasonic Electronic Devices. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*include files*/ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/regulator/consumer.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <mach/hardware.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/jiffies.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/spinlock.h> + +/* configurable */ +#define GYRO_MOUNT_SWAP_XY 0 /* swap X, Y */ +#define GYRO_MOUNT_REVERSE_X 0 /* reverse X */ +#define GYRO_MOUNT_REVERSE_Y 0 /* reverse Y */ +#define GYRO_MOUNT_REVERSE_Z 0 /* reverse Z */ +#define GYRO_VER3_ES1 0 +#define GYRO_VER3_ES3 0 +#define GYRO_VER3_ES4 1 +#define GYRO_REGISTER_MAP2 0 +#define GYRO_SPI_INTERFACE 0 + +#define USE_GPIO_DRDY_PIN 0 +#define USE_GPIO_DIAG_PIN 0 +#define USE_GPIO_WINDOW_PIN 0 + +/* macro defines */ +#define CHIP_ID 0x68 +#define DEVICE_NAME "ewtsa" +#define EWTSA_ON 1 +#define EWTSA_OFF 0 +#define WINDOW_PIN 14 +#define DRDY_PIN 12 +#define DIAG_PIN 11 +#define DIAG_ENABLE 0 +#define DIAG_DISABLE 1 +#define MAX_VALUE 32768 + +/* ewtsa_delay parameter */ +#define DELAY_THRES_MIN 1 +#define DELAY_THRES_1 4 +#define DELAY_THRES_2 9 /* msec x 90% */ +#define DELAY_THRES_3 18 +#define DELAY_THRES_4 45 +#define DELAY_THRES_5 90 +#define DELAY_THRES_6 128 +#define DELAY_THRES_MAX 255 +#define DELAY_DLPF_0 0 +#define DELAY_DLPF_1 1 +#define DELAY_DLPF_2 2 +#define DELAY_DLPF_3 3 +#define DELAY_DLPF_4 4 +#define DELAY_DLPF_5 5 +#define DELAY_DLPF_6 6 +#define DELAY_INTMIN_THRES 9 +#define DELAY_INT8K_THRES 79 +#define DELAY_THRES_FIFO 150 + +/* ewtsa_range parameter */ +#define DYNRANGE_250 0x00 +#define DYNRANGE_500 0x01 +#define DYNRANGE_1000 0x02 +#define DYNRANGE_2000 0x03 + +#define DATA_RATE_1 0x01 +#define DATA_RATE_5 0x05 +#define DATA_RATE_8 0x08 +#define DATA_RATE_10 0x0A + +/* ewtsa_sleep parameter */ +#define SLEEP_OFF 0 +#define SLEEP_ON 1 +#define SLEEP_ALLRESET 2 + +/* ewtsa_calib parameter */ +#define BOOST_TIME_500MS 0 +#define BOOST_TIME_300MS 1 +#define BOOST_TIME_200MS 2 +#define BOOST_TIME_100MS 3 +#define BOOST_FS_48KHZ 0 +#define BOOST_FS_16KHZ 1 +#define HPF_001HZ 0 +#define HPF_002HZ 1 +#define MASK_CLIP 0 +#define MASK_NON_CLIP 1 +#define THRESHOLD_ON 0 +#define THRESHOLD_OFF 1 +#define LAG_NON 0 +#define LAG_5SMP 1 +#define LAG_10SMP 2 +#define LAG_20SMP 3 +#define W1_THRES_LEVEL_2DPS 0 +#define W1_THRES_LEVEL_5DPS 1 +#define W1_THRES_LEVEL_10DPS 2 +#define W1_THRES_LEVEL_15DPS 3 +#define REFERENCE_WAIT 16 +#define W1_THRES_CENTER_COEF 25000 +#define CALIB_FS_62_5HZ 0 +#define CALIB_FS_31_25HZ 1 + +/* ewtsa_configuration parameter */ +#define BYPASS_MODE 0 +#define FIFO_MODE 1 +#define FIFO_MAX 32 +#define FIFO_MIN_DELAY 5 +#define MAP_NAME_SIZE 4 +#define INTERFACE_NAME_SIZE 3 +#define CMD_SIZE_3 3 +#define CMD_SIZE_4 4 +#define THRES_CENTER_MIN 0 +#define THRES_CENTER_MAX 359 +#define THRES_CENTER_INIT_X 160 +#define THRES_CENTER_INIT_Y 160 +#define THRES_CENTER_INIT_Z 160 + +/* EWTSA_system_restart parameter */ +#define RST_REG_INIT_OFF 0x00 +#define RST_REG_INIT_RANGE 0x01 +#define RST_REG_INIT_DELAY 0x02 +#define RST_REG_INIT_ALL 0xFF + +/* event mode */ +#define EWTSA_POLLING_MODE 0 +#define EWTSA_INTERUPT_MODE 1 + +/* ewtsa register address */ +#define REG_SLAD 0x00 +#define REG_FIFO_DRDY 0x10 +#define REG_FIFO_CTRL1 0x13 +#define REG_FIFO_CTRL2 0x14 +#define REG_DATA_RATE 0x15 +#define REG_FS_DLPF_CTRL 0x16 +#define REG_INT_CTRL 0x17 +#define REG_CTRL_REG2 0x18 +#define REG_CTRL_REG3 0x19 +#define REG_INT_STAT 0x1A +#define REG_TEMP_H 0x1B +#define REG_TEMP_L 0x1C +#define REG_OUTX_H 0x1D +#define REG_OUTX_L 0x1E +#define REG_OUTY_H 0x1F +#define REG_OUTY_L 0x20 +#define REG_OUTZ_H 0x21 +#define REG_OUTZ_L 0x22 +#define REG_CTRL_REG5 0x24 +#define REG_REFERENCE 0x25 +#define REG_STATUS_REG 0x27 +#define REG_DIGITAL_CAL 0x29 +#define REG_DIAG_CTRL 0x2B +#define REG_FIFO_DM 0x2F +#define REG_DIAG_MONI 0x39 +#define REG_SLEEP_CTRL 0x3E +#define REG_W1THX_H 0x46 +#define REG_W1THX_L 0x47 +#define REG_W1THY_H 0x48 +#define REG_W1THY_L 0x49 +#define REG_W1THZ_H 0x4A +#define REG_W1THZ_L 0x4B +#define REG_SOC_CNT1 0x4C +#define REG_SOC_CNT2 0x4D +#define REG_SLFSLP_CNT 0x4F +#define REG_SPITYPE 0x60 +#define REG_MBURST_ALL 0xFF + +/* ewtsa register map2 address */ +#define REG2_CTRL_REG1 0x20 + +/* ewtsa register param */ +#define INT_CTRL_WTMON_ENABLE 0x0D +#define INT_CTRL_WTMON_DISABLE 0x00 +#define DIGITAL_CAL_ENABLE 0x00 +#define DIGITAL_CAL_DISABLE 0x01 +#define SLEEP_CTRL_ACTIVATE 0x44 +#define SLEEP_CTRL_SLEEP 0x04 +#define SLEEP_CTRL_ALLRSTSLEEP 0x00 +#define SLEEP_CTRL_LOGIC_RST 0x80 +#define SOC_CNT1_BOOST_ON 0x01 +#define SOC_CNT1_WIN_DIS 0x70 +#define SOC_CNT2_SOCCLK_ON 0x40 +#define SOC_CNT2_SOCCLK_OFF 0x00 +#define INT_CTRL_INT_ENABLE 0x01 +#define INT_CTRL_INT_DISABLE 0x00 +#define INT_CTRL_INT_WTMON_EN 0x08 +#define CTRL_REG2_REF_MODE 0x10 +#define CTRL_REG2_NOR_MODE 0x60 +#define CTRL_REG2_HPCF 0x09 +#define CTRL_REG5_FIFO_EN 0x53 +#define CTRL_REG5_INIT 0x13 +#define FIFO_DRDY_DITH_EN 0x02 +#define FIFO_DRDY_INIT 0x17 +#define CTRL_REG3_WTM_DIS 0x00 +#define CTRL_REG3_WTM_EN 0x04 +#define STATUS_REG_OVERRUN 0xF0 +#define FIFO_CTRL1_CLEAR 0x02 + +/* ewtsa register map2 param */ +#define CTRL_REG1_SLEEP 0x07 +#define CTRL_REG1_ACTIVATE 0x0F + +/* ewtsa interrupt control */ +#define EWSTA_INT_CLEAR 0x00 +#define EWSTA_INT_SKIP 0x01 + +/* EWTSA_set_calibration param */ +#define EWTSA_RANGE_0 250 +#define EWTSA_RANGE_1 500 +#define EWTSA_RANGE_2 1000 +#define EWTSA_RANGE_3 2000 +#define EWTSA_BOOST_TIME_0 500 +#define EWTSA_BOOST_TIME_1 300 +#define EWTSA_BOOST_TIME_2 200 +#define EWTSA_BOOST_TIME_3 100 +#define EWTSA_W1_THRES_LV_0 2 +#define EWTSA_W1_THRES_LV_1 5 +#define EWTSA_W1_THRES_LV_2 10 +#define EWTSA_W1_THRES_LV_3 15 + +/* init param */ +#define SLEEP_INIT_VAL SLEEP_ALLRESET +#define FIFO_TYPE_INIT_VAL BYPASS_MODE +#define DELAY_INIT_VAL DELAY_THRES_1 +#define RANGE_INIT_VAL DYNRANGE_1000 +#define DLPF_INIT_VAL DELAY_DLPF_2 +#define CALIB_FUNC_INIT_VAL EWTSA_ON +#if GYRO_VER3_ES4 +#define CALIB_BTIM_INIT_VAL BOOST_TIME_100MS +#else +#define CALIB_BTIM_INIT_VAL BOOST_TIME_500MS +#endif +#define CALIB_FS_INIT_VAL CALIB_FS_62_5HZ +#define CALIB_RST_INIT_VAL EWTSA_ON +#define CALIB_BFS_INIT_VAL BOOST_FS_48KHZ +#define CALIB_CLK_INIT_VAL EWTSA_ON +#define CALIB_HPF_INIT_VAL HPF_002HZ +#if GYRO_VER3_ES4 +#define CALIB_LAG_INIT_VAL LAG_5SMP +#else +#define CALIB_LAG_INIT_VAL LAG_10SMP +#endif +#define W1_FUNC_INIT_VAL THRESHOLD_ON +#define W2_FUNC_INIT_VAL THRESHOLD_OFF +#if GYRO_VER3_ES4 +#define W1_LV_INIT_VAL W1_THRES_LEVEL_5DPS +#define W1_MASK_INIT_VAL MASK_CLIP +#else +#define W1_LV_INIT_VAL W1_THRES_LEVEL_15DPS +#define W1_MASK_INIT_VAL MASK_NON_CLIP +#endif + +/* declarations */ +struct ewtsa_t { + struct i2c_client *client; + struct input_dev *input_dev; + struct workqueue_struct *workqueue; + struct delayed_work input_work; + struct mutex mlock; + spinlock_t slock; + unsigned long delay; + signed short fifo_lastdata[4]; + unsigned short w1_thres_x; + unsigned short w1_thres_y; + unsigned short w1_thres_z; + unsigned char event; + unsigned char range; + unsigned char sleep; + unsigned char dlpf; + unsigned char calib; + unsigned char calib_fs; + unsigned char calib_rst; + unsigned char calib_boost_tm; + unsigned char calib_boost_fs; + unsigned char fifo_mode; + unsigned char fifo_num; + unsigned char fifo_data_flag; + unsigned char reset_param; + unsigned char int_skip; + unsigned char calib_alway; + unsigned char hpf; + unsigned char w1_datamask; + unsigned char w1_thres_en; + unsigned char w2_thres_en; + unsigned char offset_lag; + unsigned char w1_thres_level; + unsigned char reserved; +}; + +static int __init init_ewtsa(void); +static void __exit exit_ewtsa(void); +static ssize_t ewtsa_sleep_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t ewtsa_sleep_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t ewtsa_delay_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t ewtsa_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t ewtsa_range_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t ewtsa_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t ewtsa_calib_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t ewtsa_calib_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t ewtsa_config_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t ewtsa_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static int EWTSA_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int EWTSA_remove(struct i2c_client *client); +static int EWTSA_suspend(struct i2c_client *client, pm_message_t mesg); +static int EWTSA_resume(struct i2c_client *client); +static void EWTSA_report_abs(struct ewtsa_t *ewt); +static void EWTSA_dev_poll(struct work_struct *work); +static void EWTSA_input_work_func(struct work_struct *work); +#if USE_GPIO_DRDY_PIN +static irqreturn_t EWTSA_interrupt(int irq, void *dev_id); +#endif +static void EWTSA_system_restart(struct ewtsa_t *ewtsa); +static void EWTSA_set_calibration(struct ewtsa_t *ewtsa); + +static struct device_attribute ewtsa_sleep_attr = { + .attr = { + .name = "ewtsa_sleep", + .mode = S_IRUGO | S_IWUSR, + }, + .show = ewtsa_sleep_show, + .store = ewtsa_sleep_store, +}; + +static struct device_attribute ewtsa_delay_attr = { + .attr = { + .name = "ewtsa_delay", + .mode = S_IRUGO | S_IWUSR, + }, + .show = ewtsa_delay_show, + .store = ewtsa_delay_store, +}; + +static struct device_attribute ewtsa_range_attr = { + .attr = { + .name = "ewtsa_range", + .mode = S_IRUGO | S_IWUSR, + }, + .show = ewtsa_range_show, + .store = ewtsa_range_store, +}; + +static struct device_attribute ewtsa_calib_attr = { + .attr = { + .name = "ewtsa_calib", + .mode = S_IRUGO | S_IWUSR, + }, + .show = ewtsa_calib_show, + .store = ewtsa_calib_store, +}; + +static struct device_attribute ewtsa_config_attr = { + .attr = { + .name = "ewtsa_configuration", + .mode = S_IRUGO | S_IWUSR, + }, + .show = ewtsa_config_show, + .store = ewtsa_config_store, +}; + +static const struct i2c_device_id ewtsa_id[] = { + {"ewtsa", 0}, + {{0}, 0} +}; + +MODULE_DEVICE_TABLE(i2c, ewtsa_id); + +static struct i2c_driver i2c_ewtsa_driver = { + .driver = { + .name = "ewtsa", + }, + .probe = EWTSA_probe, + .remove = EWTSA_remove, + .suspend = EWTSA_suspend, + .resume = EWTSA_resume, + .id_table = ewtsa_id, +}; + +/* show the sleep mode */ +static ssize_t ewtsa_sleep_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client; + struct ewtsa_t *ewtsa; +#if !GYRO_VER3_ES1 + int ret; + unsigned char val; +#endif /* GYRO_VER3_ES1 */ + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + client = to_i2c_client(dev); + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(client); + + /* output buffer check */ + if (buf == NULL) { + dev_err(&client->dev, "buf pointer null!\n"); + return -EIO; + } + +#if GYRO_VER3_ES1 + return sprintf(buf, "%d\n", ewtsa->sleep); +#else /* GYRO_VER3_ES1 */ + ret = i2c_smbus_read_byte_data(ewtsa->client, REG_SLEEP_CTRL); + if (ret < 0) { + dev_err(&ewtsa->client->dev, "REG_SLEEP_CTRL read err(ret = %d)\n", ret); + return ret; + } + val = (unsigned char)ret; + + /* REG_SLEEP_CTRL register value check */ + if ((val & SLEEP_CTRL_ACTIVATE) == SLEEP_CTRL_ACTIVATE) { + val = SLEEP_OFF; + } + else if ((val & SLEEP_CTRL_SLEEP) == SLEEP_CTRL_SLEEP) { + val = SLEEP_ON; + } + else { + val = SLEEP_ALLRESET; + } + + return sprintf(buf, "%d\n", val); +#endif /* GYRO_VER3_ES1 */ +} + +/* Set the sleep mode */ +static ssize_t ewtsa_sleep_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + u8 reg; + struct i2c_client *client; + struct ewtsa_t *ewtsa; + unsigned char val; + unsigned char before_sleep; + s32 ret; +#if GYRO_VER3_ES1 || USE_GPIO_DRDY_PIN + int err; +#endif /* GYRO_VER3_ES1 */ + long chk_param; + unsigned long l_flags = 0; +#if GYRO_VER3_ES1 + unsigned char map2_flag = EWTSA_OFF; +#endif /* GYRO_VER3_ES1 */ + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + client = to_i2c_client(dev); + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(client); + + /* input buffer check */ + if (buf == NULL) { + dev_err(&client->dev, "buf pointer null!\n"); + return -EIO; + } + + chk_param = simple_strtol(buf, NULL, 10); + if ((chk_param < SLEEP_OFF) || (chk_param >SLEEP_ALLRESET)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", chk_param); + return -EINVAL; + } + val = (unsigned char)chk_param; + + dev_info(&ewtsa->client->dev, "set SLEEP = %d\n", val); + +#if GYRO_VER3_ES1 + /* if current status is same */ + if (ewtsa->sleep == val) { + return count; + } +#else /* GYRO_VER3_ES1 */ + ret = i2c_smbus_read_byte_data(ewtsa->client, REG_SLEEP_CTRL); + if (ret < 0) { + dev_err(&ewtsa->client->dev, "REG_SLEEP_CTRL read err(ret = %d)\n", ret); + return ret; + } + reg = (u8)ret; + + /* REG_SLEEP_CTRL register value check */ + if ((reg & SLEEP_CTRL_ACTIVATE) == SLEEP_CTRL_ACTIVATE) { + reg = SLEEP_OFF; + } + else if ((reg & SLEEP_CTRL_SLEEP) == SLEEP_CTRL_SLEEP) { + reg = SLEEP_ON; + } + else { + reg = SLEEP_ALLRESET; + } + + /* if current status is same */ + if (reg == val) { + return count; + } +#endif /* GYRO_VER3_ES1 */ + + before_sleep = ewtsa->sleep; + switch(val) + { + case SLEEP_OFF: +#if GYRO_VER3_ES1 + if (ewtsa->sleep == SLEEP_ON) { + reg = CTRL_REG1_ACTIVATE; + map2_flag = EWTSA_ON; + } + else { + reg = SLEEP_CTRL_ACTIVATE; + } +#else /* GYRO_VER3_ES1 */ + reg = SLEEP_CTRL_ACTIVATE; +#endif /* GYRO_VER3_ES1 */ + break; + case SLEEP_ON: + if (ewtsa->sleep == SLEEP_ALLRESET) { + return count; + } + reg = SLEEP_CTRL_SLEEP; + ewtsa->calib_rst = EWTSA_ON; + break; + default: /* SLEEP_ALLRESET */ + reg = SLEEP_CTRL_ALLRSTSLEEP; + ewtsa->calib_rst = EWTSA_ON; + ewtsa->reset_param = RST_REG_INIT_ALL; + break; + } + + if (ewtsa->event != EWTSA_POLLING_MODE) { + /* disable interrupt */ + ret = i2c_smbus_write_byte_data(ewtsa->client, REG_INT_CTRL, INT_CTRL_INT_DISABLE); + if (ret < 0) + { + dev_err(&ewtsa->client->dev, "REG_INT_CTRL write err(data = 0x%02x, ret = %d)\n", INT_CTRL_INT_DISABLE, ret); + return ret; + } + } + + dev_info(&ewtsa->client->dev, "set reg = 0x%02x\n", reg); +#if GYRO_VER3_ES1 + if (map2_flag == EWTSA_ON) { + ret = i2c_smbus_write_byte_data(ewtsa->client, REG2_CTRL_REG1, reg); + } + else { + ret = i2c_smbus_write_byte_data(ewtsa->client, REG_SLEEP_CTRL, reg); + } +#else /* GYRO_VER3_ES1 */ + ret = i2c_smbus_write_byte_data(ewtsa->client, REG_SLEEP_CTRL, reg); +#endif /* GYRO_VER3_ES1 */ + if (ret < 0) { + dev_err(&ewtsa->client->dev, "REG_SLEEP_CTRL write err(data = 0x%02x, ret = %d)\n", reg, ret); + return ret; + } + ewtsa->sleep = val; + + if (val != SLEEP_OFF) { + if (ewtsa->event == EWTSA_POLLING_MODE) { + cancel_delayed_work(&ewtsa->input_work); + } + } + else { + ret = i2c_smbus_write_byte_data(ewtsa->client, REG_DIAG_CTRL, DIAG_ENABLE); + if (ret < 0) { + dev_err(&ewtsa->client->dev, "REG_DIAG_CTRL write err(data = 0x%02x, ret = %d)\n", DIAG_ENABLE, ret); + return ret; + } + if (ewtsa->event == EWTSA_POLLING_MODE) { + ret = i2c_smbus_write_byte_data(ewtsa->client, REG_INT_CTRL, INT_CTRL_WTMON_DISABLE); /* No INT */ + if (ret < 0) { + dev_err(&ewtsa->client->dev, "REG_INT_CTRL write err(data = 0x%02x, ret = %d)\n", INT_CTRL_WTMON_DISABLE, ret); + return ret; + } + } + + if (ewtsa->calib_rst == EWTSA_ON) { + EWTSA_system_restart(ewtsa); + } + if (ewtsa->event == EWTSA_POLLING_MODE) { + /* polling timer start */ + queue_delayed_work(ewtsa->workqueue, + &ewtsa->input_work, + msecs_to_jiffies(ewtsa->delay)); + } + } + + if (ewtsa->event == EWTSA_POLLING_MODE) { + mutex_lock(&ewtsa->mlock); + input_report_abs(ewtsa->input_dev, ABS_RY, -1); + input_sync(ewtsa->input_dev); + mutex_unlock(&ewtsa->mlock); + } + else { + spin_lock_irqsave(&ewtsa->slock, l_flags); + input_report_abs(ewtsa->input_dev, ABS_RY, -1); + input_sync(ewtsa->input_dev); + spin_unlock_irqrestore(&ewtsa->slock, l_flags); + + if (val == SLEEP_OFF) { + /* enable interrupt */ +#if USE_GPIO_DRDY_PIN + err = gpio_request(DRDY_PIN, "DRDY"); + err += gpio_direction_input(DRDY_PIN); + err += request_threaded_irq(gpio_to_irq(DRDY_PIN), NULL, EWTSA_interrupt, IRQF_TRIGGER_RISING, DEVICE_NAME, ewtsa); + if (err != 0) { + dev_err(&ewtsa->client->dev, "request_irq err(%d)\n", err); + return err; + } +#endif + + ewtsa->fifo_data_flag = EWTSA_OFF; + memset(ewtsa->fifo_lastdata, 0x00, sizeof(ewtsa->fifo_lastdata)); + ewtsa->int_skip = EWSTA_INT_SKIP; + if (ewtsa->fifo_mode == BYPASS_MODE) { + reg = (u8)INT_CTRL_INT_ENABLE; + } + else { + reg = (u8)(INT_CTRL_INT_ENABLE | INT_CTRL_INT_WTMON_EN); + } + ret = i2c_smbus_write_byte_data(ewtsa->client, REG_INT_CTRL, reg); + if (ret < 0) { + dev_err(&ewtsa->client->dev, "REG_INT_CTRL write err(data = 0x%02x, ret = %d)\n", reg, ret); + return ret; + } + } + else + { + if (before_sleep == SLEEP_OFF) { +#if USE_GPIO_DRDY_PIN + free_irq(gpio_to_irq(DRDY_PIN), ewtsa); + gpio_free(DRDY_PIN); +#endif + } + } + } + + return count; +} + +/* Show the LPF settings */ +static ssize_t ewtsa_delay_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client; + struct ewtsa_t *ewtsa; + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + client = to_i2c_client(dev); + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(client); + + /* output buffer check */ + if (buf == NULL) { + dev_err(&client->dev, "buf pointer null!\n"); + return -EIO; + } + + return sprintf(buf, "%ld\n", ewtsa->delay); +} + +/* Set the LPF settings*/ +static ssize_t ewtsa_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client; + struct ewtsa_t *ewtsa; + unsigned long delay; + unsigned char val; + unsigned char number; + u8 smpl; + int err; + unsigned char reg; + unsigned char fifo_type; + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + client = to_i2c_client(dev); + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(client); + + /* input buffer check */ + if (buf == NULL) { + dev_err(&client->dev, "buf pointer null!\n"); + return -EIO; + } + err = strict_strtoul(buf, 0, &delay); + if (err != 0) { + dev_err(&ewtsa->client->dev, "strict_strtoul err(ret = %d)\n", err); + return err; + } + + if (delay == ewtsa->delay) { + return count; + } + + if ((delay < DELAY_THRES_MIN) || (delay > DELAY_THRES_MAX)) { + dev_err(&ewtsa->client->dev, "param err(ret = %ld)\n", delay); + return -EINVAL; + } + + dev_info(&ewtsa->client->dev, "Delay = %ld\n", delay); + + if (ewtsa->sleep == SLEEP_OFF) { + if (ewtsa->event == EWTSA_POLLING_MODE) { + cancel_delayed_work(&ewtsa->input_work); + } + else { + /* disable interrupt */ + err = i2c_smbus_write_byte_data(ewtsa->client, REG_INT_CTRL, INT_CTRL_INT_DISABLE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_INT_CTRL write err(data = 0x%02x, ret = %d)\n", INT_CTRL_INT_DISABLE, err); + return err; + } + } + + if (ewtsa->event == EWTSA_POLLING_MODE) { + fifo_type = BYPASS_MODE; + } + else { + fifo_type = ewtsa->fifo_mode; + } + + if (fifo_type == BYPASS_MODE) { + if (delay < DELAY_THRES_4) { + if (delay >= DELAY_THRES_3) { + val = DELAY_DLPF_3; + } else { + val = DELAY_DLPF_2; + } + } else { + if (delay >= DELAY_THRES_6) { + val = DELAY_DLPF_6; + } else if (delay >= DELAY_THRES_5) { + val = DELAY_DLPF_5; + } else { + val = DELAY_DLPF_4; + } + } + } + else { + if (delay <= DELAY_THRES_FIFO) { + val = DELAY_DLPF_1; + } + else { + val = DELAY_DLPF_2; + } + } + + reg = (unsigned char)((unsigned char)(ewtsa->range << 3) | val ); + dev_info(&ewtsa->client->dev, "FS_DLPF = %2X\n", (unsigned int)reg); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FS_DLPF_CTRL, reg); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FS_DLPF_CTRL write err(data = 0x%02x, ret = %d)\n", reg, err); + return err; + } + ewtsa->dlpf = val; + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG5, CTRL_REG5_INIT); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG5 write err(data = 0x%02x, ret = %d)\n", CTRL_REG5_INIT, err); + return err; + } + + if (fifo_type != BYPASS_MODE) { + reg = FIFO_DRDY_DITH_EN; + } + else { + dev_info(&ewtsa->client->dev, "FIFO_CTR = %2X\n", fifo_type); + reg = (unsigned char)(fifo_type << 5); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FIFO_CTRL2, reg); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FIFO_CTRL2 write err(data = 0x%02x, ret = %d)\n", reg, err); + return err; + } + reg = FIFO_DRDY_INIT; + } + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FIFO_DRDY, reg); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FIFO_DRDY write err(data = 0x%02x, ret = %d)\n", reg, err); + return err; + } + + if (ewtsa->event == EWTSA_POLLING_MODE) { + smpl = DATA_RATE_1 - 1; /* SMPL = 0 */ + dev_info(&ewtsa->client->dev, "SMPL+1 = %2X\n", smpl); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_DATA_RATE, smpl); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_DATA_RATE write err(data = 0x%02x, ret = %d)\n", smpl, err); + return err; + } + ewtsa->delay = delay; + ewtsa->reset_param &= (unsigned char)~RST_REG_INIT_DELAY; + EWTSA_system_restart(ewtsa); + + queue_delayed_work(ewtsa->workqueue, + &ewtsa->input_work, + msecs_to_jiffies(ewtsa->delay)); + } + else { + if (fifo_type == BYPASS_MODE) { + if (delay <= DELAY_THRES_2) { + smpl = DELAY_INTMIN_THRES; + } + else { + smpl = (unsigned char)(delay - 1); + } + ewtsa->fifo_num = 1; + } + else { + if (delay <= DELAY_THRES_FIFO) { + if (delay > FIFO_MIN_DELAY) { + number = (unsigned char)(delay / DATA_RATE_5); + if ((delay % DATA_RATE_5) != 0) { + number++; + } + } + else { + number = 2; + } + smpl = DATA_RATE_5 - 1; /* SMPL = 4 */ + } + else { + number = (unsigned char)(delay / DATA_RATE_10); + if ((delay % DATA_RATE_10) != 0) { + number++; + } + smpl = DATA_RATE_10 - 1; /* SMPL = 9 */ + } + + reg = (unsigned char)(fifo_type << 5); + reg |= number; + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FIFO_CTRL2, reg); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FIFO_CTRL2 write err(data = 0x%02x, ret = %d)\n", reg, err); + return err; + } + ewtsa->fifo_num = number; + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG3, CTRL_REG3_WTM_EN); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG3 write err(data = 0x%02x, ret = %d)\n", CTRL_REG3_WTM_EN, err); + return err; + } + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG5, CTRL_REG5_FIFO_EN); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG5 write err(data = 0x%02x, ret = %d)\n", CTRL_REG5_FIFO_EN, err); + return err; + } + } + dev_info(&ewtsa->client->dev, "SMPL+1 = %2X\n", smpl); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_DATA_RATE, smpl); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_DATA_RATE write err(data = 0x%02x, ret = %d)\n", smpl, err); + return err; + } + ewtsa->delay = delay; + ewtsa->reset_param &= (unsigned char)~RST_REG_INIT_DELAY; + EWTSA_system_restart(ewtsa); + + /* enable interrupt */ + ewtsa->fifo_data_flag = EWTSA_OFF; + memset(ewtsa->fifo_lastdata, 0x00, sizeof(ewtsa->fifo_lastdata)); + ewtsa->int_skip = EWSTA_INT_SKIP; + if (fifo_type == BYPASS_MODE) { + reg = (u8)INT_CTRL_INT_ENABLE; + } + else { + reg = (u8)(INT_CTRL_INT_ENABLE | INT_CTRL_INT_WTMON_EN); + } + err = i2c_smbus_write_byte_data(ewtsa->client, REG_INT_CTRL, reg); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_INT_CTRL write err(data = 0x%02x, ret = %d)\n", reg, err); + return err; + } + } + } + else { + ewtsa->delay = delay; + ewtsa->calib_rst = EWTSA_ON; + ewtsa->reset_param |= RST_REG_INIT_DELAY; + } + + return count; +} + +/* Show the FS settings */ +static ssize_t ewtsa_range_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client; + struct ewtsa_t *ewtsa ; + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + client = to_i2c_client(dev); + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(client); + + /* output buffer check */ + if (buf == NULL) { + dev_err(&client->dev, "buf pointer null!\n"); + return -EIO; + } + + return sprintf(buf, "%d\n", ewtsa->range); +} + +/* Set the FS settings*/ +static ssize_t ewtsa_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client; + struct ewtsa_t *ewtsa; + unsigned char val; + s32 err; + unsigned char rng; + u8 reg; + long chk_param; + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + client = to_i2c_client(dev); + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(client); + + /* input buffer check */ + if (buf == NULL) { + dev_err(&client->dev, "buf pointer null!\n"); + return -EIO; + } + chk_param = simple_strtol(buf, NULL, 10); + if ((chk_param < DYNRANGE_250) || (chk_param > DYNRANGE_2000)) { + dev_info(&ewtsa->client->dev, "invalid value = %ld\n", chk_param); + return -EINVAL; + } + val = (unsigned char)chk_param; + + if (val == ewtsa->range) { + return count; + } + + dev_info(&ewtsa->client->dev, "FS = %d\n", (int)val); + if (ewtsa->sleep == SLEEP_OFF) { + if (ewtsa->event != EWTSA_POLLING_MODE) { + /* disable interrupt */ + err = i2c_smbus_write_byte_data(ewtsa->client, REG_INT_CTRL, INT_CTRL_INT_DISABLE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_INT_CTRL write err(data = 0x%02x, ret = %d)\n", INT_CTRL_INT_DISABLE, err); + return err; + } + } + rng = (unsigned char)((unsigned char)(val << 3) | ewtsa->dlpf); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FS_DLPF_CTRL, rng); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FS_DLPF_CTRL write err(data = 0x%02x, ret = %d)\n", rng, err); + return err; + } + ewtsa->range = val; + ewtsa->reset_param &= (unsigned char)~RST_REG_INIT_RANGE; + if (ewtsa->event == EWTSA_POLLING_MODE) { + cancel_delayed_work(&ewtsa->input_work); + EWTSA_system_restart(ewtsa); + queue_delayed_work(ewtsa->workqueue, + &ewtsa->input_work, + msecs_to_jiffies(ewtsa->delay)); + } + else { + EWTSA_system_restart(ewtsa); + + /* enable interrupt */ + ewtsa->fifo_data_flag = EWTSA_OFF; + memset(ewtsa->fifo_lastdata, 0x00, sizeof(ewtsa->fifo_lastdata)); + ewtsa->int_skip = EWSTA_INT_SKIP; + if (ewtsa->fifo_mode == BYPASS_MODE) { + reg = (u8)INT_CTRL_INT_ENABLE; + } + else { + reg = (u8)(INT_CTRL_INT_ENABLE | INT_CTRL_INT_WTMON_EN); + } + err = i2c_smbus_write_byte_data(ewtsa->client, REG_INT_CTRL, reg); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_INT_CTRL write err(data = 0x%02x, ret = %d)\n", reg, err); + return err; + } + } + } + else { + ewtsa->range = val; + ewtsa->calib_rst = EWTSA_ON; + ewtsa->reset_param |= RST_REG_INIT_RANGE; + } + + return count; +} + +/* Show the SELF O C settings */ +static ssize_t ewtsa_calib_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client; + struct ewtsa_t *ewtsa; + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + client = to_i2c_client(dev); + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(client); + + /* output buffer check */ + if (buf == NULL) { + dev_err(&client->dev, "buf pointer null!\n"); + return -EIO; + } + + return sprintf(buf, "%d\n", ewtsa->calib); +} + +/* Set the SELF O C settings*/ +static ssize_t ewtsa_calib_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client; + struct ewtsa_t *ewtsa; + unsigned char val; + s32 err; + u8 reg; + long chk_param; + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + client = to_i2c_client(dev); + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(client); + + /* input buffer check */ + if (buf == NULL) { + dev_err(&client->dev, "buf pointer null!\n"); + return -EIO; + } + chk_param = simple_strtol(buf, NULL, 10); + if ((chk_param != EWTSA_ON) && (chk_param != EWTSA_OFF)) { + dev_info(&ewtsa->client->dev, "invalid value = %ld\n", chk_param); + return -EINVAL; + } + val = (unsigned char)chk_param; + + dev_info(&ewtsa->client->dev, "SELF_O_C = %d(now = %d)\n", (int)val, ewtsa->calib); + + if (ewtsa->calib == val) { + return count; + } + + ewtsa->calib = val; + if (ewtsa->sleep == SLEEP_OFF) { + if (ewtsa->event == EWTSA_POLLING_MODE) { + cancel_delayed_work(&ewtsa->input_work); + EWTSA_system_restart(ewtsa); + queue_delayed_work(ewtsa->workqueue, + &ewtsa->input_work, + msecs_to_jiffies(ewtsa->delay)); + } + else { + /* disable interrupt */ + err = i2c_smbus_write_byte_data(ewtsa->client, REG_INT_CTRL, INT_CTRL_INT_DISABLE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_INT_CTRL write err(data = 0x%02x, ret = %d)\n", INT_CTRL_INT_DISABLE, err); + return err; + } + + EWTSA_system_restart(ewtsa); + + /* enable interrupt */ + ewtsa->fifo_data_flag = EWTSA_OFF; + memset(ewtsa->fifo_lastdata, 0x00, sizeof(ewtsa->fifo_lastdata)); + ewtsa->int_skip = EWSTA_INT_SKIP; + if (ewtsa->fifo_mode == BYPASS_MODE) { + reg = (u8)INT_CTRL_INT_ENABLE; + } + else { + reg = (u8)(INT_CTRL_INT_ENABLE | INT_CTRL_INT_WTMON_EN); + } + err = i2c_smbus_write_byte_data(ewtsa->client, REG_INT_CTRL, reg); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_INT_CTRL write err(data = 0x%02x, ret = %d)\n", reg, err); + return err; + } + } + } + else { + ewtsa->calib_rst = EWTSA_ON; + } + + return count; +} + +/* Show the gyro configurations */ +static ssize_t ewtsa_config_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *l_client; + struct ewtsa_t *ewtsa; + int ret; + ssize_t ret_len = 0; + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + l_client = to_i2c_client(dev); + + if (l_client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(l_client); + + /* output buffer check */ + if (buf == NULL) { + dev_err(&ewtsa->client->dev, "buf pointer null!\n"); + return -EIO; + } + +#if GYRO_REGISTER_MAP2 + ret = sprintf(buf+ret_len, "MAP2;"); +#else /* GYRO_REGISTER_MAP2 */ + ret = sprintf(buf+ret_len, "MAP1;"); +#endif /* GYRO_REGISTER_MAP2 */ + if (ret >= 0) { + ret_len += ret; + } + +#if GYRO_SPI_INTERFACE + ret = sprintf(buf+ret_len, "SPI;"); +#else /* GYRO_SPI_INTERFACE */ + ret = sprintf(buf+ret_len, "I2C;"); +#endif /* GYRO_SPI_INTERFACE */ + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "SLP=%d;", ewtsa->sleep); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "DLY=%ld;", ewtsa->delay); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "RNG=%d;", ewtsa->range); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "SOC=%d;", ewtsa->calib); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "SBT=%d;", ewtsa->calib_boost_tm); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "HPF=%d;", ewtsa->hpf); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "SFR=%d;", ewtsa->calib_fs); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "EVE=%d;", ewtsa->event); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "FIFO=%d;", ewtsa->fifo_mode); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "SAA=%d;", ewtsa->calib_alway); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "W1CX=%d;", ewtsa->w1_thres_x); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "W1CY=%d;", ewtsa->w1_thres_y); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "W1CZ=%d;", ewtsa->w1_thres_z); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "BFR=%d;", ewtsa->calib_boost_fs); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "OTL=%d;", ewtsa->offset_lag); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "W1L=%d;", ewtsa->w1_thres_level); + if (ret >= 0) { + ret_len += ret; + } + + ret = sprintf(buf+ret_len, "W1DM=%d;", ewtsa->w1_datamask); + if (ret >= 0) { + ret_len += ret; + } + + return ret_len; +} + +/* Set the gyro configurations */ +static ssize_t ewtsa_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *l_client; + struct ewtsa_t *ewtsa; + char val_char[4] = {0}; + char sleep_val[4] = {0}; + unsigned char cmd[5] = {0}; + unsigned char cmd_size = 0; + unsigned char val_size = 0; + unsigned char sleep_flag = EWTSA_OFF; + unsigned char sleep_mode = SLEEP_ALLRESET; + unsigned char fifo_tmp; + unsigned char event_tmp; + int loop; + int size_err; + unsigned long val = 0; + size_t chk_cnt = 0; + ssize_t sleep_ret; + + if (dev == NULL) { + printk(KERN_INFO "struct device null pointer\n"); + return -EIO; + } + l_client = to_i2c_client(dev); + + if (l_client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(l_client); + + /* input buffer check */ + if (buf == NULL) { + dev_err(&ewtsa->client->dev, "buf pointer null!\n"); + return -EIO; + } + + fifo_tmp = ewtsa->fifo_mode; + event_tmp = ewtsa->event; + + if (strncmp(buf, "MAP", 3) == 0) { + /* get register map information */ +#if GYRO_REGISTER_MAP2 + if (strncmp(buf, "MAP2", MAP_NAME_SIZE) != 0) { + dev_err(&ewtsa->client->dev, "register map unmatch!\n"); + return -EINVAL; + } +#else /* GYRO_REGISTER_MAP2 */ + if (strncmp(buf, "MAP1", MAP_NAME_SIZE) != 0) { + dev_err(&ewtsa->client->dev, "register map unmatch!\n"); + return -EINVAL; + } +#endif /* GYRO_REGISTER_MAP2 */ + buf += MAP_NAME_SIZE + 1; + chk_cnt += MAP_NAME_SIZE + 1; + + /* get communication interface */ +#if GYRO_SPI_INTERFACE + if (strncmp(buf, "SPI", INTERFACE_NAME_SIZE) != 0) { + dev_err(&ewtsa->client->dev, "communication interface unmatch!\n"); + return -EINVAL; + } +#else /* GYRO_SPI_INTERFACE */ + if (strncmp(buf, "I2C", INTERFACE_NAME_SIZE) != 0) { + dev_err(&ewtsa->client->dev, "communication interface unmatch!\n"); + return -EINVAL; + } +#endif /* GYRO_SPI_INTERFACE */ + buf += INTERFACE_NAME_SIZE + 1; + chk_cnt += INTERFACE_NAME_SIZE + 1; + } + + while (chk_cnt < count) { + memset(cmd, 0x00, sizeof(cmd)); + memset(val_char, 0x00, sizeof(val_char)); + size_err = 0; + + for (loop = 0; (chk_cnt + loop) < count; loop++) { + if (*(buf + loop) == '=') { + break; + } + + if (*(buf + loop) == ';') { + dev_err(&ewtsa->client->dev, "command format err\n"); + return -EINVAL; + } + } + + if ((chk_cnt + loop) >= count) { + break; + } + + cmd_size = (unsigned char)loop; + if (cmd_size == 0) { + dev_err(&ewtsa->client->dev, "command nothing\n"); + return -EINVAL; + } + + /* command size over? */ + if (loop > (sizeof(cmd) - 1)) { + size_err = EWTSA_ON; + } + else { + memcpy(cmd, buf, cmd_size); + } + buf += cmd_size + 1; + chk_cnt += cmd_size + 1; + + for (loop = 0; (chk_cnt + loop) < count; loop++) { + if (*(buf + loop) == ';') { + break; + } + } + + if ((chk_cnt + loop) >= count) { + break; + } + + val_size = (unsigned char)loop; + if (val_size == 0) { + dev_err(&ewtsa->client->dev, "value nothing(cmd = %s)\n", cmd); + return -EINVAL; + } + + if (size_err != 0) { + /* if command size is over, value ignore and next command check. */ + buf += val_size + 1; + chk_cnt += val_size + 1; + continue; + } + else if (loop > (sizeof(val_char) - 1)) { + /* if value size is over, return format err. */ + size_err = EWTSA_ON; + } + else { + memcpy(val_char, buf, val_size); + size_err = strict_strtoul(val_char, 10, &val); + } + + if (size_err != 0) { + dev_err(&ewtsa->client->dev, "value format err(cmd = %s)\n", cmd); + return -EINVAL; + } + buf += val_size + 1; + chk_cnt += val_size + 1; + + if (cmd_size == CMD_SIZE_3) { + if (strncmp((char*)cmd, "SLP", CMD_SIZE_3) == 0) { + sleep_flag = EWTSA_ON; + memcpy(sleep_val, val_char, sizeof(sleep_val)); + if (val == 0) { + sleep_mode = SLEEP_OFF; + } + } + else if (strncmp((char*)cmd, "DLY", CMD_SIZE_3) == 0) { + if ((val < DELAY_THRES_MIN) || (val > DELAY_THRES_MAX)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + + ewtsa->delay = val; + ewtsa->calib_rst = EWTSA_ON; + ewtsa->reset_param |= RST_REG_INIT_DELAY; + } + else if (strncmp((char*)cmd, "RNG", CMD_SIZE_3) == 0) { + if (val > DYNRANGE_2000) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->range = (unsigned char)val; + ewtsa->calib_rst = EWTSA_ON; + ewtsa->reset_param |= RST_REG_INIT_RANGE; + } + else if (strncmp((char*)cmd, "SOC", CMD_SIZE_3) == 0) { + if ((val != EWTSA_ON) && (val != EWTSA_OFF)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->calib = (unsigned char)val; + ewtsa->calib_rst = EWTSA_ON; + } + else if (strncmp((char*)cmd, "SBT", CMD_SIZE_3) == 0) { + if (val > BOOST_TIME_100MS) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->calib_boost_tm = (unsigned char)val; + } + else if (strncmp((char*)cmd, "HPF", CMD_SIZE_3) == 0) { + if ((val != HPF_001HZ) && (val != HPF_002HZ)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->hpf = (unsigned char)val; + ewtsa->calib_rst = EWTSA_ON; + } + else if (strncmp((char*)cmd, "SFR", CMD_SIZE_3) == 0) { + if ((val != CALIB_FS_62_5HZ) && (val != CALIB_FS_31_25HZ)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->calib_fs = (unsigned char)val; + ewtsa->calib_rst = EWTSA_ON; + } + else if (strncmp((char*)cmd, "EVE", CMD_SIZE_3) == 0) { + if ((val != EWTSA_POLLING_MODE) && (val != EWTSA_INTERUPT_MODE)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } +#if USE_GPIO_DRDY_PIN + event_tmp = (unsigned char)val; +#else + event_tmp = (unsigned char)EWTSA_POLLING_MODE; +#endif + ewtsa->calib_rst = EWTSA_ON; + ewtsa->reset_param = RST_REG_INIT_ALL; + } + else if (strncmp((char*)cmd, "SAA", CMD_SIZE_3) == 0) { + if ((val != EWTSA_ON) && (val != EWTSA_OFF)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->calib_alway = (unsigned char)val; + ewtsa->calib_rst = EWTSA_ON; + } + else if (strncmp((char*)cmd, "BFR", CMD_SIZE_3) == 0) { + if ((val != BOOST_FS_48KHZ) && (val != BOOST_FS_16KHZ)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->calib_boost_fs = (unsigned char)val; + } + else if (strncmp((char*)cmd, "OTL", CMD_SIZE_3) == 0) { + if (val > LAG_20SMP) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->offset_lag = (unsigned char)val; + ewtsa->calib_rst = EWTSA_ON; + } + else if (strncmp((char*)cmd, "W1L", CMD_SIZE_3) == 0) { + if (val > W1_THRES_LEVEL_15DPS) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->w1_thres_level = (unsigned char)val; + ewtsa->calib_rst = EWTSA_ON; + } + else { + dev_info(&ewtsa->client->dev, "unknown command(%s)\n", cmd); + } + } + else if (cmd_size == CMD_SIZE_4) { + if (strncmp((char*)cmd, "FIFO", CMD_SIZE_4) == 0) { + if ((val != BYPASS_MODE) && (val != FIFO_MODE)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + fifo_tmp = (unsigned char)val; + ewtsa->calib_rst = EWTSA_ON; + ewtsa->reset_param = RST_REG_INIT_ALL; + } + else if (strncmp((char*)cmd, "W1CX", CMD_SIZE_4) == 0) { + if (val > THRES_CENTER_MAX) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->w1_thres_x = (unsigned short)val; + ewtsa->calib_rst = EWTSA_ON; + } + else if (strncmp((char*)cmd, "W1CY", CMD_SIZE_4) == 0) { + if (val > THRES_CENTER_MAX) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->w1_thres_y = (unsigned short)val; + ewtsa->calib_rst = EWTSA_ON; + } + else if (strncmp((char*)cmd, "W1CZ", CMD_SIZE_4) == 0) { + if (val > THRES_CENTER_MAX) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->w1_thres_z = (unsigned short)val; + ewtsa->calib_rst = EWTSA_ON; + } + else if (strncmp((char*)cmd, "W1DM", CMD_SIZE_4) == 0) { + if ((val != MASK_CLIP) && (val != MASK_NON_CLIP)) { + dev_err(&ewtsa->client->dev, "invalid value = %ld\n", val); + return -EINVAL; + } + ewtsa->w1_datamask = (unsigned char)val; + ewtsa->calib_rst = EWTSA_ON; + } + else { + dev_info(&ewtsa->client->dev, "unknown command(%s)\n", cmd); + } + } + else { + dev_info(&ewtsa->client->dev, "unknown command(%s)\n", cmd); + } + } + + if (sleep_flag == EWTSA_ON) { + if (sleep_mode == SLEEP_OFF) { + /* all reset sleep mode */ + val_char[0] = '2'; + val_char[1] = '\0'; + sleep_ret = ewtsa_sleep_store(dev, attr, val_char, 1); + if (sleep_ret != 1) { + dev_err(&ewtsa->client->dev, "ewtsa_sleep_store err(%d)\n", sleep_ret); + return sleep_ret; + } + ewtsa->event = event_tmp; + ewtsa->fifo_mode = fifo_tmp; + } + sleep_ret = ewtsa_sleep_store(dev, attr, sleep_val, sizeof(sleep_val)); + if (sleep_ret != sizeof(sleep_val)) { + dev_err(&ewtsa->client->dev, "ewtsa_sleep_store err(%d)\n", sleep_ret); + return sleep_ret; + } + ewtsa->event = event_tmp; + ewtsa->fifo_mode = fifo_tmp; + } + else { + if (ewtsa->calib_rst == EWTSA_ON) { + sleep_mode = ewtsa->sleep; + + /* all reset sleep mode */ + val_char[0] = '2'; + val_char[1] = '\0'; + sleep_ret = ewtsa_sleep_store(dev, attr, val_char, 1); + if (sleep_ret != 1) { + dev_err(&ewtsa->client->dev, "ewtsa_sleep_store err(%d)\n", sleep_ret); + return sleep_ret; + } + + ewtsa->event = event_tmp; + ewtsa->fifo_mode = fifo_tmp; + + if (sleep_mode == SLEEP_OFF) { + /* sleep off mode */ + val_char[0] = '0'; + val_char[1] = '\0'; + sleep_ret = ewtsa_sleep_store(dev, attr, val_char, 1); + if (sleep_ret != 1) { + dev_err(&ewtsa->client->dev, "ewtsa_sleep_store err(%d)\n", sleep_ret); + return sleep_ret; + } + } + } + } + + return count; +} + +/* calibration & register settings */ +static void EWTSA_system_restart(struct ewtsa_t *ewtsa) +{ + unsigned char val; + unsigned char smpl; + unsigned char number; + unsigned char fifo_type; + s32 err; +#if GYRO_VER3_ES1 + signed long ret; + signed long timeout; +#endif + + if (ewtsa == NULL) { + printk(KERN_INFO "EWTSA_system_restart:ewtsa null pointer\n"); + return; + } + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_DIGITAL_CAL, DIGITAL_CAL_DISABLE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_DIGITAL_CAL write err(data = 0x%02x, ret = %d)\n", DIGITAL_CAL_DISABLE, err); + return; + } + +#if GYRO_VER3_ES1 + err = i2c_smbus_write_byte_data(ewtsa->client, REG_REFERENCE, 0x00); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_REFERENCE write err(data = 0x00, ret = %d)\n", err); + return; + } + + val = (unsigned char)(CTRL_REG2_REF_MODE | CTRL_REG2_HPCF); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + err = i2c_smbus_read_byte_data(ewtsa->client, REG_REFERENCE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_REFERENCE read err(ret = %d)\n", err); + return; + } + + val = SOC_CNT2_SOCCLK_ON; + val |= (unsigned char)(CALIB_FS_62_5HZ << 7); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SOC_CNT2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SOC_CNT2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + /* Wait reference mode setting */ + ret = (signed long)((REFERENCE_WAIT * HZ)/1000); + ret += (signed long)(1000 / HZ); + while (ret > 0) { + timeout = ret; + set_current_state(TASK_UNINTERRUPTIBLE); + ret = schedule_timeout(timeout); + } + + val = SOC_CNT2_SOCCLK_OFF; + val |= (unsigned char)(CALIB_FS_62_5HZ << 7); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SOC_CNT2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SOC_CNT2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + val = (unsigned char)(CTRL_REG2_NOR_MODE | CTRL_REG2_HPCF); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } +#endif /* GYRO_VER3_ES1 */ + + if (ewtsa->event == EWTSA_POLLING_MODE) { + fifo_type = BYPASS_MODE; + } + else { + fifo_type = ewtsa->fifo_mode; + } + + if ((ewtsa->reset_param & RST_REG_INIT_ALL) != RST_REG_INIT_OFF) { + if (fifo_type == BYPASS_MODE) { + if (ewtsa->delay < DELAY_THRES_4) { + if (ewtsa->delay >= DELAY_THRES_3) { + ewtsa->dlpf = DELAY_DLPF_3; + } else { + ewtsa->dlpf = DELAY_DLPF_2; + } + } else { + if (ewtsa->delay >= DELAY_THRES_6) { + ewtsa->dlpf = DELAY_DLPF_6; + } else if (ewtsa->delay >= DELAY_THRES_5) { + ewtsa->dlpf = DELAY_DLPF_5; + } else { + ewtsa->dlpf = DELAY_DLPF_4; + } + } + } + else { + if (ewtsa->delay <= DELAY_THRES_FIFO) { + ewtsa->dlpf = DELAY_DLPF_1; + } + else { + ewtsa->dlpf = DELAY_DLPF_2; + } + } + val = (unsigned char)((unsigned char)(ewtsa->range << 3) | ewtsa->dlpf); + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FS_DLPF_CTRL, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FS_DLPF_CTRL write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + } + + if ((ewtsa->reset_param & RST_REG_INIT_DELAY) != RST_REG_INIT_OFF) { + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG5, CTRL_REG5_INIT); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG5 write err(data = 0x%02x, ret = %d)\n", CTRL_REG5_INIT, err); + return; + } + + if (fifo_type != BYPASS_MODE) { + val = FIFO_DRDY_DITH_EN; + } + else { + val = (unsigned char)(fifo_type << 5); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FIFO_CTRL2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FIFO_CTRL2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + val = FIFO_DRDY_INIT; + } + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FIFO_DRDY, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FIFO_DRDY write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + if (fifo_type == BYPASS_MODE) { + if (ewtsa->event == EWTSA_POLLING_MODE) { + smpl = DATA_RATE_1 - 1; /* SMPL = 0 */ + } + else { + if (ewtsa->delay <= DELAY_THRES_2) { + smpl = DELAY_INTMIN_THRES; + } + else { + smpl = (unsigned char)(ewtsa->delay - 1); + } + } + ewtsa->fifo_num = 1; + } + else { + if (ewtsa->delay <= DELAY_THRES_FIFO) { + if (ewtsa->delay > FIFO_MIN_DELAY) { + number = (unsigned char)(ewtsa->delay / DATA_RATE_5); + if ((ewtsa->delay % DATA_RATE_5) != 0) { + number++; + } + } + else { + number = 2; + } + smpl = DATA_RATE_5 - 1; /* SMPL = 4 */ + } + else { + number = (unsigned char)(ewtsa->delay / DATA_RATE_10); + if ((ewtsa->delay % DATA_RATE_10) != 0) { + number++; + } + smpl = DATA_RATE_10 - 1; /* SMPL = 9 */ + } + + val = (unsigned char)(fifo_type << 5); + val |= number; + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FIFO_CTRL2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FIFO_CTRL2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + ewtsa->fifo_num = number; + + val = CTRL_REG3_WTM_EN; + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG3, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG3 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG5, CTRL_REG5_FIFO_EN); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG5 write err(data = 0x%02x, ret = %d)\n", CTRL_REG5_FIFO_EN, err); + return; + } + } + err = i2c_smbus_write_byte_data(ewtsa->client, REG_DATA_RATE, smpl); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_DATA_RATE write err(data = 0x%02x, ret = %d)\n", smpl, err); + return; + } + } + ewtsa->reset_param = RST_REG_INIT_OFF; + + if (ewtsa->calib == EWTSA_ON) { + EWTSA_set_calibration(ewtsa); + } + else { + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SLEEP_CTRL, SLEEP_CTRL_SLEEP); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SLEEP_CTRL write err(data = 0x%02x, ret = %d)\n", SLEEP_CTRL_SLEEP, err); + return; + } + +#if GYRO_VER3_ES1 + err = i2c_smbus_write_byte_data(ewtsa->client, REG2_CTRL_REG1, CTRL_REG1_ACTIVATE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG2_CTRL_REG1 write err(data = 0x%02x, ret = %d)\n", CTRL_REG1_ACTIVATE, err); + return; + } +#else /* GYRO_VER3_ES1 */ + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SLEEP_CTRL, SLEEP_CTRL_ACTIVATE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SLEEP_CTRL write err(data = 0x%02x, ret = %d)\n", SLEEP_CTRL_ACTIVATE, err); + return; + } +#endif /* GYRO_VER3_ES1 */ + + /* FIFO clear */ + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FIFO_CTRL1, FIFO_CTRL1_CLEAR); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FIFO_CTRL1 write err(data = 0x02, ret = %d)\n", err); + return; + } + } + + ewtsa->calib_rst = EWTSA_OFF; +} + +static void EWTSA_set_calibration(struct ewtsa_t *ewtsa) +{ + unsigned char val; + s32 err; + signed long ret; + signed long l_timeout; + unsigned long center; + static const unsigned short ewtsa_boost_time[4] = { + EWTSA_BOOST_TIME_0, EWTSA_BOOST_TIME_1, EWTSA_BOOST_TIME_2, EWTSA_BOOST_TIME_3 + }; + static const unsigned char ewtsa_w1_threshold_level[4] = { + EWTSA_W1_THRES_LV_0, EWTSA_W1_THRES_LV_1, EWTSA_W1_THRES_LV_2, EWTSA_W1_THRES_LV_3 + }; + static const unsigned short ewtsa_dynamic_range[4] = { + EWTSA_RANGE_0, EWTSA_RANGE_1, EWTSA_RANGE_2, EWTSA_RANGE_3 + }; + + if (ewtsa == NULL) { + printk(KERN_INFO "EWTSA_system_restart:ewtsa null pointer\n"); + return; + } + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SOC_CNT1, SOC_CNT1_WIN_DIS | SOC_CNT1_BOOST_ON); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SOC_CNT1 write err(data = 0x%02x, ret = %d)\n", SOC_CNT1_WIN_DIS | SOC_CNT1_BOOST_ON, err); + return; + } + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SLEEP_CTRL, SLEEP_CTRL_SLEEP); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SLEEP_CTRL write err(data = 0x%02x, ret = %d)\n", SLEEP_CTRL_SLEEP, err); + return; + } + +#if GYRO_VER3_ES1 + err = i2c_smbus_write_byte_data(ewtsa->client, REG2_CTRL_REG1, CTRL_REG1_ACTIVATE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG2_CTRL_REG1 write err(data = 0x%02x, ret = %d)\n", CTRL_REG1_ACTIVATE, err); + return; + } +#else /* GYRO_VER3_ES1 */ + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SLEEP_CTRL, SLEEP_CTRL_ACTIVATE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SLEEP_CTRL write err(data = 0x%02x, ret = %d)\n", SLEEP_CTRL_ACTIVATE, err); + return; + } +#endif /* GYRO_VER3_ES1 */ + + if (ewtsa_w1_threshold_level[ewtsa->w1_thres_level] > ewtsa->w1_thres_x) { + center = ewtsa_w1_threshold_level[ewtsa->w1_thres_level] + 1; + } + else { + center = ewtsa->w1_thres_x; + } + center *= W1_THRES_CENTER_COEF; + center /= ewtsa_dynamic_range[ewtsa->range]; + val = (unsigned char)((0xFF00 & center) >> 8); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_REFERENCE, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_REFERENCE write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + val = (unsigned char)(CTRL_REG2_REF_MODE | CTRL_REG2_HPCF); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + val = SOC_CNT2_SOCCLK_ON; + val |= (unsigned char)(CALIB_FS_62_5HZ << 7); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SOC_CNT2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SOC_CNT2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + /* Wait reference mode setting */ + ret = (signed long)((REFERENCE_WAIT * HZ)/1000); + ret += (signed long)(1000 / HZ); + while (ret > 0) { + l_timeout = ret; + set_current_state(TASK_UNINTERRUPTIBLE); + ret = schedule_timeout(l_timeout); + } + + val = SOC_CNT2_SOCCLK_OFF; + val |= (unsigned char)(CALIB_FS_62_5HZ << 7); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SOC_CNT2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SOC_CNT2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + val = (unsigned char)(CTRL_REG2_NOR_MODE | CTRL_REG2_HPCF); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_CTRL_REG2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_CTRL_REG2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } +#if GYRO_VER3_ES3 || GYRO_VER3_ES4 //2012.01.25 for ES3 & ES4 + val = (unsigned char)(0x40 | SOC_CNT1_BOOST_ON); +#else + val = (unsigned char)((unsigned char)(ewtsa->w1_datamask << 6) | SOC_CNT1_BOOST_ON); +#endif + val |= (unsigned char)(ewtsa->w2_thres_en << 5); + val |= (unsigned char)(ewtsa->w1_thres_en << 4); + val |= (unsigned char)(ewtsa->calib_boost_tm << 2); + val |= (unsigned char)(ewtsa->calib_boost_fs << 1); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SOC_CNT1, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SOC_CNT1 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + val = (unsigned char)(SOC_CNT2_SOCCLK_ON | ewtsa->w1_thres_level); + val |= (unsigned char)(ewtsa->calib_fs << 7); + val |= (unsigned char)(ewtsa->offset_lag << 4); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SOC_CNT2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SOC_CNT2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + val = (unsigned char)(ewtsa->hpf << 7); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SLFSLP_CNT, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SLFSLP_CNT write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + if (ewtsa_w1_threshold_level[ewtsa->w1_thres_level] > ewtsa->w1_thres_x) { + center = ewtsa_w1_threshold_level[ewtsa->w1_thres_level] + 1; + } + else { + center = ewtsa->w1_thres_x; + } + center *= W1_THRES_CENTER_COEF; + center /= ewtsa_dynamic_range[ewtsa->range]; + val = (unsigned char)((0xFF00 & center) >> 8); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_W1THX_H, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_W1THX_H write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + val = (unsigned char)(0xFF & center); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_W1THX_L, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_W1THX_L write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + if (ewtsa_w1_threshold_level[ewtsa->w1_thres_level] > ewtsa->w1_thres_y) { + center = ewtsa_w1_threshold_level[ewtsa->w1_thres_level] + 1; + } + else { + center = ewtsa->w1_thres_y; + } + center *= W1_THRES_CENTER_COEF; + center /= ewtsa_dynamic_range[ewtsa->range]; + val = (unsigned char)((0xFF00 & center) >> 8); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_W1THY_H, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_W1THY_H write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + val = (unsigned char)(0xFF & center); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_W1THY_L, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_W1THY_L write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + if (ewtsa_w1_threshold_level[ewtsa->w1_thres_level] > ewtsa->w1_thres_z) { + center = ewtsa_w1_threshold_level[ewtsa->w1_thres_level] + 1; + } + else { + center = ewtsa->w1_thres_z; + } + center *= W1_THRES_CENTER_COEF; + center /= ewtsa_dynamic_range[ewtsa->range]; + val = (unsigned char)((0xFF00 & center) >> 8); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_W1THZ_H, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_W1THZ_H write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + val = (unsigned char)(0xFF & center); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_W1THZ_L, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_W1THZ_L write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + err = i2c_smbus_write_byte_data(ewtsa->client, REG_DIGITAL_CAL, DIGITAL_CAL_ENABLE); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_DIGITAL_CAL write err(data = 0x%02x, ret = %d)\n", DIGITAL_CAL_ENABLE, err); + return; + } + + /* Wait calibration boost */ + ret = (signed long)((ewtsa_boost_time[ewtsa->calib_boost_tm] * HZ)/1000); + ret += (signed long)(1000 / HZ); + while (ret > 0) { + l_timeout = ret; + set_current_state(TASK_UNINTERRUPTIBLE); + ret = schedule_timeout(l_timeout); + } + + /* boost stop */ + val = (unsigned char)(ewtsa->w1_datamask << 6); + val |= (unsigned char)(ewtsa->w2_thres_en << 5); + val |= (unsigned char)(ewtsa->w1_thres_en << 4); + val |= (unsigned char)(ewtsa->calib_boost_tm << 2); + val |= (unsigned char)(ewtsa->calib_boost_fs << 1); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SOC_CNT1, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SOC_CNT1 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + + if ((ewtsa->calib_alway != EWTSA_ON) || + ((ewtsa->w1_thres_en == THRESHOLD_OFF) && (ewtsa->w2_thres_en == THRESHOLD_OFF))) { + val = (unsigned char)(SOC_CNT2_SOCCLK_OFF | ewtsa->w1_thres_level); + err = i2c_smbus_write_byte_data(ewtsa->client, REG_SOC_CNT2, val); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_SOC_CNT2 write err(data = 0x%02x, ret = %d)\n", val, err); + return; + } + } + + /* FIFO clear */ + err = i2c_smbus_write_byte_data(ewtsa->client, REG_FIFO_CTRL1, FIFO_CTRL1_CLEAR); + if (err < 0) { + dev_err(&ewtsa->client->dev, "REG_FIFO_CTRL1 write err(data = 0x02, ret = %d)\n", err); + return; + } + return; +} + +/* Read the angular data from the registers */ +static void EWTSA_report_abs(struct ewtsa_t *ewt) +{ + unsigned short x = 0, y = 0, z = 0, temp = 0; + s16 send_x, send_y, send_z, send_temp; + unsigned char reg = REG_MBURST_ALL; + unsigned char reg2[32][8]; + int err; + struct i2c_msg msg[2]; +#if GYRO_MOUNT_SWAP_XY + s16 tmp; +#endif /* GYRO_MOUNT_SWAP_XY */ + unsigned char diag_stat = 0; + unsigned char loop; + unsigned long l_flags = 0; + signed long cal_tmp[4] = {0}; + unsigned char get_num = 0; + unsigned char read_num = 0; + + if (ewt == NULL) { + printk(KERN_INFO "struct ewtsa_t null pointer\n"); + return; + } + + if (ewt->event == EWTSA_POLLING_MODE) { + mutex_lock(&ewt->mlock); + } + else { + if (ewt->fifo_mode == FIFO_MODE) { + err = i2c_smbus_read_byte_data(ewt->client, REG_FIFO_DM); + if (err < 0) { + dev_err(&ewt->client->dev, "REG_FIFO_DM read err(%d)\n", err); + err = 0; + } + read_num = (unsigned char)err; + if (((unsigned char)(read_num & 0x20) >> 5) == 1) { + /* data nothing */ + err = i2c_smbus_read_byte_data(ewt->client, REG_INT_STAT); + if (err < 0) { + dev_err(&ewt->client->dev, "REG_INT_STAT read err(%d)\n", err); + } + return; + } + read_num &= 0x1F; + + if (ewt->fifo_num > read_num) { + err = i2c_smbus_read_byte_data(ewt->client, REG_INT_STAT); + if (err < 0) { + dev_err(&ewt->client->dev, "REG_INT_STAT read err(%d)\n", err); + } + return; + } + } + } + + msg[0].addr = ewt->client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = ® + + msg[1].addr = ewt->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = (unsigned short)(8 * ewt->fifo_num); + msg[1].buf = ®2[0][0]; + + err = i2c_transfer(ewt->client->adapter, msg, 2); + if (err < 0) { + dev_err(&ewt->client->dev, "REG_MBURST_ALL read err(%d)\n", err); + memset(reg2, 0x00, sizeof(reg2)); + } + + for (loop = 0; loop < ewt->fifo_num; loop++) { + x = (unsigned short)(0xFF & reg2[loop][3]); + x |= (unsigned short)(0xFF00 & (unsigned short)(reg2[loop][2] << 8)); + y = (unsigned short)(0xFF & reg2[loop][5]); + y |= (unsigned short)(0xFF00 & (unsigned short)(reg2[loop][4] << 8)); + z = (unsigned short)(0xFF & reg2[loop][7]); + z |= (unsigned short)(0xFF00 & (unsigned short)(reg2[loop][6] << 8)); + temp = (unsigned short)(0xFF & reg2[loop][1]); + temp |= (unsigned short)(0xFF00 & (unsigned short)(reg2[loop][0] << 8)); + + cal_tmp[0] += (signed short)x; + cal_tmp[1] += (signed short)y; + cal_tmp[2] += (signed short)z; + cal_tmp[3] += (signed short)temp; + get_num++; + } + + err = i2c_smbus_read_byte_data(ewt->client, REG_STATUS_REG); + if (err < 0) { + dev_err(&ewt->client->dev, "REG_STATUS_REG read err(%d)\n", err); + err = 0; + } + reg = (unsigned char)err; + if ((reg & STATUS_REG_OVERRUN) != 0) { + err = i2c_smbus_write_byte_data(ewt->client, REG_FIFO_CTRL1, FIFO_CTRL1_CLEAR); + if (err < 0) { + dev_err(&ewt->client->dev, "REG_FIFO_CTRL1 read err(%d)\n", err); + } + } + + if (ewt->int_skip == EWSTA_INT_SKIP) { + ewt->int_skip = EWSTA_INT_CLEAR; + err = i2c_smbus_read_byte_data(ewt->client, REG_INT_STAT); + if (err < 0) { + dev_err(&ewt->client->dev, "REG_INT_STAT read err(%d)\n", err); + } + return; + } + + if (get_num != 0) { + if (ewt->fifo_data_flag == EWTSA_ON) { + cal_tmp[0] += ewt->fifo_lastdata[0]; + cal_tmp[1] += ewt->fifo_lastdata[1]; + cal_tmp[2] += ewt->fifo_lastdata[2]; + cal_tmp[3] += ewt->fifo_lastdata[3]; + get_num++; + } + + /* fifo mode only */ + if (get_num > 1) { + ewt->fifo_lastdata[0] = (signed short)x; + ewt->fifo_lastdata[1] = (signed short)y; + ewt->fifo_lastdata[2] = (signed short)z; + ewt->fifo_lastdata[3] = (signed short)temp; + ewt->fifo_data_flag = EWTSA_ON; + } + + send_x = (signed short)(cal_tmp[0] / get_num); + send_y = (signed short)(cal_tmp[1] / get_num); + send_z = (signed short)(cal_tmp[2] / get_num); + send_temp = (signed short)(cal_tmp[3] / get_num); + } + else { + ewt->fifo_lastdata[0] = 0; + ewt->fifo_lastdata[1] = 0; + ewt->fifo_lastdata[2] = 0; + ewt->fifo_lastdata[3] = 0; + ewt->fifo_data_flag = EWTSA_OFF; + + send_x = 0; + send_y = 0; + send_z = 0; + send_temp = 0; + err = i2c_smbus_write_byte_data(ewt->client, REG_FIFO_CTRL1, FIFO_CTRL1_CLEAR); + if (err < 0) { + dev_err(&ewt->client->dev, "REG_FIFO_CTRL1 read err(%d)\n", err); + } + } + +#if GYRO_MOUNT_SWAP_XY + tmp = send_x; + send_x = send_y; + send_y = tmp; +#endif /* GYRO_MOUNT_SWAP_XY */ +#if GYRO_MOUNT_REVERSE_X + send_x *= -1; +#endif /* GYRO_MOUNT_REVERSE_X */ +#if GYRO_MOUNT_REVERSE_Y + send_y *= -1; +#endif /* GYRO_MOUNT_REVERSE_Y */ +#if GYRO_MOUNT_REVERSE_Z + send_z *= -1; +#endif /* GYRO_MOUNT_REVERSE_Z */ + + if (ewt->event != EWTSA_POLLING_MODE) { + err = i2c_smbus_read_byte_data(ewt->client, REG_INT_STAT); + if (err < 0) { + dev_err(&ewt->client->dev, "REG_INT_STAT read err(%d)\n", err); + err = 0; + } + diag_stat = (unsigned char)err; + spin_lock_irqsave(&ewt->slock, l_flags); + } + + input_report_abs(ewt->input_dev, ABS_X, send_x); + input_report_abs(ewt->input_dev, ABS_Y, send_y); + input_report_abs(ewt->input_dev, ABS_Z, send_z); + input_report_abs(ewt->input_dev, ABS_RX, send_temp); + +#if USE_GPIO_DIAG_PIN + if (ewt->event == EWTSA_POLLING_MODE) { + input_report_abs(ewt->input_dev, ABS_RY, gpio_get_value(DIAG_PIN)); + } + else { + diag_stat = (unsigned char)((unsigned char)(diag_stat & 0x04) >> 2); + input_report_abs(ewt->input_dev, ABS_RY, diag_stat); + } +#else + diag_stat = (unsigned char)((unsigned char)(diag_stat & 0x04) >> 2); + input_report_abs(ewt->input_dev, ABS_RY, diag_stat); +#endif + input_sync(ewt->input_dev); + + if (ewt->event == EWTSA_POLLING_MODE) { + mutex_unlock(&ewt->mlock); + } + else { + spin_unlock_irqrestore(&ewt->slock, l_flags); + } +} + +static void EWTSA_dev_poll(struct work_struct *work) +{ + struct ewtsa_t *ewt; + + if (work == NULL) { + printk(KERN_INFO "struct work_struct null pointer\n"); + return; + } + ewt = container_of(work, struct ewtsa_t, input_work.work); + + if (ewt->sleep == SLEEP_OFF) { + EWTSA_report_abs(ewt); + } +} + +/* Interrupt handler */ +#if USE_GPIO_DRDY_PIN +static irqreturn_t EWTSA_interrupt(int irq, void *dev_id) +{ + struct ewtsa_t *ewtsa = dev_id; + + if (ewtsa == NULL) { + printk(KERN_INFO "struct ewtsa_t null pointer\n"); + return IRQ_RETVAL(1); + } + + if (irq == gpio_to_irq(DRDY_PIN)) { + if (ewtsa->sleep != SLEEP_OFF) { + return IRQ_RETVAL(1); + } + EWTSA_report_abs(ewtsa); + } + return IRQ_RETVAL(1); +} +#endif + +static void EWTSA_input_work_func(struct work_struct *work) +{ + struct ewtsa_t *ewt; + volatile unsigned long start_jiff = jiffies, delay_jiff, next_jiff; + + if (work == NULL) { + printk(KERN_INFO "struct work_struct null pointer\n"); + return; + } + ewt = container_of(work, struct ewtsa_t, input_work.work); + + if (ewt->sleep == SLEEP_OFF) { + EWTSA_dev_poll(work); + + /* adjust polling interval */ + delay_jiff = jiffies; + if (start_jiff > delay_jiff) { /* jiffies overflow */ + delay_jiff += 0xFFFFFFFFUL - start_jiff; + } + else { + delay_jiff -= start_jiff; + } + next_jiff = msecs_to_jiffies(ewt->delay); + /* for delay_jiff > next_jiff */ + delay_jiff %= next_jiff; + next_jiff -= delay_jiff; + + queue_delayed_work(ewt->workqueue, + &ewt->input_work, + next_jiff); + } +} + +/* Suspend function to register device */ +static int EWTSA_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct ewtsa_t *ewt; + s32 ret; + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewt = i2c_get_clientdata(client); + + if (ewt->event == EWTSA_POLLING_MODE) { + cancel_delayed_work(&ewt->input_work); + } + else { + /* disable interrupt */ + ret = i2c_smbus_write_byte_data(ewt->client, REG_INT_CTRL, INT_CTRL_INT_DISABLE); + if (ret < 0) { + dev_err(&ewt->client->dev, "REG_INT_CTRL write err(ret = %d)\n", ret); + } + + if (ewt->sleep == SLEEP_OFF) { +#if USE_GPIO_DRDY_PIN + free_irq(gpio_to_irq(DRDY_PIN), ewt); + /* keep sleep status for resume */ +#endif + } + else { + ewt->sleep = SLEEP_ALLRESET; + } + } +#if USE_GPIO_WINDOW_PIN + gpio_free(WINDOW_PIN); +#endif +#if USE_GPIO_DRDY_PIN + gpio_free(DRDY_PIN); +#endif +#if USE_GPIO_DIAG_PIN + gpio_free(DIAG_PIN); +#endif + ewt->calib_rst = EWTSA_ON; + ewt->reset_param = RST_REG_INIT_ALL; + ret = i2c_smbus_write_byte_data(ewt->client, REG_SLEEP_CTRL, SLEEP_CTRL_ALLRSTSLEEP); + if (ret < 0) { + dev_err(&ewt->client->dev, "REG_SLEEP_CTRL write err(ret = %d)\n", ret); + } + return 0; +} + +/* Resume function to register device */ +static int EWTSA_resume(struct i2c_client *client) +{ + struct ewtsa_t *ewt; + int ret; + + if (client == NULL) { + printk(KERN_INFO "struct i2c_client null pointer\n"); + return -EIO; + } + ewt = i2c_get_clientdata(client); + +#if USE_GPIO_WINDOW_PIN + ret = gpio_request(WINDOW_PIN, "WINDOW"); + ret += gpio_direction_input(WINDOW_PIN); +#else + ret = 0; +#endif +#if USE_GPIO_DIAG_PIN + ret += gpio_request(DIAG_PIN, "DIAG"); + ret += gpio_direction_input(DIAG_PIN); +#endif + if ((ewt->sleep != SLEEP_OFF) || (ret != 0)) { + return 0; + } + +#if GYRO_VER3_ES1 + ret = i2c_smbus_write_byte_data(ewt->client, REG2_CTRL_REG1, CTRL_REG1_ACTIVATE); +#else /* GYRO_VER3_ES1 */ + ret = i2c_smbus_write_byte_data(ewt->client, REG_SLEEP_CTRL, SLEEP_CTRL_ACTIVATE); +#endif /* GYRO_VER3_ES1 */ + + if (ret >= 0) { + EWTSA_system_restart(ewt); + + if (ewt->event == EWTSA_POLLING_MODE) { + queue_delayed_work(ewt->workqueue, + &ewt->input_work, + msecs_to_jiffies(ewt->delay)); + } + else { + /* enable interrupt */ +#if USE_GPIO_DRDY_PIN + ret = gpio_request(DRDY_PIN, "DRDY"); + ret += gpio_direction_input(DRDY_PIN); + ret += request_threaded_irq(gpio_to_irq(DRDY_PIN), NULL, EWTSA_interrupt, IRQF_TRIGGER_RISING, DEVICE_NAME, ewt); + + if (ret == 0) { + ewt->int_skip = EWSTA_INT_SKIP; + if (ewt->fifo_mode == BYPASS_MODE) { + ret = i2c_smbus_write_byte_data(ewt->client, REG_INT_CTRL, INT_CTRL_INT_ENABLE); + } + else { + ret = i2c_smbus_write_byte_data(ewt->client, REG_INT_CTRL, INT_CTRL_INT_ENABLE | INT_CTRL_INT_WTMON_EN); + } + if (ret < 0) { + dev_err(&ewt->client->dev, "REG_INT_CTRL write err(ret = %d)\n", ret); + } + } +#endif + } + } + else { + dev_err(&ewt->client->dev, "REG_SLEEP_CTRL write err(ret = %d)\n", ret); + } + + return 0; +} + +/* Probe function to register device */ +static int EWTSA_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret; + struct ewtsa_t *ewtsa; + + if (client == NULL) { + printk(KERN_INFO "EWTSA_probe:client null pointer\n"); + return -EIO; + } + + ewtsa = kzalloc(sizeof(*ewtsa), GFP_KERNEL); + if (ewtsa == NULL) { + dev_err(&client->dev, "unable to allocate memory!\n"); + return -ENOMEM; + } + + ewtsa->workqueue = create_workqueue("ewtsa_workqueue"); + if (ewtsa->workqueue == NULL) { + dev_err(&client->dev, "Unable to create workqueue!\n"); + kfree(ewtsa); + return -ENOMEM; + } + + ewtsa->client = client; + i2c_set_clientdata(client, ewtsa); + + ewtsa->sleep = SLEEP_INIT_VAL; /* sleep mode */ + ewtsa->delay = DELAY_INIT_VAL; /* information interval */ + ewtsa->range = RANGE_INIT_VAL; /* dynamic range */ + ewtsa->dlpf = DLPF_INIT_VAL; /* dlpf */ + ewtsa->calib = CALIB_FUNC_INIT_VAL; /* calibration function */ + ewtsa->calib_boost_tm = CALIB_BTIM_INIT_VAL; /* boost time[ms] */ + ewtsa->calib_fs = CALIB_FS_INIT_VAL; /* offset renewal rate */ + ewtsa->calib_rst = CALIB_RST_INIT_VAL; /* calib restart flag */ + ewtsa->fifo_mode = FIFO_TYPE_INIT_VAL; /* fifo type */ + ewtsa->reset_param = RST_REG_INIT_ALL; /* register setting flag */ +#if USE_GPIO_DRDY_PIN + ewtsa->event = EWTSA_INTERUPT_MODE; /* data detect method */ +#else + ewtsa->event = EWTSA_POLLING_MODE; /* data detect method */ +#endif + ewtsa->calib_boost_fs = CALIB_BFS_INIT_VAL; /* calibration boost fs */ + ewtsa->int_skip = EWSTA_INT_CLEAR; /* first data flag */ + ewtsa->calib_alway = CALIB_CLK_INIT_VAL; /* socclk flag */ + ewtsa->hpf = CALIB_HPF_INIT_VAL; /* hpf */ + ewtsa->w1_thres_x = THRES_CENTER_INIT_X; /* threshold center val */ + ewtsa->w1_thres_y = THRES_CENTER_INIT_Y; /* threshold center val */ + ewtsa->w1_thres_z = THRES_CENTER_INIT_Z; /* threshold center val */ + ewtsa->w1_datamask = W1_MASK_INIT_VAL; /* window1 datamask set */ + ewtsa->w1_thres_en = W1_FUNC_INIT_VAL; /* window1 function flag */ + ewtsa->w2_thres_en = W2_FUNC_INIT_VAL; /* window2 function flag */ + ewtsa->offset_lag = CALIB_LAG_INIT_VAL; /* offset renewal lag */ + ewtsa->w1_thres_level = W1_LV_INIT_VAL; /* window1 threshold lv */ + ewtsa->fifo_data_flag = EWTSA_OFF; /* last data flag */ + ewtsa->fifo_num = 0; /* fifo number */ + memset(ewtsa->fifo_lastdata, 0x00, sizeof(ewtsa->fifo_lastdata)); + + /*create device file in sysfs as user interface */ + ret = device_create_file(&client->dev, &ewtsa_sleep_attr); + if (ret != 0) { + dev_err(&client->dev, "create device(sleep_attr) file failed!\n"); + destroy_workqueue(ewtsa->workqueue); + kfree(ewtsa); + return ret; + } + ret = device_create_file(&client->dev, &ewtsa_delay_attr); + if (ret != 0) { + dev_err(&client->dev, "create device(delay_attr) file failed!\n"); + device_remove_file(&client->dev, &ewtsa_sleep_attr); + destroy_workqueue(ewtsa->workqueue); + kfree(ewtsa); + return ret; + } + ret = device_create_file(&client->dev, &ewtsa_range_attr); + if (ret != 0) { + dev_err(&client->dev, "create device(range_attr) file failed!\n"); + device_remove_file(&client->dev, &ewtsa_delay_attr); + device_remove_file(&client->dev, &ewtsa_sleep_attr); + destroy_workqueue(ewtsa->workqueue); + kfree(ewtsa); + return ret; + } + ret = device_create_file(&client->dev, &ewtsa_calib_attr); + if (ret != 0) { + dev_err(&client->dev, "create device(calib_attr) file failed!\n"); + device_remove_file(&client->dev, &ewtsa_range_attr); + device_remove_file(&client->dev, &ewtsa_delay_attr); + device_remove_file(&client->dev, &ewtsa_sleep_attr); + destroy_workqueue(ewtsa->workqueue); + kfree(ewtsa); + return ret; + } + ret = device_create_file(&client->dev, &ewtsa_config_attr); + if (ret != 0) { + dev_err(&client->dev, "create device(calib_attr) file failed!\n"); + device_remove_file(&client->dev, &ewtsa_calib_attr); + device_remove_file(&client->dev, &ewtsa_range_attr); + device_remove_file(&client->dev, &ewtsa_delay_attr); + device_remove_file(&client->dev, &ewtsa_sleep_attr); + destroy_workqueue(ewtsa->workqueue); + kfree(ewtsa); + return ret; + } + + /*input poll device register */ + ewtsa->input_dev = input_allocate_device(); + if (ewtsa->input_dev == NULL) { + dev_err(&client->dev, "alloc input device failed!\n"); + device_remove_file(&client->dev, &ewtsa_config_attr); + device_remove_file(&client->dev, &ewtsa_calib_attr); + device_remove_file(&client->dev, &ewtsa_range_attr); + device_remove_file(&client->dev, &ewtsa_delay_attr); + device_remove_file(&client->dev, &ewtsa_sleep_attr); + destroy_workqueue(ewtsa->workqueue); + kfree(ewtsa); + return -ENOMEM; + } + ewtsa->input_dev->name = DEVICE_NAME; + ewtsa->input_dev->id.bustype = BUS_I2C; + ewtsa->input_dev->evbit[0] = BIT_MASK(EV_ABS); + + mutex_init(&ewtsa->mlock); + spin_lock_init(&ewtsa->slock); + + input_set_abs_params(ewtsa->input_dev, ABS_X, -MAX_VALUE, MAX_VALUE, 0, 0); + input_set_abs_params(ewtsa->input_dev, ABS_Y, -MAX_VALUE, MAX_VALUE, 0, 0); + input_set_abs_params(ewtsa->input_dev, ABS_Z, -MAX_VALUE, MAX_VALUE, 0, 0); + input_set_abs_params(ewtsa->input_dev, ABS_RX, -200, 200, 0, 0); + input_set_abs_params(ewtsa->input_dev, ABS_RY, -200, 200, 0, 0); + + ret = input_register_device(ewtsa->input_dev); + if (ret != 0) { + dev_err(&client->dev, "register poll device failed!\n"); + input_free_device(ewtsa->input_dev); + device_remove_file(&client->dev, &ewtsa_config_attr); + device_remove_file(&client->dev, &ewtsa_calib_attr); + device_remove_file(&client->dev, &ewtsa_range_attr); + device_remove_file(&client->dev, &ewtsa_delay_attr); + device_remove_file(&client->dev, &ewtsa_sleep_attr); + destroy_workqueue(ewtsa->workqueue); + kfree(ewtsa); + return ret; + } + + /* GPIO configuration */ + ret = i2c_smbus_write_byte_data(ewtsa->client, REG_SLEEP_CTRL, SLEEP_CTRL_ALLRSTSLEEP); + if (ret < 0) { + dev_err(&ewtsa->client->dev, "REG_SLEEP_CTRL write err(data = 0x00, ret = %d)\n", ret); + } +#if USE_GPIO_WINDOW_PIN + ret = gpio_request(WINDOW_PIN, "WINDOW"); + ret += gpio_direction_input(WINDOW_PIN); +#else + ret = 0; +#endif +#if USE_GPIO_DIAG_PIN + ret += gpio_request(DIAG_PIN, "DIAG"); + ret += gpio_direction_input(DIAG_PIN); +#endif + if (ret != 0) { + dev_err(&client->dev, "gpio_request failed!\n"); +#if USE_GPIO_WINDOW_PIN + gpio_free(WINDOW_PIN); +#endif +#if USE_GPIO_DIAG_PIN + gpio_free(DIAG_PIN); +#endif + input_unregister_device(ewtsa->input_dev); + input_free_device(ewtsa->input_dev); + device_remove_file(&client->dev, &ewtsa_config_attr); + device_remove_file(&client->dev, &ewtsa_calib_attr); + device_remove_file(&client->dev, &ewtsa_range_attr); + device_remove_file(&client->dev, &ewtsa_delay_attr); + device_remove_file(&client->dev, &ewtsa_sleep_attr); + destroy_workqueue(ewtsa->workqueue); + kfree(ewtsa); + return ret; + } + + INIT_DELAYED_WORK(&ewtsa->input_work, EWTSA_input_work_func); + + dev_info(&client->dev, "ewtsa device is probed successfully.\n"); + return 0; +} + +/* Remove function to unregister the device */ +static int EWTSA_remove(struct i2c_client *client) +{ + struct ewtsa_t *ewtsa; + + if (client == NULL) { + printk(KERN_INFO "client pointer null!\n"); + return -EIO; + } + ewtsa = i2c_get_clientdata(client); + + i2c_smbus_write_byte_data(ewtsa->client, REG_SLEEP_CTRL, SLEEP_CTRL_ALLRSTSLEEP); +#if USE_GPIO_DRDY_PIN + if (ewtsa->sleep == SLEEP_OFF) { + free_irq(gpio_to_irq(DRDY_PIN), ewtsa); + gpio_free(DRDY_PIN); + } +#endif +#if USE_GPIO_WINDOW_PIN + gpio_free(WINDOW_PIN); +#endif +#if USE_GPIO_DIAG_PIN + gpio_free(DIAG_PIN); +#endif + + input_unregister_device(ewtsa->input_dev); + input_free_device(ewtsa->input_dev); + destroy_workqueue(ewtsa->workqueue); + device_remove_file(&client->dev, &ewtsa_sleep_attr); + device_remove_file(&client->dev, &ewtsa_delay_attr); + device_remove_file(&client->dev, &ewtsa_range_attr); + device_remove_file(&client->dev, &ewtsa_calib_attr); + device_remove_file(&client->dev, &ewtsa_config_attr); + kfree(ewtsa); + dev_info(&client->dev, "ewtsa device is removed successfully.\n"); + return 0; +} + + +static int __init init_ewtsa(void) +{ + return i2c_add_driver(&i2c_ewtsa_driver); +} + +static void __exit exit_ewtsa(void) +{ + i2c_del_driver(&i2c_ewtsa_driver); +} + +module_init(init_ewtsa); +module_exit(exit_ewtsa); + +MODULE_AUTHOR("Panasonic Electronic Devices"); +MODULE_DESCRIPTION("Gyro sensor driver"); +MODULE_LICENSE("GPL"); |
