/***************************************************************************** * Copyright (C) 2016 MediaTek Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. * * Accelerometer Sensor Driver * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * 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. * * *****************************************************************************/ /***************************************************************************** *** HEADER FILES *****************************************************************************/ #include "cust_acc.h" #include "accel.h" #include "mc3433.h" /***************************************************************************** *** CONFIGURATION *****************************************************************************/ /* Just for mcube's calibration APK*/ /* #define _MC3XXX_SUPPORT_DOT_CALIBRATION_ */ #define _MC3XXX_SUPPORT_LPF_ /*#define _MC3XXX_SUPPORT_CONCURRENCY_PROTECTION_ */ /* #define _MC3XXX_SUPPORT_APPLY_AVERAGE_AGORITHM_ */ /* #define _MC3XXX_SUPPORT_PERIODIC_DOC_ */ /* #define _MC3XXX_SUPPORT_VPROXIMITY_SENSOR_ */ #define _MC3XXX_SUPPORT_LRF_ /* #define _MC3XXX_SUPPORT_POWER_SAVING_SHUTDOWN_POWER_ */ #define C_MAX_FIR_LENGTH (32) #define VIRTUAL_Z 0 /***************************************************************************** *** CONSTANT / DEFINITION *****************************************************************************/ /************************** *** CONFIGURATION **************************/ #define MC3XXX_DEV_NAME "MC3XXX" #define MC3XXX_DEV_DRIVER_VERSION "2.1.6" #define MC3XXX_DEV_DRIVER_VERSION_VIRTUAL_Z "1.0.1" /************************** *** COMMON **************************/ #define MC3XXX_AXIS_X 0 #define MC3XXX_AXIS_Y 1 #define MC3XXX_AXIS_Z 2 #define MC3XXX_AXES_NUM 3 #define MC3XXX_DATA_LEN 6 #define MC3XXX_RESOLUTION_LOW 1 #define MC3XXX_RESOLUTION_HIGH 2 #define MC3XXX_LOW_REOLUTION_DATA_SIZE 3 #define MC3XXX_HIGH_REOLUTION_DATA_SIZE 6 #define MC3XXX_INIT_SUCC (0) #define MC3XXX_INIT_FAIL (-1) #define MC3XXX_REGMAP_LENGTH (64) #define C_I2C_FIFO_SIZE 8 #define ACC_TAG " " #define ACC_LOG(fmt, args...) pr_debug(ACC_TAG"%s %d : "\ fmt, __func__, __LINE__, ##args) #define ACC_PR_ERR(fmt, args...) pr_err(ACC_TAG"%s %d : "\ fmt, __func__, __LINE__, ##args) /* Maintain cust info here */ struct acc_hw accel_cust; static struct acc_hw *hw = &accel_cust; /* For driver get cust info */ struct acc_hw *get_cust_acc(void) { return &accel_cust; } /***************************************************************************** *** DATA TYPE / STRUCTURE DEFINITION / ENUM *****************************************************************************/ enum MCUBE_TRC { MCUBE_TRC_FILTER = 0x01, MCUBE_TRC_RAWDATA = 0x02, MCUBE_TRC_IOCTL = 0x04, MCUBE_TRC_CALI = 0X08, MCUBE_TRC_INFO = 0X10, MCUBE_TRC_REGXYZ = 0X20, }; struct scale_factor { u8 whole; u8 fraction; }; struct data_resolution { struct scale_factor scalefactor; int sensitivity; }; struct data_filter { s16 raw[C_MAX_FIR_LENGTH][MC3XXX_AXES_NUM]; int sum[MC3XXX_AXES_NUM]; int num; int idx; }; struct mc3xxx_i2c_data { /* ================================================ */ struct i2c_client *client; struct acc_hw *hw; struct hwmsen_convert cvt; /* ================================================ */ struct data_resolution *reso; atomic_t trace; atomic_t suspend; atomic_t selftest; atomic_t filter; s16 cali_sw[MC3XXX_AXES_NUM + 1]; /* ================================================ */ s16 offset[MC3XXX_AXES_NUM + 1]; s16 data[MC3XXX_AXES_NUM + 1]; /* ================================================ */ #if defined(_MC3XXX_SUPPORT_LPF_) atomic_t firlen; atomic_t fir_en; struct data_filter fir; #endif }; #ifdef _MC3XXX_SUPPORT_LRF_ struct S_LRF_CB { s16 nIsNewRound; s16 nPreDiff; s16 nPreValue; s16 nMaxValue; s16 nMinValue; s16 nRepValue; s16 nNewDataMonitorCount; }; #endif /***************************************************************************** *** EXTERNAL FUNCTION *****************************************************************************/ /* extern struct acc_hw* mc3xxx_get_cust_acc_hw(void); */ /***************************************************************************** *** STATIC FUNCTION *****************************************************************************/ static int mc3xxx_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); static int mc3xxx_i2c_remove(struct i2c_client *client); static int _mc3xxx_i2c_auto_probe(struct i2c_client *client); static int mc3xxx_suspend(struct device *dev); static int mc3xxx_resume(struct device *dev); static int mc3xxx_local_init(void); static int mc3xxx_remove(void); static int MC3XXX_SetPowerMode(struct i2c_client *client, bool enable); static int MC3XXX_WriteCalibration(struct i2c_client *client, int dat[MC3XXX_AXES_NUM]); static void MC3XXX_SetGain(void); /***************************************************************************** *** STATIC VARIABLE & CONTROL BLOCK DECLARATION *****************************************************************************/ static unsigned char s_bResolution; static unsigned char s_bPCODE; static unsigned char s_bPCODER; static unsigned char s_bHWID; static unsigned char s_bMPOL; static int s_nInitFlag = MC3XXX_INIT_FAIL; static struct acc_init_info mc3xxx_init_info = { .name = MC3XXX_DEV_NAME, .init = mc3xxx_local_init, .uninit = mc3xxx_remove, }; #ifdef CONFIG_OF static const struct of_device_id accel_of_match[] = { {.compatible = "mediatek,gsensor"}, {}, }; #endif static const struct i2c_device_id mc3xxx_i2c_id[] = { {MC3XXX_DEV_NAME, 0}, {}, }; static unsigned short mc3xxx_i2c_auto_probe_addr[] = { 0x4C, 0x6C, 0x4E, 0x6D, 0x6E, 0x6F }; #ifdef CONFIG_PM_SLEEP static const struct dev_pm_ops mc3xxx_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mc3xxx_suspend, mc3xxx_resume) }; #endif static struct i2c_driver mc3xxx_i2c_driver = { .driver = { .name = MC3XXX_DEV_NAME, #ifdef CONFIG_PM_SLEEP .pm = &mc3xxx_pm_ops, #endif #ifdef CONFIG_OF .of_match_table = accel_of_match, #endif }, .probe = mc3xxx_i2c_probe, .remove = mc3xxx_i2c_remove, .id_table = mc3xxx_i2c_id, }; static struct i2c_client *mc3xxx_i2c_client; static struct mc3xxx_i2c_data *mc3xxx_obj_i2c_data; static struct data_resolution mc3xxx_offset_resolution = { {7, 8}, 256 }; static bool mc3xxx_sensor_power; static struct GSENSOR_VECTOR3D gsensor_gain; static char selftestRes[10] = {0}; static struct file *fd_file; static mm_segment_t oldfs; static unsigned char offset_buf[6]; static signed int offset_data[3]; static signed int gain_data[3]; static unsigned char s_baOTP_OffsetData[6] = { 0 }; static signed int s_nIsRBM_Enabled; static DEFINE_MUTEX(MC3XXX_i2c_mutex); #ifdef _MC3XXX_SUPPORT_LRF_ static struct S_LRF_CB s_taLRF_CB[MC3XXX_AXES_NUM]; #endif #ifdef _MC3XXX_SUPPORT_CONCURRENCY_PROTECTION_ static struct semaphore s_tSemaProtect; #endif #ifdef _MC3XXX_SUPPORT_DOT_CALIBRATION_ static int s_nIsCaliLoaded; static int LPF_FirstRun = 1; #endif static int LPF_SamplingRate = 5; static int LPF_CutoffFrequency = 0x00000004; static unsigned int iAReal0_X; static unsigned int iAcc0Lpf0_X; static unsigned int iAcc0Lpf1_X; static unsigned int iAcc1Lpf0_X; static unsigned int iAcc1Lpf1_X; static unsigned int iAReal0_Y; static unsigned int iAcc0Lpf0_Y; static unsigned int iAcc0Lpf1_Y; static unsigned int iAcc1Lpf0_Y; static unsigned int iAcc1Lpf1_Y; static unsigned int iAReal0_Z; static unsigned int iAcc0Lpf0_Z; static unsigned int iAcc0Lpf1_Z; static unsigned int iAcc1Lpf0_Z; static unsigned int iAcc1Lpf1_Z; static signed char s_bAccuracyStatus = SENSOR_STATUS_ACCURACY_MEDIUM; #ifdef _MC3XXX_SUPPORT_PERIODIC_DOC_ static DECLARE_WAIT_QUEUE_HEAD(wq_mc3xxx_open_status); static atomic_t s_t_mc3xxx_open_status = ATOMIC_INIT(0); static unsigned char s_bIsPDOC_Enabled; #endif #ifdef _MC3XXX_SUPPORT_VPROXIMITY_SENSOR_ static int P_STATUS; static int prev_P_STATUS; #endif /***************************************************************************** *** MACRO *****************************************************************************/ #ifdef _MC3XXX_SUPPORT_CONCURRENCY_PROTECTION_ static int mc3xxx_mutex_lock(void); static void mc3xxx_mutex_unlock(void); static void mc3xxx_mutex_init(void); static void mc3xxx_mutex_init(void) { sema_init(&s_tSemaProtect, 1); } static int mc3xxx_mutex_lock(void) { if (down_interruptible(&s_tSemaProtect)) return (-ERESTARTSYS); return 0; } static void mc3xxx_mutex_unlock(void) { up(&s_tSemaProtect); } #else #define mc3xxx_mutex_init() do {} while (0) #define mc3xxx_mutex_lock() do {} while (0) #define mc3xxx_mutex_unlock() do {} while (0) #endif #define IS_MCFM12() ((s_bHWID >= 0xC0) && (s_bHWID <= 0xCF)) #define IS_MCFM3X() ((s_bHWID == 0x20)\ || ((s_bHWID >= 0x22) && (s_bHWID <= 0x2F))) /***************************************************************************** *** TODO *****************************************************************************/ #define DATA_PATH "/sdcard2/mcube-register-map.txt" #ifdef _MC3XXX_SUPPORT_DOT_CALIBRATION_ static char file_path[MC3XXX_BUF_SIZE] = "/data/data/com.mcube.acc/files/mcube-calib.txt"; static char backup_file_path[MC3XXX_BUF_SIZE] = "/data/misc/sensors/mcube-calib.txt"; #endif /***************************************************************************** *** FUNCTION *****************************************************************************/ /**************I2C operate API*****************************/ static int MC3XXX_i2c_read_block(struct i2c_client *client, u8 addr, u8 *data, u8 len) { u8 beg = addr; int err; struct i2c_msg msgs[2] = {{0}, {0} }; mutex_lock(&MC3XXX_i2c_mutex); msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = 1; msgs[0].buf = &beg; msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD; msgs[1].len = len; msgs[1].buf = data; if (!client) { mutex_unlock(&MC3XXX_i2c_mutex); return -EINVAL; } else if (len > C_I2C_FIFO_SIZE) { ACC_PR_ERR(" length %d exceeds %d\n", len, C_I2C_FIFO_SIZE); mutex_unlock(&MC3XXX_i2c_mutex); return -EINVAL; } err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (err != 2) { ACC_PR_ERR("i2c_transfer error: (%d %p %d) %d\n", addr, data, len, err); err = -EIO; } else err = 0; mutex_unlock(&MC3XXX_i2c_mutex); return err; } static int MC3XXX_i2c_write_block(struct i2c_client *client, u8 addr, u8 *data, u8 len) { /* address occupies one byte, the max length for write is 7 bytes */ int err, idx, num; char buf[C_I2C_FIFO_SIZE]; err = 0; mutex_lock(&MC3XXX_i2c_mutex); if (!client) { mutex_unlock(&MC3XXX_i2c_mutex); return -EINVAL; } else if (len >= C_I2C_FIFO_SIZE) { ACC_PR_ERR(" length %d exceeds %d\n", len, C_I2C_FIFO_SIZE); mutex_unlock(&MC3XXX_i2c_mutex); return -EINVAL; } num = 0; buf[num++] = addr; for (idx = 0; idx < len; idx++) buf[num++] = data[idx]; err = i2c_master_send(client, buf, num); if (err < 0) { ACC_PR_ERR("send command error!!\n"); mutex_unlock(&MC3XXX_i2c_mutex); return -EFAULT; } err = 0; mutex_unlock(&MC3XXX_i2c_mutex); return err; } /***************************************** *** GetLowPassFilter *****************************************/ static unsigned int GetLowPassFilter(unsigned int X0, unsigned int Y1) { unsigned int lTemp; lTemp = Y1; lTemp *= LPF_CutoffFrequency; /* 4HZ LPF RC=0.04 */ X0 *= LPF_SamplingRate; lTemp += X0; lTemp += LPF_CutoffFrequency; lTemp /= (LPF_CutoffFrequency + LPF_SamplingRate); Y1 = lTemp; return Y1; } /***************************************** *** openFile *****************************************/ static struct file *openFile(char *path, int flag, int mode) { struct file *fp = NULL; fp = filp_open(path, flag, mode); if (IS_ERR(fp) || !fp->f_op) return NULL; else return fp; } /***************************************** *** readFile *****************************************/ #ifdef _MC3XXX_SUPPORT_DOT_CALIBRATION_ static int readFile(struct file *fp, char *buf, int readlen) { if (fp->f_op && fp->f_op->read) return fp->f_op->read(fp, buf, readlen, &fp->f_pos); else return -1; } #endif /***************************************** *** writeFile *****************************************/ static int writeFile(struct file *fp, char *buf, int writelen) { if (fp->f_op && fp->f_op->write) return fp->f_op->write(fp, buf, writelen, &fp->f_pos); else return -1; } /***************************************** *** closeFile *****************************************/ static int closeFile(struct file *fp) { filp_close(fp, NULL); return 0; } /***************************************** *** initKernelEnv *****************************************/ static void initKernelEnv(void) { oldfs = get_fs(); set_fs(KERNEL_DS); } /***************************************** * mcube_write_log_data *****************************************/ static int mcube_write_log_data(struct i2c_client *client, u8 data[0x3f]) { #define _WRT_LOG_DATA_BUFFER_SIZE (66 * 50) s16 rbm_data[3] = {0}, raw_data[3] = {0}; int err = 0; char *_pszBuffer = NULL; int n = 0, i = 0; initKernelEnv(); fd_file = openFile(DATA_PATH, O_RDWR | O_CREAT, 0); if (fd_file == NULL) ACC_LOG("%s fail to open\n", __func__); else { rbm_data[MC3XXX_AXIS_X] = (s16)((data[0x0d]) | (data[0x0e] << 8)); rbm_data[MC3XXX_AXIS_Y] = (s16)((data[0x0f]) | (data[0x10] << 8)); rbm_data[MC3XXX_AXIS_Z] = (s16)((data[0x11]) | (data[0x12] << 8)); raw_data[MC3XXX_AXIS_X] = (rbm_data[MC3XXX_AXIS_X] + offset_data[0]/2) * gsensor_gain.x / gain_data[0]; raw_data[MC3XXX_AXIS_Y] = (rbm_data[MC3XXX_AXIS_Y] + offset_data[1]/2) * gsensor_gain.y / gain_data[1]; raw_data[MC3XXX_AXIS_Z] = (rbm_data[MC3XXX_AXIS_Z] + offset_data[2]/2) * gsensor_gain.z / gain_data[2]; _pszBuffer = kzalloc(_WRT_LOG_DATA_BUFFER_SIZE, GFP_KERNEL); if (_pszBuffer == NULL) { ACC_PR_ERR("fail to allocate memory for buffer\n"); return -1; } memset(_pszBuffer, 0, _WRT_LOG_DATA_BUFFER_SIZE); n += sprintf(_pszBuffer+n, "G-sensor RAW X = %d Y = %d Z = %d\n", raw_data[0], raw_data[1], raw_data[2]); n += sprintf(_pszBuffer+n, "G-sensor RBM X = %d Y = %d Z = %d\n", rbm_data[0], rbm_data[1], rbm_data[2]); for (i = 0; i < 63; i++) n += sprintf(_pszBuffer+n, "mCube register map Register[%x] = 0x%x\n", i, data[i]); mdelay(50); err = writeFile(fd_file, _pszBuffer, n); if (err <= 0) ACC_LOG("write file error %d\n", err); kfree(_pszBuffer); set_fs(oldfs); closeFile(fd_file); } return 0; } #ifdef _MC3XXX_SUPPORT_DOT_CALIBRATION_ /***************************************** *** mcube_read_cali_file *****************************************/ static int mcube_read_cali_file(struct i2c_client *client) { int cali_data[3] = {0}, cali_data1[3] = {0}; int err = 0; char buf[64] = {0}; initKernelEnv(); fd_file = openFile(file_path, O_RDONLY, 0); if (fd_file == NULL) { ACC_LOG("%s:fail to open calibration file: %s\n", __func__, file_path); fd_file = openFile(backup_file_path, O_RDONLY, 0); if (fd_file == NULL) { ACC_LOG("%s:fail to open calibration file: %s\n", __func__, backup_file_path); cali_data[0] = 0; cali_data[1] = 0; cali_data[2] = 0; return -1; } } else memset(buf, 0, sizeof(buf)); err = readFile(fd_file, buf, sizeof(buf)); if (err <= 0) ACC_LOG("read file error %d\n", err); set_fs(oldfs); closeFile(fd_file); err = sscanf(buf, "%d %d %d", &cali_data[MC3XXX_AXIS_X], &cali_data[MC3XXX_AXIS_Y], &cali_data[MC3XXX_AXIS_Z]); cali_data1[MC3XXX_AXIS_X] = cali_data[MC3XXX_AXIS_X] * gsensor_gain.x / GRAVITY_EARTH_1000; cali_data1[MC3XXX_AXIS_Y] = cali_data[MC3XXX_AXIS_Y] * gsensor_gain.y / GRAVITY_EARTH_1000; cali_data1[MC3XXX_AXIS_Z] = cali_data[MC3XXX_AXIS_Z] * gsensor_gain.z / GRAVITY_EARTH_1000; MC3XXX_WriteCalibration(client, cali_data1); return 0; } /***************************************** *** mcube_load_cali *****************************************/ static void mcube_load_cali(struct i2c_client *pt_i2c_client) { if (false == s_nIsCaliLoaded) { if (mcube_read_cali_file(pt_i2c_client) == MC3XXX_RETCODE_SUCCESS) s_nIsCaliLoaded = true; } } #endif /* _MC3XXX_SUPPORT_DOT_CALIBRATION_ */ /***************************************** *** mcube_psensor_ioctl *****************************************/ #ifdef _MC3XXX_SUPPORT_VPROXIMITY_SENSOR_ static long mcube_psensor_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; void __user *data; int pSensor = 0; if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (err) { PS_ERR("access error: %08X, (%2d, %2d)\n", cmd, _IOC_DIR(cmd), _IOC_SIZE(cmd)); return -EFAULT; } switch (cmd) { case PSENSOR_IOCTL_SET_POSTURE: data = (void __user *)arg; if (data == NULL) { err = -EINVAL; break; } if (copy_from_user(&pSensor, data, sizeof(int))) { err = -EFAULT; break; } P_STATUS = pSensor; PS_LOG("IOCTL Get P_STATUS = %d", pSensor); break; default: PS_ERR("unknown IOCTL: 0x%08x\n", cmd); /* err = -ENOIOCTLCMD; */ break; } return err; } /***************************************** *** STATIC STRUCTURE:: fops *****************************************/ static const struct file_operations mcube_psensor_fops = { .owner = THIS_MODULE, .unlocked_ioctl = mcube_psensor_ioctl, }; /***************************************** *** STATIC STRUCTURE:: misc-device *****************************************/ static struct miscdevice mcube_psensor_device = { .minor = MISC_DYNAMIC_MINOR, .name = "psensor", .fops = &mcube_psensor_fops, }; /***************************************** *** psensor_ps_operate *****************************************/ static int psensor_ps_operate(void *self, uint32_t command, void *buff_in, int size_in, void *buff_out, int size_out, int *actualout) { int err = 0; int value; int val = -1; hwm_sensor_data *sensor_data; switch (command) { case SENSOR_DELAY: if ((buff_in == NULL) || (size_in < sizeof(int))) { PS_ERR("Set delay parameter error!\n"); err = -EINVAL; } /* Do nothing */ break; case SENSOR_ENABLE: value = *(int *)buff_in; if (value) { if ((buff_in == NULL) || (size_in < sizeof(int))) { PS_ERR("Enable sensor parameter error!\n"); err = -EINVAL; } else { value = *(int *)buff_in; PS_ERR("enable ps\n"); } } else PS_ERR("disable ps\n"); break; case SENSOR_GET_DATA: PS_LOG("fwq get ps data !!!!!!\n"); if ((buff_out == NULL) || (size_out < sizeof(hwm_sensor_data))) { PS_ERR("get sensor data parameter error!\n"); err = -EINVAL; } else { sensor_data = (hwm_sensor_data *)buff_out; PS_LOG("mcube sensor data P_STATUS=%d\n", P_STATUS); if (prev_P_STATUS != P_STATUS) { if (P_STATUS == 0) { PS_LOG("TURN ON LCD\n"); val = 1; PS_LOG( "Set val = 1, Proximity sensor far away\n"); } else if (P_STATUS == 1) { PS_LOG("TURN OFF LCD\n"); val = 0; PS_LOG("Set val = 0, Proximity sensor close\n"); } PS_LOG( "mcube sensor data prev_P_STATUS=%d, P_STATUS=%d\n", prev_P_STATUS, P_STATUS); prev_P_STATUS = P_STATUS; } else { PS_LOG("P_STATUS %5d=>%5d\n", prev_P_STATUS, P_STATUS); prev_P_STATUS = P_STATUS; val = (P_STATUS == 0) ? (1):(0); } sensor_data->values[0] = val; sensor_data->value_divide = 1; sensor_data->status = SENSOR_STATUS_ACCURACY_MEDIUM; prev_P_STATUS = P_STATUS; } break; default: PS_ERR( "proxmy sensor operate function has no this command %d!\n", command); err = -1; } return err; } #endif /* end of _MC3XXX_SUPPORT_VPROXIMITY_SENSOR_ */ /***************************************** *** MC3XXX_power *****************************************/ static void MC3XXX_power(struct acc_hw *hw, unsigned int on) { } #ifdef _MC3XXX_SUPPORT_DOT_CALIBRATION_ /***************************************** *** MC3XXX_rbm *****************************************/ static void MC3XXX_rbm(struct i2c_client *client, int enable) { u8 _baDataBuf[3] = { 0 }; _baDataBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x07, _baDataBuf, 0x01); MC3XXX_i2c_read_block(client, 0x04, _baDataBuf, 0x01); if (0x00 == (_baDataBuf[0] & 0x40)) { _baDataBuf[0] = 0x6D; MC3XXX_i2c_write_block(client, 0x1B, _baDataBuf, 0x01); _baDataBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x1B, _baDataBuf, 0x01); } if (enable == 1) { _baDataBuf[0] = 0x00; MC3XXX_i2c_write_block(client, 0x3B, _baDataBuf, 0x01); _baDataBuf[0] = 0x02; MC3XXX_i2c_write_block(client, 0x14, _baDataBuf, 0x01); if (s_bResolution == MC3XXX_RESOLUTION_LOW) gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 1024; s_nIsRBM_Enabled = 1; LPF_FirstRun = 1; } else if (enable == 0) { _baDataBuf[0] = 0x00; MC3XXX_i2c_write_block(client, 0x14, _baDataBuf, 0x01); _baDataBuf[0] = s_bPCODER; MC3XXX_i2c_write_block(client, 0x3B, _baDataBuf, 0x01); MC3XXX_SetGain(); s_nIsRBM_Enabled = 0; } MC3XXX_i2c_read_block(client, 0x04, _baDataBuf, 0x01); if (_baDataBuf[0] & 0x40) { _baDataBuf[0] = 0x6D; MC3XXX_i2c_write_block(client, 0x1B, _baDataBuf, 0x01); _baDataBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x1B, _baDataBuf, 0x01); } /* MC3XXX_i2c_read_block(client, 0x04, _baDataBuf, 0x01); */ /* ACC_LOG("END - REG(0x04): 0x%X\n", _baDataBuf[0]); */ _baDataBuf[0] = 0x41; MC3XXX_i2c_write_block(client, 0x07, _baDataBuf, 0x01); mdelay(220); } /***************************************** *** MC3XXX_ReadData_RBM *****************************************/ static int MC3XXX_ReadData_RBM(struct i2c_client *client, int data[MC3XXX_AXES_NUM]) { u8 addr = 0x0d; u8 rbm_buf[MC3XXX_DATA_LEN] = {0}; int err = 0; int _nTemp = 0; if (client == NULL) { err = -EINVAL; return err; } err = MC3XXX_i2c_read_block(client, addr, rbm_buf, 0x06); if (err) { ACC_PR_ERR("error: %d\n", err); return err; } data[MC3XXX_AXIS_X] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8)); data[MC3XXX_AXIS_Y] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8)); data[MC3XXX_AXIS_Z] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8)); if (s_bPCODE == MC3XXX_PCODE_3250) { _nTemp = data[MC3XXX_AXIS_X]; data[MC3XXX_AXIS_X] = data[MC3XXX_AXIS_Y]; data[MC3XXX_AXIS_Y] = -_nTemp; } else { if (s_bMPOL & 0x01) data[MC3XXX_AXIS_X] = -data[MC3XXX_AXIS_X]; if (s_bMPOL & 0x02) data[MC3XXX_AXIS_Y] = -data[MC3XXX_AXIS_Y]); } return err; } #endif /* _MC3XXX_SUPPORT_DOT_CALIBRATION_ */ /***************************************** *** MC3XXX_ValidateSensorIC *****************************************/ static int MC3XXX_ValidateSensorIC(unsigned char *pbPCode, unsigned char *pbHwID) { if ((*pbHwID == 0x01) || (*pbHwID == 0x03) || ((*pbHwID >= 0x04) && (*pbHwID <= 0x0F))) { if ((*pbPCode == MC3XXX_PCODE_3210) || (*pbPCode == MC3XXX_PCODE_3230) || (*pbPCode == MC3XXX_PCODE_3250)) return MC3XXX_RETCODE_SUCCESS; } else if ((*pbHwID == 0x02) || (*pbHwID == 0x21) || ((*pbHwID >= 0x10) && (*pbHwID <= 0x1F))) { if ((*pbPCode == MC3XXX_PCODE_3210) || (*pbPCode == MC3XXX_PCODE_3230) || (*pbPCode == MC3XXX_PCODE_3250) || (*pbPCode == MC3XXX_PCODE_3410) || (*pbPCode == MC3XXX_PCODE_3410N) || (*pbPCode == MC3XXX_PCODE_3430) || (*pbPCode == MC3XXX_PCODE_3430N)) { return MC3XXX_RETCODE_SUCCESS; } } else if ((*pbHwID >= 0xC0) && (*pbHwID <= 0xCF)) { *pbPCode = (*pbPCode & 0x71); if ((*pbPCode == MC3XXX_PCODE_3510) || (*pbPCode == MC3XXX_PCODE_3530)) return MC3XXX_RETCODE_SUCCESS; } else if ((*pbHwID == 0x20) || ((*pbHwID >= 0x22) && (*pbHwID <= 0x2F))) { *pbPCode = (*pbPCode & 0xF1); if ((*pbPCode == MC3XXX_PCODE_3210) || (*pbPCode == MC3XXX_PCODE_3216) || (*pbPCode == MC3XXX_PCODE_3236) || (*pbPCode == MC3XXX_PCODE_RESERVE_1) || (*pbPCode == MC3XXX_PCODE_RESERVE_2) || (*pbPCode == MC3XXX_PCODE_RESERVE_3) || (*pbPCode == MC3XXX_PCODE_RESERVE_4) || (*pbPCode == MC3XXX_PCODE_RESERVE_5) || (*pbPCode == MC3XXX_PCODE_RESERVE_6) || (*pbPCode == MC3XXX_PCODE_RESERVE_7) || (*pbPCode == MC3XXX_PCODE_RESERVE_8) || (*pbPCode == MC3XXX_PCODE_RESERVE_9)) return MC3XXX_RETCODE_SUCCESS; } return MC3XXX_RETCODE_ERROR_IDENTIFICATION; } /***************************************** *** MC3XXX_Read_Chip_ID *****************************************/ static int MC3XXX_Read_Chip_ID(struct i2c_client *client, char *buf) { u8 _bChipID[4] = { 0 }; if (!buf || !client) return -EINVAL; if (MC3XXX_i2c_read_block(client, 0x3C, _bChipID, 4)) { ACC_PR_ERR("[%s] i2c read fail\n", __func__); _bChipID[0] = 0; _bChipID[1] = 0; _bChipID[2] = 0; _bChipID[3] = 0; } return sprintf(buf, "%02X-%02X-%02X-%02X\n", _bChipID[3], _bChipID[2], _bChipID[1], _bChipID[0]); } /***************************************** *** MC3XXX_Read_Reg_Map *****************************************/ static int MC3XXX_Read_Reg_Map(struct i2c_client *p_i2c_client, u8 *pbUserBuf) { u8 _baData[MC3XXX_REGMAP_LENGTH] = { 0 }; int _nIndex = 0; if (p_i2c_client == NULL) return (-EINVAL); for (_nIndex = 0; _nIndex < MC3XXX_REGMAP_LENGTH; _nIndex++) { MC3XXX_i2c_read_block(p_i2c_client, _nIndex, &_baData[_nIndex], 1); if (pbUserBuf != NULL) pbUserBuf[_nIndex] = _baData[_nIndex]; } mcube_write_log_data(p_i2c_client, _baData); return 0; } /***************************************** *** MC3XXX_SaveDefaultOffset *****************************************/ static void MC3XXX_SaveDefaultOffset(struct i2c_client *p_i2c_client) { MC3XXX_i2c_read_block(p_i2c_client, 0x21, &s_baOTP_OffsetData[0], 3); MC3XXX_i2c_read_block(p_i2c_client, 0x24, &s_baOTP_OffsetData[3], 3); } /***************************************** *** MC3XXX_LPF *****************************************/ #ifdef _MC3XXX_SUPPORT_LPF_ static void MC3XXX_LPF(struct mc3xxx_i2c_data *priv, s16 data[MC3XXX_AXES_NUM]) { if (atomic_read(&priv->filter)) { if (atomic_read(&priv->fir_en) && !atomic_read(&priv->suspend)) { int idx, firlen = atomic_read(&priv->firlen); if (priv->fir.num < firlen) { priv->fir.raw[priv->fir.num][MC3XXX_AXIS_X] = data[MC3XXX_AXIS_X]; priv->fir.raw[priv->fir.num][MC3XXX_AXIS_Y] = data[MC3XXX_AXIS_Y]; priv->fir.raw[priv->fir.num][MC3XXX_AXIS_Z] = data[MC3XXX_AXIS_Z]; priv->fir.sum[MC3XXX_AXIS_X] += data[MC3XXX_AXIS_X]; priv->fir.sum[MC3XXX_AXIS_Y] += data[MC3XXX_AXIS_Y]; priv->fir.sum[MC3XXX_AXIS_Z] += data[MC3XXX_AXIS_Z]; priv->fir.num++; priv->fir.idx++; } else { idx = priv->fir.idx % firlen; priv->fir.sum[MC3XXX_AXIS_X] -= priv->fir.raw[idx][MC3XXX_AXIS_X]; priv->fir.sum[MC3XXX_AXIS_Y] -= priv->fir.raw[idx][MC3XXX_AXIS_Y]; priv->fir.sum[MC3XXX_AXIS_Z] -= priv->fir.raw[idx][MC3XXX_AXIS_Z]; priv->fir.raw[idx][MC3XXX_AXIS_X] = data[MC3XXX_AXIS_X]; priv->fir.raw[idx][MC3XXX_AXIS_Y] = data[MC3XXX_AXIS_Y]; priv->fir.raw[idx][MC3XXX_AXIS_Z] = data[MC3XXX_AXIS_Z]; priv->fir.sum[MC3XXX_AXIS_X] += data[MC3XXX_AXIS_X]; priv->fir.sum[MC3XXX_AXIS_Y] += data[MC3XXX_AXIS_Y]; priv->fir.sum[MC3XXX_AXIS_Z] += data[MC3XXX_AXIS_Z]; priv->fir.idx++; data[MC3XXX_AXIS_X] = priv->fir.sum[MC3XXX_AXIS_X] / firlen; data[MC3XXX_AXIS_Y] = priv->fir.sum[MC3XXX_AXIS_Y] / firlen; data[MC3XXX_AXIS_Z] = priv->fir.sum[MC3XXX_AXIS_Z] / firlen; } } } } #endif /* END OF #ifdef _MC3XXX_SUPPORT_LPF_ */ #ifdef _MC3XXX_SUPPORT_LRF_ /***************************************** *** _MC3XXX_LowResFilter *****************************************/ static void _MC3XXX_LowResFilter(s16 nAxis, s16 naData[MC3XXX_AXES_NUM]) { #define _LRF_DIFF_COUNT_POS 2 #define _LRF_DIFF_COUNT_NEG (-_LRF_DIFF_COUNT_POS) #define _LRF_DIFF_BOUNDARY_POS (_LRF_DIFF_COUNT_POS + 1) #define _LRF_DIFF_BOUNDARY_NEG (_LRF_DIFF_COUNT_NEG - 1) #define _LRF_DIFF_DATA_UNCHANGE_MAX_COUNT 11 signed int _nCurrDiff = 0; signed int _nSumDiff = 0; s16 _nCurrData = naData[nAxis]; _nCurrDiff = (_nCurrData - s_taLRF_CB[nAxis].nRepValue); if ((_nCurrDiff > _LRF_DIFF_COUNT_NEG) && (_nCurrDiff < _LRF_DIFF_COUNT_POS)) { if (s_taLRF_CB[nAxis].nIsNewRound) { s_taLRF_CB[nAxis].nMaxValue = _nCurrData; s_taLRF_CB[nAxis].nMinValue = _nCurrData; s_taLRF_CB[nAxis].nIsNewRound = 0; s_taLRF_CB[nAxis].nNewDataMonitorCount = 0; } else { if (_nCurrData > s_taLRF_CB[nAxis].nMaxValue) s_taLRF_CB[nAxis].nMaxValue = _nCurrData; else if (_nCurrData < s_taLRF_CB[nAxis].nMinValue) s_taLRF_CB[nAxis].nMinValue = _nCurrData; if (s_taLRF_CB[nAxis].nMinValue != s_taLRF_CB[nAxis].nMaxValue) { if (_nCurrData == s_taLRF_CB[nAxis].nPreValue) s_taLRF_CB[nAxis] .nNewDataMonitorCount++; else s_taLRF_CB[nAxis] .nNewDataMonitorCount = 0; } } if (1 != (s_taLRF_CB[nAxis].nMaxValue - s_taLRF_CB[nAxis].nMinValue)) s_taLRF_CB[nAxis].nRepValue = ((s_taLRF_CB[nAxis].nMaxValue + s_taLRF_CB[nAxis].nMinValue) / 2); _nSumDiff = (_nCurrDiff + s_taLRF_CB[nAxis].nPreDiff); if (_nCurrDiff) s_taLRF_CB[nAxis].nPreDiff = _nCurrDiff; if ((_nSumDiff > _LRF_DIFF_BOUNDARY_NEG) && (_nSumDiff < _LRF_DIFF_BOUNDARY_POS)) { if (s_taLRF_CB[nAxis].nNewDataMonitorCount < _LRF_DIFF_DATA_UNCHANGE_MAX_COUNT) { naData[nAxis] = s_taLRF_CB[nAxis].nRepValue; goto _LRF_RETURN; } } } s_taLRF_CB[nAxis].nRepValue = _nCurrData; s_taLRF_CB[nAxis].nPreDiff = 0; s_taLRF_CB[nAxis].nIsNewRound = 1; _LRF_RETURN: s_taLRF_CB[nAxis].nPreValue = _nCurrData; #undef _LRF_DIFF_COUNT_POS #undef _LRF_DIFF_COUNT_NEG #undef _LRF_DIFF_BOUNDARY_POS #undef _LRF_DIFF_BOUNDARY_NEG #undef _LRF_DIFF_DATA_UNCHANGE_MAX_COUNT } #endif /* END OF #ifdef _MC3XXX_SUPPORT_LRF_ */ /***************************************** *** _MC3XXX_ReadData_RBM2RAW *****************************************/ static void _MC3XXX_ReadData_RBM2RAW(s16 waData[MC3XXX_AXES_NUM]) { waData[MC3XXX_AXIS_X] = (waData[MC3XXX_AXIS_X] + offset_data[MC3XXX_AXIS_X] / 2) * 1024 / gain_data[MC3XXX_AXIS_X] + 8096; waData[MC3XXX_AXIS_Y] = (waData[MC3XXX_AXIS_Y] + offset_data[MC3XXX_AXIS_Y] / 2) * 1024 / gain_data[MC3XXX_AXIS_Y] + 8096; waData[MC3XXX_AXIS_Z] = (waData[MC3XXX_AXIS_Z] + offset_data[MC3XXX_AXIS_Z] / 2) * 1024 / gain_data[MC3XXX_AXIS_Z] + 8096; iAReal0_X = (0x0010 * waData[MC3XXX_AXIS_X]); iAcc1Lpf0_X = GetLowPassFilter(iAReal0_X, iAcc1Lpf1_X); iAcc0Lpf0_X = GetLowPassFilter(iAcc1Lpf0_X, iAcc0Lpf1_X); waData[MC3XXX_AXIS_X] = (iAcc0Lpf0_X / 0x0010); iAReal0_Y = (0x0010 * waData[MC3XXX_AXIS_Y]); iAcc1Lpf0_Y = GetLowPassFilter(iAReal0_Y, iAcc1Lpf1_Y); iAcc0Lpf0_Y = GetLowPassFilter(iAcc1Lpf0_Y, iAcc0Lpf1_Y); waData[MC3XXX_AXIS_Y] = (iAcc0Lpf0_Y / 0x0010); iAReal0_Z = (0x0010 * waData[MC3XXX_AXIS_Z]); iAcc1Lpf0_Z = GetLowPassFilter(iAReal0_Z, iAcc1Lpf1_Z); iAcc0Lpf0_Z = GetLowPassFilter(iAcc1Lpf0_Z, iAcc0Lpf1_Z); waData[MC3XXX_AXIS_Z] = (iAcc0Lpf0_Z / 0x0010); waData[MC3XXX_AXIS_X] = (waData[MC3XXX_AXIS_X] - 8096) * gsensor_gain.x / 1024; waData[MC3XXX_AXIS_Y] = (waData[MC3XXX_AXIS_Y] - 8096) * gsensor_gain.y / 1024; waData[MC3XXX_AXIS_Z] = (waData[MC3XXX_AXIS_Z] - 8096) * gsensor_gain.z / 1024; iAcc0Lpf1_X = iAcc0Lpf0_X; iAcc1Lpf1_X = iAcc1Lpf0_X; iAcc0Lpf1_Y = iAcc0Lpf0_Y; iAcc1Lpf1_Y = iAcc1Lpf0_Y; iAcc0Lpf1_Z = iAcc0Lpf0_Z; iAcc1Lpf1_Z = iAcc1Lpf0_Z; } /***************************************** *** MC3XXX_ReadData *****************************************/ static int MC3XXX_ReadData(struct i2c_client *pt_i2c_client, s16 waData[MC3XXX_AXES_NUM]) { u8 _baData[MC3XXX_DATA_LEN] = { 0 }; s16 _nTemp = 0; #ifdef _MC3XXX_SUPPORT_LPF_ struct mc3xxx_i2c_data *_ptPrivData = NULL; #endif if (pt_i2c_client == NULL) { ACC_PR_ERR("ERR: Null Pointer\n"); return MC3XXX_RETCODE_ERROR_NULL_POINTER; } if (!s_nIsRBM_Enabled) { if (s_bResolution == MC3XXX_RESOLUTION_LOW) { if (MC3XXX_i2c_read_block(pt_i2c_client, MC3XXX_REG_XOUT, _baData, MC3XXX_LOW_REOLUTION_DATA_SIZE)) { ACC_PR_ERR("ERR: fail to read data via I2C!\n"); return MC3XXX_RETCODE_ERROR_I2C; } waData[MC3XXX_AXIS_X] = ((s8) _baData[0]); waData[MC3XXX_AXIS_Y] = ((s8) _baData[1]); waData[MC3XXX_AXIS_Z] = ((s8) _baData[2]); #ifdef _MC3XXX_SUPPORT_LRF_ _MC3XXX_LowResFilter(MC3XXX_AXIS_X, waData); _MC3XXX_LowResFilter(MC3XXX_AXIS_Y, waData); _MC3XXX_LowResFilter(MC3XXX_AXIS_Z, waData); #endif } else if (s_bResolution == MC3XXX_RESOLUTION_HIGH) { if (MC3XXX_i2c_read_block(pt_i2c_client, MC3XXX_REG_XOUT_EX_L, _baData, MC3XXX_HIGH_REOLUTION_DATA_SIZE)) { ACC_PR_ERR("ERR: fail to read data via I2C!\n"); return MC3XXX_RETCODE_ERROR_I2C; } waData[MC3XXX_AXIS_X] = ((signed short) ((_baData[0]) | (_baData[1]<<8))); waData[MC3XXX_AXIS_Y] = ((signed short) ((_baData[2]) | (_baData[3]<<8))); waData[MC3XXX_AXIS_Z] = ((signed short) ((_baData[4]) | (_baData[5]<<8))); } #ifdef _MC3XXX_SUPPORT_LPF_ _ptPrivData = i2c_get_clientdata(pt_i2c_client); MC3XXX_LPF(_ptPrivData, waData); #endif } else { if (MC3XXX_i2c_read_block(pt_i2c_client, MC3XXX_REG_XOUT_EX_L, _baData, MC3XXX_HIGH_REOLUTION_DATA_SIZE)) { ACC_PR_ERR("ERR: fail to read data via I2C!\n"); return MC3XXX_RETCODE_ERROR_I2C; } waData[MC3XXX_AXIS_X] = ((s16)((_baData[0]) | (_baData[1] << 8))); waData[MC3XXX_AXIS_Y] = ((s16)((_baData[2]) | (_baData[3] << 8))); waData[MC3XXX_AXIS_Z] = ((s16)((_baData[4]) | (_baData[5] << 8))); _MC3XXX_ReadData_RBM2RAW(waData); } if (s_bPCODE == MC3XXX_PCODE_3250) { _nTemp = waData[MC3XXX_AXIS_X]; waData[MC3XXX_AXIS_X] = waData[MC3XXX_AXIS_Y]; waData[MC3XXX_AXIS_Y] = -_nTemp; } else { if (s_bMPOL & 0x01) waData[MC3XXX_AXIS_X] = -waData[MC3XXX_AXIS_X]; if (s_bMPOL & 0x02) waData[MC3XXX_AXIS_Y] = -waData[MC3XXX_AXIS_Y]; } return MC3XXX_RETCODE_SUCCESS; } /***************************************** *** MC3XXX_ReadOffset *****************************************/ static int MC3XXX_ReadOffset(struct i2c_client *client, s16 ofs[MC3XXX_AXES_NUM]) { int err = 0; u8 off_data[6] = {0}; s16 _nTemp = 0; if (s_bResolution == MC3XXX_RESOLUTION_HIGH) { err = MC3XXX_i2c_read_block(client, MC3XXX_REG_XOUT_EX_L, off_data, MC3XXX_DATA_LEN); if (err) { ACC_PR_ERR("error: %d\n", err); return err; } ofs[MC3XXX_AXIS_X] = ((s16)(off_data[0])) | ((s16)(off_data[1])<<8); ofs[MC3XXX_AXIS_Y] = ((s16)(off_data[2])) | ((s16)(off_data[3])<<8); ofs[MC3XXX_AXIS_Z] = ((s16)(off_data[4])) | ((s16)(off_data[5])<<8); } else if (s_bResolution == MC3XXX_RESOLUTION_LOW) { err = MC3XXX_i2c_read_block(client, 0, off_data, 3); if (err) { ACC_PR_ERR("error: %d\n", err); return err; } ofs[MC3XXX_AXIS_X] = (s8)off_data[0]; ofs[MC3XXX_AXIS_Y] = (s8)off_data[1]; ofs[MC3XXX_AXIS_Z] = (s8)off_data[2]; } if (s_bPCODE == MC3XXX_PCODE_3250) { _nTemp = ofs[0]; ofs[0] = ofs[1]; ofs[1] = -_nTemp; } else { if (s_bMPOL & 0x01) ofs[0] = -ofs[0]; if (s_bMPOL & 0x02) ofs[1] = -ofs[1]; } return err; } /***************************************** *** MC3XXX_ResetCalibration *****************************************/ static int MC3XXX_ResetCalibration(struct i2c_client *client) { struct mc3xxx_i2c_data *obj = i2c_get_clientdata(client); u8 buf[MC3XXX_AXES_NUM] = {0x00, 0x00, 0x00}; s16 tmp = 0; int err = 0; u8 bMsbFilter = 0x3F; s16 wSignBitMask = 0x2000; s16 wSignPaddingBits = 0xC000; buf[0] = 0x43; err = MC3XXX_i2c_write_block(client, 0x07, buf, 1); if (err) ACC_PR_ERR("error 0x07: %d\n", err); err = MC3XXX_i2c_write_block(client, 0x21, offset_buf, 6); if (err) ACC_PR_ERR("error: %d\n", err); buf[0] = 0x41; err = MC3XXX_i2c_write_block(client, 0x07, buf, 1); if (err) ACC_PR_ERR("error: %d\n", err); mdelay(20); if (IS_MCFM12() || IS_MCFM3X()) { bMsbFilter = 0x7F; wSignBitMask = 0x4000; wSignPaddingBits = 0x8000; } tmp = ((offset_buf[1] & bMsbFilter) << 8) + offset_buf[0]; if (tmp & wSignBitMask) tmp |= wSignPaddingBits; offset_data[0] = tmp; tmp = ((offset_buf[3] & bMsbFilter) << 8) + offset_buf[2]; if (tmp & wSignBitMask) tmp |= wSignPaddingBits; offset_data[1] = tmp; tmp = ((offset_buf[5] & bMsbFilter) << 8) + offset_buf[4]; if (tmp & wSignBitMask) tmp |= wSignPaddingBits; offset_data[2] = tmp; memset(obj->cali_sw, 0x00, sizeof(obj->cali_sw)); return err; } /***************************************** *** MC3XXX_ReadCalibration *****************************************/ static int MC3XXX_ReadCalibration(struct i2c_client *client, int dat[MC3XXX_AXES_NUM]) { struct mc3xxx_i2c_data *obj = i2c_get_clientdata(client); int err = 0; err = MC3XXX_ReadOffset(client, obj->offset); if (err) { ACC_PR_ERR("read offset fail, %d\n", err); return err; } dat[MC3XXX_AXIS_X] = obj->offset[MC3XXX_AXIS_X]; dat[MC3XXX_AXIS_Y] = obj->offset[MC3XXX_AXIS_Y]; dat[MC3XXX_AXIS_Z] = obj->offset[MC3XXX_AXIS_Z]; return 0; } /***************************************** *** MC3XXX_WriteCalibration *****************************************/ static int MC3XXX_WriteCalibration(struct i2c_client *client, int dat[MC3XXX_AXES_NUM]) { struct mc3xxx_i2c_data *obj = i2c_get_clientdata(client); int err = 0; u8 buf[9] = { 0}; s16 tmp = 0, x_gain = 0, y_gain = 0, z_gain = 0; s32 x_off = 0, y_off = 0, z_off = 0; int cali[MC3XXX_AXES_NUM] = {0}; int _nTemp = 0; u8 bMsbFilter = 0x3F; s16 wSignBitMask = 0x2000; s16 wSignPaddingBits = 0xC000; s32 dwRangePosLimit = 0x1FFF; s32 dwRangeNegLimit = -0x2000; cali[MC3XXX_AXIS_X] = obj->cvt.sign[MC3XXX_AXIS_X] * (dat[obj->cvt.map[MC3XXX_AXIS_X]]); cali[MC3XXX_AXIS_Y] = obj->cvt.sign[MC3XXX_AXIS_Y] * (dat[obj->cvt.map[MC3XXX_AXIS_Y]]); cali[MC3XXX_AXIS_Z] = obj->cvt.sign[MC3XXX_AXIS_Z] * (dat[obj->cvt.map[MC3XXX_AXIS_Z]]); if (s_bPCODE == MC3XXX_PCODE_3250) { _nTemp = cali[MC3XXX_AXIS_X]; cali[MC3XXX_AXIS_X] = -cali[MC3XXX_AXIS_Y]; cali[MC3XXX_AXIS_Y] = _nTemp; } else { if (s_bMPOL & 0x01) cali[MC3XXX_AXIS_X] = -cali[MC3XXX_AXIS_X]; if (s_bMPOL & 0x02) cali[MC3XXX_AXIS_Y] = -cali[MC3XXX_AXIS_Y]; } /* read registers 0x21~0x29 */ err = MC3XXX_i2c_read_block(client, 0x21, buf, 3); if (err) { ACC_PR_ERR("error: %d\n", err); return err; } err = MC3XXX_i2c_read_block(client, 0x24, &buf[3], 3); if (err) { ACC_PR_ERR("error: %d\n", err); return err; } err = MC3XXX_i2c_read_block(client, 0x27, &buf[6], 3); if (err) { ACC_PR_ERR("error: %d\n", err); return err; } if (IS_MCFM12() || IS_MCFM3X()) { bMsbFilter = 0x7F; wSignBitMask = 0x4000; wSignPaddingBits = 0x8000; dwRangePosLimit = 0x3FFF; dwRangeNegLimit = -0x4000; } /* get x,y,z offset */ tmp = ((buf[1] & bMsbFilter) << 8) + buf[0]; if (tmp & wSignBitMask) tmp |= wSignPaddingBits; x_off = tmp; tmp = ((buf[3] & bMsbFilter) << 8) + buf[2]; if (tmp & wSignBitMask) tmp |= wSignPaddingBits; y_off = tmp; tmp = ((buf[5] & bMsbFilter) << 8) + buf[4]; if (tmp & wSignBitMask) tmp |= wSignPaddingBits; z_off = tmp; /* get x,y,z gain */ x_gain = ((buf[1] >> 7) << 8) + buf[6]; y_gain = ((buf[3] >> 7) << 8) + buf[7]; z_gain = ((buf[5] >> 7) << 8) + buf[8]; /* prepare new offset */ x_off = x_off + 16 * cali[MC3XXX_AXIS_X] * 256 * 128 / 3 / gsensor_gain.x / (40 + x_gain); y_off = y_off + 16 * cali[MC3XXX_AXIS_Y] * 256 * 128 / 3 / gsensor_gain.y / (40 + y_gain); z_off = z_off + 16 * cali[MC3XXX_AXIS_Z] * 256 * 128 / 3 / gsensor_gain.z / (40 + z_gain); /* add for over range */ if (x_off > dwRangePosLimit) x_off = dwRangePosLimit; else if (x_off < dwRangeNegLimit) x_off = dwRangeNegLimit; if (y_off > dwRangePosLimit) y_off = dwRangePosLimit; else if (y_off < dwRangeNegLimit) y_off = dwRangeNegLimit; if (z_off > dwRangePosLimit) z_off = dwRangePosLimit; else if (z_off < dwRangeNegLimit) z_off = dwRangeNegLimit; /* storege the cerrunt offset data with DOT format */ offset_data[0] = x_off; offset_data[1] = y_off; offset_data[2] = z_off; /* storege the cerrunt Gain data with GOT format */ gain_data[0] = 256*8*128/3/(40+x_gain); gain_data[1] = 256*8*128/3/(40+y_gain); gain_data[2] = 256*8*128/3/(40+z_gain); buf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x07, buf, 1); buf[0] = x_off & 0xff; buf[1] = ((x_off >> 8) & bMsbFilter) | (x_gain & 0x0100 ? 0x80 : 0); buf[2] = y_off & 0xff; buf[3] = ((y_off >> 8) & bMsbFilter) | (y_gain & 0x0100 ? 0x80 : 0); buf[4] = z_off & 0xff; buf[5] = ((z_off >> 8) & bMsbFilter) | (z_gain & 0x0100 ? 0x80 : 0); MC3XXX_i2c_write_block(client, 0x21, buf, 6); buf[0] = 0x41; MC3XXX_i2c_write_block(client, 0x07, buf, 1); mdelay(50); return err; } /***************************************** *** MC3XXX_SetPowerMode *****************************************/ static int MC3XXX_SetPowerMode(struct i2c_client *client, bool enable) { u8 databuf[2] = {0}; int res = 0; u8 addr = MC3XXX_REG_MODE_FEATURE; if (enable == mc3xxx_sensor_power) ACC_LOG("Sensor power status should not be set again!!!\n"); if (MC3XXX_i2c_read_block(client, addr, databuf, 1)) { ACC_PR_ERR("read power ctl register err!\n"); return MC3XXX_RETCODE_ERROR_I2C; } if (enable) { databuf[0] = 0x41; res = MC3XXX_i2c_write_block(client, MC3XXX_REG_MODE_FEATURE, databuf, 1); #ifdef _MC3XXX_SUPPORT_DOT_CALIBRATION_ mcube_load_cali(client); #endif } else { databuf[0] = 0x43; res = MC3XXX_i2c_write_block(client, MC3XXX_REG_MODE_FEATURE, databuf, 1); } if (res < 0) { ACC_LOG("fwq set power mode failed!\n"); return MC3XXX_RETCODE_ERROR_I2C; } mc3xxx_sensor_power = enable; return MC3XXX_RETCODE_SUCCESS; } /***************************************** *** MC3XXX_SetResolution *****************************************/ static void MC3XXX_SetResolution(void) { switch (s_bPCODE) { case MC3XXX_PCODE_3230: case MC3XXX_PCODE_3430: case MC3XXX_PCODE_3430N: case MC3XXX_PCODE_3530: case MC3XXX_PCODE_3236: s_bResolution = MC3XXX_RESOLUTION_LOW; break; case MC3XXX_PCODE_3210: case MC3XXX_PCODE_3250: case MC3XXX_PCODE_3410: case MC3XXX_PCODE_3410N: case MC3XXX_PCODE_3510: case MC3XXX_PCODE_3216: s_bResolution = MC3XXX_RESOLUTION_HIGH; break; case MC3XXX_PCODE_RESERVE_10: ACC_PR_ERR("RESERVED ONLINE!\n"); /* TODO: should have a default configuration... */ break; case MC3XXX_PCODE_RESERVE_1: case MC3XXX_PCODE_RESERVE_3: case MC3XXX_PCODE_RESERVE_4: case MC3XXX_PCODE_RESERVE_5: case MC3XXX_PCODE_RESERVE_6: case MC3XXX_PCODE_RESERVE_8: case MC3XXX_PCODE_RESERVE_9: ACC_PR_ERR("RESERVED ONLINE!\n"); s_bResolution = MC3XXX_RESOLUTION_LOW; break; case MC3XXX_PCODE_RESERVE_2: case MC3XXX_PCODE_RESERVE_7: ACC_PR_ERR("RESERVED ONLINE!\n"); s_bResolution = MC3XXX_RESOLUTION_HIGH; break; default: ACC_PR_ERR("ERR: no resolution assigned!\n"); } } /***************************************** *** MC3XXX_SetSampleRate *****************************************/ static void MC3XXX_SetSampleRate(struct i2c_client *pt_i2c_client) { unsigned char _baDataBuf[2] = { 0 }; _baDataBuf[0] = MC3XXX_REG_SAMPLE_RATE; _baDataBuf[1] = 0x00; if (IS_MCFM12() || IS_MCFM3X()) { unsigned char _baData2Buf[2] = { 0 }; _baData2Buf[0] = 0x2A; MC3XXX_i2c_read_block(pt_i2c_client, 0x2A, _baData2Buf, 1); _baData2Buf[0] = (_baData2Buf[0] & 0xC0); switch (_baData2Buf[0]) { case 0x00: _baDataBuf[0] = 0x00; break; case 0x40: _baDataBuf[0] = 0x08; break; case 0x80: _baDataBuf[0] = 0x09; break; case 0xC0: _baDataBuf[0] = 0x0A; break; default: ACC_PR_ERR( "[%s] no chance to get here... check code!\n", __func__); break; } } else _baDataBuf[0] = 0x00; MC3XXX_i2c_write_block(pt_i2c_client, MC3XXX_REG_SAMPLE_RATE, _baDataBuf, 1); } /***************************************** *** MC3XXX_ConfigRegRange *****************************************/ static void MC3XXX_ConfigRegRange(struct i2c_client *pt_i2c_client) { unsigned char _baDataBuf[2] = { 0 }; int res = 0; /* _baDataBuf[0] = 0x3F; */ /********************************************* * Modify low pass filter bandwidth to 512hz, * for solving sensor data don't change issue *********************************************/ _baDataBuf[0] = 0x0F; if (s_bResolution == MC3XXX_RESOLUTION_LOW) _baDataBuf[0] = 0x32; if (IS_MCFM12() || IS_MCFM3X()) { if (s_bResolution == MC3XXX_RESOLUTION_LOW) _baDataBuf[0] = 0x02; else _baDataBuf[0] = 0x25; } res = MC3XXX_i2c_write_block(pt_i2c_client, MC3XXX_REG_RANGE_CONTROL, _baDataBuf, 1); if (res < 0) ACC_PR_ERR("%s fail\n", __func__); } /***************************************** *** MC3XXX_SetGain *****************************************/ static void MC3XXX_SetGain(void) { gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 1024; if (s_bResolution == MC3XXX_RESOLUTION_LOW) { gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 86; if (IS_MCFM12() || IS_MCFM3X()) gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 64; } } /***************************************** *** MC3XXX_Init *****************************************/ static int MC3XXX_Init(struct i2c_client *client, int reset_cali) { unsigned char _baDataBuf[2] = { 0 }; #ifdef _MC3XXX_SUPPORT_POWER_SAVING_SHUTDOWN_POWER_ if (_mc3xxx_i2c_auto_probe(client) != MC3XXX_RETCODE_SUCCESS) return MC3XXX_RETCODE_ERROR_I2C; #endif _baDataBuf[0] = 0x43; MC3XXX_i2c_write_block(client, MC3XXX_REG_MODE_FEATURE, _baDataBuf, 1); MC3XXX_SetResolution(); MC3XXX_SetSampleRate(client); MC3XXX_ConfigRegRange(client); MC3XXX_SetGain(); _baDataBuf[0] = 0x00; MC3XXX_i2c_write_block(client, MC3XXX_REG_TAP_DETECTION_ENABLE, _baDataBuf, 1); _baDataBuf[0] = 0x00; MC3XXX_i2c_write_block(client, MC3XXX_REG_INTERRUPT_ENABLE, _baDataBuf, 1); _baDataBuf[0] = 0; MC3XXX_i2c_read_block(client, 0x2A, _baDataBuf, 1); s_bMPOL = (_baDataBuf[0] & 0x03); #ifdef _MC3XXX_SUPPORT_DOT_CALIBRATION_ MC3XXX_rbm(client, 0); #endif #ifdef _MC3XXX_SUPPORT_LPF_ { struct mc3xxx_i2c_data *_pt_i2c_data = i2c_get_clientdata(client); memset(&_pt_i2c_data->fir, 0x00, sizeof(_pt_i2c_data->fir)); } #endif #ifdef _MC3XXX_SUPPORT_LRF_ memset(&s_taLRF_CB, 0, sizeof(s_taLRF_CB)); #endif #ifdef _MC3XXX_SUPPORT_PERIODIC_DOC_ init_waitqueue_head(&wq_mc3xxx_open_status); #endif return MC3XXX_RETCODE_SUCCESS; } /***************************************** *** MC3XXX_ReadChipInfo *****************************************/ static int MC3XXX_ReadChipInfo(struct i2c_client *client, char *buf, int bufsize) { if ((buf == NULL) || (bufsize <= 30)) return -1; if (client == NULL) { *buf = 0; return -2; } sprintf(buf, "MC3XXX Chip"); return 0; } /***************************************** *** MC3XXX_ReadSensorData *****************************************/ static int MC3XXX_ReadSensorData(struct i2c_client *pt_i2c_client, char *pbBuf, int nBufSize) { int _naAccelData[MC3XXX_AXES_NUM] = { 0 }; struct mc3xxx_i2c_data *_pt_i2c_obj = ((struct mc3xxx_i2c_data *) i2c_get_clientdata(pt_i2c_client)); if ((pt_i2c_client == NULL) || (pbBuf == NULL)) { ACC_PR_ERR("ERR: Null Pointer\n"); return MC3XXX_RETCODE_ERROR_NULL_POINTER; } if (false == mc3xxx_sensor_power) { if (MC3XXX_SetPowerMode(pt_i2c_client, true) != MC3XXX_RETCODE_SUCCESS) ACC_PR_ERR("ERR: fail to set power mode!\n"); } #ifdef _MC3XXX_SUPPORT_DOT_CALIBRATION_ mcube_load_cali(pt_i2c_client); if ((s_nIsRBM_Enabled) && (LPF_FirstRun == 1)) { int _nLoopIndex = 0; LPF_FirstRun = 0; for (_nLoopIndex = 0; _nLoopIndex < (LPF_SamplingRate + LPF_CutoffFrequency); _nLoopIndex++) MC3XXX_ReadData(pt_i2c_client, _pt_i2c_obj->data); } #endif if (MC3XXX_ReadData(pt_i2c_client, _pt_i2c_obj->data) != MC3XXX_RETCODE_SUCCESS) { ACC_PR_ERR("ERR: fail to read data!\n"); return MC3XXX_RETCODE_ERROR_I2C; } /* output format: mg */ _naAccelData[(_pt_i2c_obj->cvt.map[MC3XXX_AXIS_X])] = (_pt_i2c_obj->cvt.sign[MC3XXX_AXIS_X] * _pt_i2c_obj->data[MC3XXX_AXIS_X]); _naAccelData[(_pt_i2c_obj->cvt.map[MC3XXX_AXIS_Y])] = (_pt_i2c_obj->cvt.sign[MC3XXX_AXIS_Y] * _pt_i2c_obj->data[MC3XXX_AXIS_Y]); _naAccelData[(_pt_i2c_obj->cvt.map[MC3XXX_AXIS_Z])] = (_pt_i2c_obj->cvt.sign[MC3XXX_AXIS_Z] * _pt_i2c_obj->data[MC3XXX_AXIS_Z]); _naAccelData[MC3XXX_AXIS_X] = (_naAccelData[MC3XXX_AXIS_X] * GRAVITY_EARTH_1000 / gsensor_gain.x); _naAccelData[MC3XXX_AXIS_Y] = (_naAccelData[MC3XXX_AXIS_Y] * GRAVITY_EARTH_1000 / gsensor_gain.y); _naAccelData[MC3XXX_AXIS_Z] = (_naAccelData[MC3XXX_AXIS_Z] * GRAVITY_EARTH_1000 / gsensor_gain.z); sprintf(pbBuf, "%04x %04x %04x", _naAccelData[MC3XXX_AXIS_X], _naAccelData[MC3XXX_AXIS_Y], _naAccelData[MC3XXX_AXIS_Z]); return MC3XXX_RETCODE_SUCCESS; } /***************************************** *** _MC3XXX_ReadAverageData *****************************************/ #ifdef _MC3XXX_SUPPORT_APPLY_AVERAGE_AGORITHM_ static int _MC3XXX_ReadAverageData(struct i2c_client *client, char *buf) { struct mc3xxx_i2c_data *obj = (struct mc3xxx_i2c_data *)i2c_get_clientdata(client); int acc[MC3XXX_AXES_NUM] = {0}; s16 sensor_data[3] = {0}; s16 sensor_data_max[3] = {0}; s16 sensor_data_mini[3] = {0}; s32 sensor_data_sum[3] = {0}; int i = 0, j = 0; MC3XXX_ReadData(client, sensor_data); sensor_data_max[MC3XXX_AXIS_X] = sensor_data[MC3XXX_AXIS_X]; sensor_data_max[MC3XXX_AXIS_Y] = sensor_data[MC3XXX_AXIS_Y]; sensor_data_max[MC3XXX_AXIS_Z] = sensor_data[MC3XXX_AXIS_Z]; sensor_data_mini[MC3XXX_AXIS_X] = sensor_data[MC3XXX_AXIS_X]; sensor_data_mini[MC3XXX_AXIS_Y] = sensor_data[MC3XXX_AXIS_Y]; sensor_data_mini[MC3XXX_AXIS_Z] = sensor_data[MC3XXX_AXIS_Z]; sensor_data_sum[MC3XXX_AXIS_X] += sensor_data[MC3XXX_AXIS_X]; sensor_data_sum[MC3XXX_AXIS_Y] += sensor_data[MC3XXX_AXIS_Y]; sensor_data_sum[MC3XXX_AXIS_Z] += sensor_data[MC3XXX_AXIS_Z]; for (i = 0; i < 11 ; i++) { MC3XXX_ReadData(client, sensor_data); sensor_data_sum[MC3XXX_AXIS_X] += sensor_data[MC3XXX_AXIS_X]; sensor_data_sum[MC3XXX_AXIS_Y] += sensor_data[MC3XXX_AXIS_Y]; sensor_data_sum[MC3XXX_AXIS_Z] += sensor_data[MC3XXX_AXIS_Z]; for (j = 0; j < 3 ; j++) { if (sensor_data[j] > sensor_data_max[j]) sensor_data_max[j] = sensor_data[j]; if (sensor_data[j] < sensor_data_mini[j]) sensor_data_mini[j] = sensor_data[j]; } } sensor_data[MC3XXX_AXIS_X] = (s16)((sensor_data_sum[MC3XXX_AXIS_X] - sensor_data_max[MC3XXX_AXIS_X] - sensor_data_mini[MC3XXX_AXIS_X]) / 10); sensor_data[MC3XXX_AXIS_Y] = (s16)((sensor_data_sum[MC3XXX_AXIS_Y] - sensor_data_max[MC3XXX_AXIS_Y] - sensor_data_mini[MC3XXX_AXIS_Y]) / 10); sensor_data[MC3XXX_AXIS_Z] = (s16)((sensor_data_sum[MC3XXX_AXIS_Z] - sensor_data_max[MC3XXX_AXIS_Z] - sensor_data_mini[MC3XXX_AXIS_Z]) / 10); acc[(obj->cvt.map[MC3XXX_AXIS_X])] = obj->cvt.sign[MC3XXX_AXIS_X] * sensor_data[MC3XXX_AXIS_X]; acc[(obj->cvt.map[MC3XXX_AXIS_Y])] = obj->cvt.sign[MC3XXX_AXIS_Y] * sensor_data[MC3XXX_AXIS_Y]; acc[(obj->cvt.map[MC3XXX_AXIS_Z])] = obj->cvt.sign[MC3XXX_AXIS_Z] * sensor_data[MC3XXX_AXIS_Z]; acc[MC3XXX_AXIS_X] = (acc[MC3XXX_AXIS_X] * GRAVITY_EARTH_1000 / gsensor_gain.x); acc[MC3XXX_AXIS_Y] = (acc[MC3XXX_AXIS_Y] * GRAVITY_EARTH_1000 / gsensor_gain.y); acc[MC3XXX_AXIS_Z] = (acc[MC3XXX_AXIS_Z] * GRAVITY_EARTH_1000 / gsensor_gain.z); sprintf(buf, "%04x %04x %04x", acc[MC3XXX_AXIS_X], acc[MC3XXX_AXIS_Y], acc[MC3XXX_AXIS_Z]); return 0; } #endif /* END OF #ifdef _MC3XXX_SUPPORT_APPLY_AVERAGE_AGORITHM_ */ /***************************************** *** MC3XXX_ReadRawData *****************************************/ static int MC3XXX_ReadRawData(struct i2c_client *client, char *buf) { int res = 0; if (!buf || !client) return -EINVAL; if (mc3xxx_sensor_power == false) { res = MC3XXX_SetPowerMode(client, true); if (res) ACC_PR_ERR("Power on mc3xxx error %d!\n", res); } #ifdef _MC3XXX_SUPPORT_APPLY_AVERAGE_AGORITHM_ return _MC3XXX_ReadAverageData(client, buf); #else { s16 sensor_data[3] = {0}; res = MC3XXX_ReadData(client, sensor_data); if (res) { ACC_PR_ERR("I2C error: ret value=%d", res); return -EIO; } sprintf(buf, "%04x %04x %04x", sensor_data[MC3XXX_AXIS_X], sensor_data[MC3XXX_AXIS_Y], sensor_data[MC3XXX_AXIS_Z]); } #endif return 0; } #ifdef _MC3XXX_SUPPORT_DOT_CALIBRATION_ /***************************************** *** MC3XXX_ReadRBMData *****************************************/ static int MC3XXX_ReadRBMData(struct i2c_client *client, char *buf) { int res = 0; int data[3] = { 0 }; if (!buf || !client) return -EINVAL; if (mc3xxx_sensor_power == false) { res = MC3XXX_SetPowerMode(client, true); if (res) ACC_PR_ERR("Power on mc3xxx error %d!\n", res); } res = MC3XXX_ReadData_RBM(client, data); if (res) { ACC_PR_ERR("I2C error: ret value=%d", res); return -EIO; } sprintf(buf, "%04x %04x %04x", data[MC3XXX_AXIS_X], data[MC3XXX_AXIS_Y], data[MC3XXX_AXIS_Z]); return res; } #endif /* _MC3XXX_SUPPORT_DOT_CALIBRATION_ */ /***************************************** *** MC3XXX_JudgeTestResult *****************************************/ static int MC3XXX_JudgeTestResult(struct i2c_client *client) { int res = 0; int self_result = 0; s16 acc[MC3XXX_AXES_NUM] = { 0 }; res = MC3XXX_ReadData(client, acc); if (res) { ACC_PR_ERR("I2C error: ret value=%d", res); return -EIO; } acc[MC3XXX_AXIS_X] = acc[MC3XXX_AXIS_X] * 1000 / gsensor_gain.x; acc[MC3XXX_AXIS_Y] = acc[MC3XXX_AXIS_Y] * 1000 / gsensor_gain.y; acc[MC3XXX_AXIS_Z] = acc[MC3XXX_AXIS_Z] * 1000 / gsensor_gain.z; self_result = ((acc[MC3XXX_AXIS_X] * acc[MC3XXX_AXIS_X]) + (acc[MC3XXX_AXIS_Y] * acc[MC3XXX_AXIS_Y]) + (acc[MC3XXX_AXIS_Z] * acc[MC3XXX_AXIS_Z])); if ((self_result > 475923) && (self_result < 2185360)) { ACC_PR_ERR("%s successful\n", __func__); return MC3XXX_RETCODE_SUCCESS; } ACC_PR_ERR("%s failt\n", __func__); return -EINVAL; } /***************************************** *** MC3XXX_SelfCheck *****************************************/ static void MC3XXX_SelfCheck(struct i2c_client *client, u8 *pUserBuf) { u8 _bRData1 = 0; u8 _bRData2 = 0; u8 _bRData3 = 0; u8 _baDataBuf[2] = { 0 }; MC3XXX_i2c_read_block(client, 0x20, &_bRData1, 1); MC3XXX_i2c_read_block(client, 0x3B, &_bRData2, 1); _baDataBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x07, _baDataBuf, 1); mdelay(10); for ( ; ; ) { _baDataBuf[0] = 0x6D; MC3XXX_i2c_write_block(client, 0x1B, _baDataBuf, 1); _baDataBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x1B, _baDataBuf, 1); _bRData3 = 0x00; MC3XXX_i2c_read_block(client, 0x04, &_bRData3, 1); if (_bRData3 & 0x40) break; } _baDataBuf[0] = (_bRData2 & 0xFE); MC3XXX_i2c_write_block(client, 0x3B, _baDataBuf, 1); _baDataBuf[0] = 0x03; MC3XXX_i2c_write_block(client, 0x20, _baDataBuf, 1); _baDataBuf[0] = 0x40; MC3XXX_i2c_write_block(client, 0x14, _baDataBuf, 1); mdelay(10); _baDataBuf[0] = pUserBuf[0]; MC3XXX_i2c_write_block(client, 0x00, _baDataBuf, 1); _baDataBuf[0] = 0x41; MC3XXX_i2c_write_block(client, 0x07, _baDataBuf, 1); mdelay(10); _baDataBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x07, _baDataBuf, 1); mdelay(10); MC3XXX_Read_Reg_Map(client, pUserBuf); mdelay(10); _baDataBuf[0] = 0x00; MC3XXX_i2c_write_block(client, 0x14, _baDataBuf, 1); _baDataBuf[0] = _bRData1; MC3XXX_i2c_write_block(client, 0x20, _baDataBuf, 1); _baDataBuf[0] = _bRData2; MC3XXX_i2c_write_block(client, 0x3B, _baDataBuf, 1); mdelay(10); for ( ; ; ) { _baDataBuf[0] = 0x6D; MC3XXX_i2c_write_block(client, 0x1B, _baDataBuf, 1); _baDataBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x1B, _baDataBuf, 1); _bRData3 = 0xFF; MC3XXX_i2c_read_block(client, 0x04, &_bRData3, 1); if (!(_bRData3 & 0x40)) break; } mdelay(10); } /***************************************** *** MC3XXX_GetOpenStatus *****************************************/ #ifdef _MC3XXX_SUPPORT_PERIODIC_DOC_ static int MC3XXX_GetOpenStatus(void) { wait_event_interruptible(wq_mc3xxx_open_status, (atomic_read(&s_t_mc3xxx_open_status) != 0)); return atomic_read(&s_t_mc3xxx_open_status); } #endif /***************************************** *** show_chipinfo_value *****************************************/ static ssize_t show_chipinfo_value(struct device_driver *ddri, char *buf) { struct i2c_client *client = mc3xxx_i2c_client; char strbuf[MC3XXX_BUF_SIZE] = {0}; if (client == NULL) { ACC_PR_ERR("i2c client is null!!\n"); return 0; } MC3XXX_ReadChipInfo(client, strbuf, MC3XXX_BUF_SIZE); return snprintf(buf, PAGE_SIZE, "%s\n", strbuf); } /***************************************** *** show_sensordata_value *****************************************/ static ssize_t show_sensordata_value(struct device_driver *ddri, char *buf) { struct i2c_client *client = mc3xxx_i2c_client; char strbuf[MC3XXX_BUF_SIZE] = { 0 }; if (client == NULL) { ACC_PR_ERR("i2c client is null!!\n"); return 0; } mc3xxx_mutex_lock(); MC3XXX_ReadSensorData(client, strbuf, MC3XXX_BUF_SIZE); mc3xxx_mutex_unlock(); return snprintf(buf, PAGE_SIZE, "%s\n", strbuf); } /***************************************** *** show_cali_value *****************************************/ static ssize_t show_cali_value(struct device_driver *ddri, char *buf) { struct i2c_client *client = mc3xxx_i2c_client; struct mc3xxx_i2c_data *obj; int err = 0; int len = 0; int mul = 0; int tmp[MC3XXX_AXES_NUM] = { 0 }; if (client == NULL) { ACC_PR_ERR("i2c client is null!!\n"); return 0; } obj = (struct mc3xxx_i2c_data *) i2c_get_clientdata(client); err = MC3XXX_ReadOffset(client, obj->offset); if (err) return -EINVAL; err = MC3XXX_ReadCalibration(client, tmp); if (err) return -EINVAL; mul = gsensor_gain.x / mc3xxx_offset_resolution.sensitivity; len += snprintf(buf+len, PAGE_SIZE-len, "[HW] (%+3d, %+3d, %+3d) : (0x%02X, 0x%02X, 0x%02X)\n", obj->offset[MC3XXX_AXIS_X], obj->offset[MC3XXX_AXIS_Y], obj->offset[MC3XXX_AXIS_Z], obj->offset[MC3XXX_AXIS_X], obj->offset[MC3XXX_AXIS_Y], obj->offset[MC3XXX_AXIS_Z]); len += snprintf(buf+len, PAGE_SIZE-len, "[SW][%d] (%+3d, %+3d, %+3d)\n", 1, obj->cali_sw[MC3XXX_AXIS_X], obj->cali_sw[MC3XXX_AXIS_Y], obj->cali_sw[MC3XXX_AXIS_Z]); len += snprintf(buf+len, PAGE_SIZE-len, "[ALL] (%+3d, %+3d, %+3d) : (%+3d, %+3d, %+3d)\n", obj->offset[MC3XXX_AXIS_X]*mul + obj->cali_sw[MC3XXX_AXIS_X], obj->offset[MC3XXX_AXIS_Y]*mul + obj->cali_sw[MC3XXX_AXIS_Y], obj->offset[MC3XXX_AXIS_Z]*mul + obj->cali_sw[MC3XXX_AXIS_Z], tmp[MC3XXX_AXIS_X], tmp[MC3XXX_AXIS_Y], tmp[MC3XXX_AXIS_Z]); return len; } /***************************************** *** store_cali_value *****************************************/ static ssize_t store_cali_value(struct device_driver *ddri, const char *buf, size_t count) { struct i2c_client *client = mc3xxx_i2c_client; int err = 0; int x = 0; int y = 0; int z = 0; int dat[MC3XXX_AXES_NUM] = {0}; if (!strncmp(buf, "rst", 3)) { mc3xxx_mutex_lock(); err = MC3XXX_ResetCalibration(client); mc3xxx_mutex_unlock(); if (err) ACC_PR_ERR("reset offset err = %d\n", err); } else if (sscanf(buf, "0x%02X 0x%02X 0x%02X", &x, &y, &z) == 3) { dat[MC3XXX_AXIS_X] = x; dat[MC3XXX_AXIS_Y] = y; dat[MC3XXX_AXIS_Z] = z; mc3xxx_mutex_lock(); err = MC3XXX_WriteCalibration(client, dat); mc3xxx_mutex_unlock(); if (err) ACC_PR_ERR("write calibration err = %d\n", err); } else ACC_PR_ERR("invalid format\n"); return count; } /***************************************** *** show_selftest_value *****************************************/ static ssize_t show_selftest_value(struct device_driver *ddri, char *buf) { struct i2c_client *client = mc3xxx_i2c_client; if (client == NULL) { ACC_PR_ERR("i2c client is null!!\n"); return 0; } return snprintf(buf, 8, "%s\n", selftestRes); } /***************************************** *** store_selftest_value *****************************************/ static ssize_t store_selftest_value(struct device_driver *ddri, const char *buf, size_t count) { /*write anything to this register will trigger the process*/ struct i2c_client *client = mc3xxx_i2c_client; int num = 0; int ret = 0; ret = kstrtoint(buf, 10, &num); if (ret != 0) { ACC_PR_ERR("parse number fail\n"); return count; } else if (num == 0) { ACC_PR_ERR("invalid data count\n"); return count; } mc3xxx_mutex_lock(); MC3XXX_SetPowerMode(client, true); mc3xxx_mutex_unlock(); if (!MC3XXX_JudgeTestResult(client)) { strcpy(selftestRes, "y"); } else { ACC_LOG("SELFTEST : FAIL\n"); strcpy(selftestRes, "n"); } return count; } /***************************************** *** show_firlen_value *****************************************/ static ssize_t show_firlen_value(struct device_driver *ddri, char *buf) { #ifdef _MC3XXX_SUPPORT_LPF_ struct i2c_client *client = mc3xxx_i2c_client; struct mc3xxx_i2c_data *obj = i2c_get_clientdata(client); return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&obj->firlen)); #else return snprintf(buf, PAGE_SIZE, "not support\n"); #endif } /***************************************** *** store_firlen_value *****************************************/ static ssize_t store_firlen_value(struct device_driver *ddri, const char *buf, size_t count) { #ifdef _MC3XXX_SUPPORT_LPF_ struct i2c_client *client = mc3xxx_i2c_client; struct mc3xxx_i2c_data *obj = i2c_get_clientdata(client); int firlen = 0; int ret = 0; ret = kstrtoint(buf, 10, &firlen); if (ret != 0) ACC_PR_ERR("invallid format\n"); else if (firlen > C_MAX_FIR_LENGTH) ACC_PR_ERR("exceeds maximum filter length\n"); else { atomic_set(&obj->firlen, firlen); if (firlen == 0) atomic_set(&obj->fir_en, 0); else { memset(&obj->fir, 0x00, sizeof(obj->fir)); atomic_set(&obj->fir_en, 1); } } #endif return count; } /***************************************** *** show_trace_value *****************************************/ static ssize_t show_trace_value(struct device_driver *ddri, char *buf) { ssize_t res = 0; struct mc3xxx_i2c_data *obj = mc3xxx_obj_i2c_data; if (obj == NULL) { ACC_PR_ERR("i2c_data obj is null!!\n"); return 0; } res = snprintf(buf, PAGE_SIZE, "0x%04X\n", atomic_read(&obj->trace)); return res; } /***************************************** *** store_trace_value *****************************************/ static ssize_t store_trace_value(struct device_driver *ddri, const char *buf, size_t count) { struct mc3xxx_i2c_data *obj = mc3xxx_obj_i2c_data; int trace = 0; if (obj == NULL) { ACC_PR_ERR("i2c_data obj is null!!\n"); return 0; } if (sscanf(buf, "0x%x", &trace) == 1) atomic_set(&obj->trace, trace); else ACC_PR_ERR("invalid content: '%s', length = %zu\n", buf, count); return count; } /***************************************** *** show_status_value *****************************************/ static ssize_t show_status_value(struct device_driver *ddri, char *buf) { ssize_t len = 0; struct mc3xxx_i2c_data *obj = mc3xxx_obj_i2c_data; if (obj == NULL) { ACC_PR_ERR("i2c_data obj is null!!\n"); return 0; } if (obj->hw) len += snprintf(buf+len, PAGE_SIZE-len, "CUST: %d %d (%d %d)\n", obj->hw->i2c_num, obj->hw->direction, obj->hw->power_id, obj->hw->power_vol); else len += snprintf(buf+len, PAGE_SIZE-len, "CUST: NULL\n"); return len; } /***************************************** *** show_power_status *****************************************/ static ssize_t show_power_status(struct device_driver *ddri, char *buf) { ssize_t res = 0; u8 uData = 0; struct mc3xxx_i2c_data *obj = mc3xxx_obj_i2c_data; if (obj == NULL) { ACC_PR_ERR("i2c_data obj is null!!\n"); return 0; } MC3XXX_i2c_read_block(obj->client, MC3XXX_REG_MODE_FEATURE, &uData, 1); res = snprintf(buf, PAGE_SIZE, "0x%04X\n", uData); return res; } /***************************************** *** show_version_value *****************************************/ static ssize_t show_version_value(struct device_driver *ddri, char *buf) { if (1 == VIRTUAL_Z) return snprintf(buf, PAGE_SIZE, "%s\n", MC3XXX_DEV_DRIVER_VERSION_VIRTUAL_Z); else return snprintf(buf, PAGE_SIZE, "%s\n", MC3XXX_DEV_DRIVER_VERSION); } /***************************************** *** show_chip_id *****************************************/ static ssize_t show_chip_id(struct device_driver *ddri, char *buf) { struct mc3xxx_i2c_data *_pt_i2c_data = mc3xxx_obj_i2c_data; return MC3XXX_Read_Chip_ID(_pt_i2c_data->client, buf); } /***************************************** *** show_virtual_z *****************************************/ static ssize_t show_virtual_z(struct device_driver *ddri, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", VIRTUAL_Z == 1 ? "Virtual Z Support" : "No Virtual Z Support"); } /***************************************** *** show_regiter_map *****************************************/ static ssize_t show_regiter_map(struct device_driver *ddri, char *buf) { u8 _bIndex = 0; u8 _baRegMap[64] = { 0 }; ssize_t _tLength = 0; struct i2c_client *client = mc3xxx_i2c_client; if ((buf[0] == 0xA5) && (buf[1] == 0x7B) && (buf[2] == 0x40)) { mc3xxx_mutex_lock(); MC3XXX_Read_Reg_Map(client, buf); mc3xxx_mutex_unlock(); buf[0x21] = s_baOTP_OffsetData[0]; buf[0x22] = s_baOTP_OffsetData[1]; buf[0x23] = s_baOTP_OffsetData[2]; buf[0x24] = s_baOTP_OffsetData[3]; buf[0x25] = s_baOTP_OffsetData[4]; buf[0x26] = s_baOTP_OffsetData[5]; _tLength = 64; } else { mc3xxx_mutex_lock(); MC3XXX_Read_Reg_Map(client, _baRegMap); mc3xxx_mutex_unlock(); for (_bIndex = 0; _bIndex < 64; _bIndex++) _tLength += snprintf((buf + _tLength), (PAGE_SIZE - _tLength), "Reg[0x%02X]: 0x%02X\n", _bIndex, _baRegMap[_bIndex]); } return _tLength; } /***************************************** *** store_regiter_map *****************************************/ static ssize_t store_regiter_map(struct device_driver *ddri, const char *buf, size_t count) { return count; } /***************************************** *** show_chip_orientation *****************************************/ static ssize_t show_chip_orientation(struct device_driver *ptDevDrv, char *pbBuf) { ssize_t _tLength = 0; struct acc_hw *_ptAccelHw = get_cust_acc(); _tLength = snprintf(pbBuf, PAGE_SIZE, "default direction = %d\n", _ptAccelHw->direction); return _tLength; } /***************************************** *** store_chip_orientation *****************************************/ static ssize_t store_chip_orientation(struct device_driver *ptDevDrv, const char *pbBuf, size_t tCount) { int _nDirection = 0; int ret = 0; struct mc3xxx_i2c_data *_pt_i2c_obj = mc3xxx_obj_i2c_data; if (_pt_i2c_obj == NULL) return 0; ret = kstrtoint(pbBuf, 10, &_nDirection); if (ret == 0) { if (hwmsen_get_convert(_nDirection, &_pt_i2c_obj->cvt)) ACC_PR_ERR("ERR: fail to set direction\n"); } return tCount; } /***************************************** *** show_accuracy_status *****************************************/ static ssize_t show_accuracy_status(struct device_driver *ddri, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", s_bAccuracyStatus); } /***************************************** *** store_accuracy_status *****************************************/ static ssize_t store_accuracy_status(struct device_driver *ddri, const char *buf, size_t count) { int _nAccuracyStatus = 0; int ret = 0; ret = kstrtoint(buf, 10, &_nAccuracyStatus); if (ret != 0) { ACC_PR_ERR("incorrect argument\n"); return count; } if (_nAccuracyStatus > SENSOR_STATUS_ACCURACY_HIGH) { ACC_PR_ERR("illegal accuracy status\n"); return count; } s_bAccuracyStatus = ((int8_t) _nAccuracyStatus); return count; } /***************************************** *** show_selfcheck_value *****************************************/ static ssize_t show_selfcheck_value(struct device_driver *ptDevDriver, char *pbBuf) { struct i2c_client *_pt_i2c_client = mc3xxx_i2c_client; /* ACC_LOG("[%s] 0x%02X\n", __FUNCTION__, pbBuf[0]); */ mc3xxx_mutex_lock(); MC3XXX_SelfCheck(_pt_i2c_client, pbBuf); MC3XXX_Init(_pt_i2c_client, 0); mc3xxx_mutex_unlock(); return 64; } /***************************************** *** store_selfcheck_value *****************************************/ static ssize_t store_selfcheck_value(struct device_driver *ddri, const char *buf, size_t count) { /* reserved */ /* ACC_LOG("[%s] buf[0]: 0x%02X\n", __FUNCTION__, buf[0]); */ return count; } /***************************************** *** show_chip_validate_value *****************************************/ static ssize_t show_chip_validate_value(struct device_driver *ptDevDriver, char *pbBuf) { unsigned char _bChipValidation = 0; _bChipValidation = MC3XXX_ValidateSensorIC(&s_bPCODE, &s_bHWID); return snprintf(pbBuf, PAGE_SIZE, "%d\n", _bChipValidation); } /***************************************** *** show_pdoc_enable_value *****************************************/ static ssize_t show_pdoc_enable_value(struct device_driver *ptDevDriver, char *pbBuf) { #ifdef _MC3XXX_SUPPORT_PERIODIC_DOC_ return snprintf(pbBuf, PAGE_SIZE, "%d\n", s_bIsPDOC_Enabled); #else unsigned char _bIsPDOC_Enabled = false; return snprintf(pbBuf, PAGE_SIZE, "%d\n", _bIsPDOC_Enabled); #endif } /***************************************** *** DRIVER ATTRIBUTE LIST TABLE *****************************************/ static DRIVER_ATTR(chipinfo, 0444, show_chipinfo_value, NULL); static DRIVER_ATTR(sensordata, 0444, show_sensordata_value, NULL); static DRIVER_ATTR(cali, 0644, show_cali_value, store_cali_value); static DRIVER_ATTR(selftest, 0644, show_selftest_value, store_selftest_value); static DRIVER_ATTR(firlen, 0644, show_firlen_value, store_firlen_value); static DRIVER_ATTR(trace, 0644, show_trace_value, store_trace_value); static DRIVER_ATTR(status, 0444, show_status_value, NULL); static DRIVER_ATTR(power, 0444, show_power_status, NULL); static DRIVER_ATTR(version, 0444, show_version_value, NULL); static DRIVER_ATTR(chipid, 0444, show_chip_id, NULL); static DRIVER_ATTR(virtualz, 0444, show_virtual_z, NULL); static DRIVER_ATTR(regmap, 0644, show_regiter_map, store_regiter_map); static DRIVER_ATTR(orientation, 0644, show_chip_orientation, store_chip_orientation); static DRIVER_ATTR(accuracy, 0644, show_accuracy_status, store_accuracy_status); static DRIVER_ATTR(selfcheck, 0644, show_selfcheck_value, store_selfcheck_value); static DRIVER_ATTR(validate, 0444, show_chip_validate_value, NULL); static DRIVER_ATTR(pdoc, 0444, show_pdoc_enable_value, NULL); static struct driver_attribute *mc3xxx_attr_list[] = { &driver_attr_chipinfo, &driver_attr_sensordata, &driver_attr_cali, &driver_attr_selftest, &driver_attr_firlen, &driver_attr_trace, &driver_attr_status, &driver_attr_power, &driver_attr_version, &driver_attr_chipid, &driver_attr_virtualz, &driver_attr_regmap, &driver_attr_orientation, &driver_attr_accuracy, &driver_attr_selfcheck, &driver_attr_validate, &driver_attr_pdoc, }; /***************************************** *** mc3xxx_create_attr *****************************************/ static int mc3xxx_create_attr(struct device_driver *driver) { int idx, err = 0; int num = (int)(ARRAY_SIZE(mc3xxx_attr_list)); if (driver == NULL) return -EINVAL; for (idx = 0; idx < num; idx++) { err = driver_create_file(driver, mc3xxx_attr_list[idx]); if (err) { ACC_PR_ERR("driver_create_file (%s) = %d\n", mc3xxx_attr_list[idx]->attr.name, err); break; } } return err; } /***************************************** *** mc3xxx_delete_attr *****************************************/ static int mc3xxx_delete_attr(struct device_driver *driver) { int idx, err = 0; int num = (int)(ARRAY_SIZE(mc3xxx_attr_list)); if (driver == NULL) return -EINVAL; for (idx = 0; idx < num; idx++) driver_remove_file(driver, mc3xxx_attr_list[idx]); return err; } /***************************************** *** MC3XXX_reset *****************************************/ static void MC3XXX_reset(struct i2c_client *client) { unsigned char _baBuf[2] = { 0 }; _baBuf[0] = 0x43; MC3XXX_i2c_write_block(client, MC3XXX_REG_MODE_FEATURE, _baBuf, 0x01); MC3XXX_i2c_read_block(client, 0x04, _baBuf, 0x01); if (0x00 == (_baBuf[0] & 0x40)) { _baBuf[0] = 0x6D; MC3XXX_i2c_write_block(client, 0x1B, _baBuf, 0x01); _baBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x1B, _baBuf, 0x01); } _baBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x07, _baBuf, 1); _baBuf[0] = 0x80; MC3XXX_i2c_write_block(client, 0x1C, _baBuf, 1); _baBuf[0] = 0x80; MC3XXX_i2c_write_block(client, 0x17, _baBuf, 1); mdelay(5); _baBuf[0] = 0x00; MC3XXX_i2c_write_block(client, 0x1C, _baBuf, 1); _baBuf[0] = 0x00; MC3XXX_i2c_write_block(client, 0x17, _baBuf, 1); mdelay(5); MC3XXX_i2c_read_block(client, 0x21, offset_buf, 6); MC3XXX_i2c_read_block(client, 0x04, _baBuf, 0x01); if (_baBuf[0] & 0x40) { _baBuf[0] = 0x6D; MC3XXX_i2c_write_block(client, 0x1B, _baBuf, 0x01); _baBuf[0] = 0x43; MC3XXX_i2c_write_block(client, 0x1B, _baBuf, 0x01); } _baBuf[0] = 0x41; MC3XXX_i2c_write_block(client, MC3XXX_REG_MODE_FEATURE, _baBuf, 0x01); } /***************************************** *** mc3xxx_suspend *****************************************/ static int mc3xxx_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct mc3xxx_i2c_data *obj = i2c_get_clientdata(client); int err = 0; if (obj == NULL) { ACC_PR_ERR("null pointer!!\n"); return -EINVAL; } atomic_set(&obj->suspend, 1); mc3xxx_mutex_lock(); err = MC3XXX_SetPowerMode(client, false); mc3xxx_mutex_unlock(); if (err) { ACC_PR_ERR("write power control fail!!\n"); return err; } MC3XXX_power(obj->hw, 0); return err; } /***************************************** *** mc3xxx_resume *****************************************/ static int mc3xxx_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct mc3xxx_i2c_data *obj = i2c_get_clientdata(client); int err; if (obj == NULL) { ACC_PR_ERR("null pointer!!\n"); return -EINVAL; } MC3XXX_power(obj->hw, 1); mc3xxx_mutex_lock(); err = MC3XXX_Init(client, 0); if (err) { mc3xxx_mutex_unlock(); ACC_PR_ERR("initialize client fail!!\n"); return err; } err = MC3XXX_SetPowerMode(client, true); mc3xxx_mutex_unlock(); if (err) { ACC_PR_ERR("write power control fail!!\n"); return err; } atomic_set(&obj->suspend, 0); return 0; } /***************************************** *** _mc3xxx_i2c_auto_probe *****************************************/ static int _mc3xxx_i2c_auto_probe(struct i2c_client *client) { #define _MC3XXX_I2C_PROBE_ADDR_COUNT_ \ (ARRAY_SIZE(mc3xxx_i2c_auto_probe_addr)) unsigned char _baData1Buf[2] = { 0 }; unsigned char _baData2Buf[2] = { 0 }; int _nCount = 0; int _naCheckCount[_MC3XXX_I2C_PROBE_ADDR_COUNT_] = { 0 }; memset(_naCheckCount, 0, sizeof(_naCheckCount)); _I2C_AUTO_PROBE_RECHECK_: s_bPCODE = 0x00; s_bPCODER = 0x00; s_bHWID = 0x00; for (_nCount = 0; _nCount < _MC3XXX_I2C_PROBE_ADDR_COUNT_; _nCount++) { client->addr = mc3xxx_i2c_auto_probe_addr[_nCount]; _baData1Buf[0] = 0; if (MC3XXX_i2c_read_block(client, 0x3B, _baData1Buf, 1) < 0) continue; _naCheckCount[_nCount]++; if (_baData1Buf[0] == 0x00) { if (_naCheckCount[_nCount] == 1) { MC3XXX_reset(client); mdelay(3); goto _I2C_AUTO_PROBE_RECHECK_; } else continue; } _baData2Buf[0] = 0; MC3XXX_i2c_read_block(client, 0x18, _baData2Buf, 1); s_bPCODER = _baData1Buf[0]; if (MC3XXX_ValidateSensorIC(&_baData1Buf[0], &_baData2Buf[0]) == MC3XXX_RETCODE_SUCCESS) { s_bPCODE = _baData1Buf[0]; s_bHWID = _baData2Buf[0]; MC3XXX_SaveDefaultOffset(client); return MC3XXX_RETCODE_SUCCESS; } } return MC3XXX_RETCODE_ERROR_I2C; #undef _MC3XXX_I2C_PROBE_ADDR_COUNT_ } /************************************************************** * if use this type of enable , * Gsensor should report inputEvent(x, y, z ,stats, div) to HAL **************************************************************/ static int mc3xxx_open_report_data(int open) { /* should queuq work to report event if is_report_input_direct=true */ return 0; } /************************************************************** * if use this type of enable , * Gsensor only enabled but not report inputEvent to HAL *************************************************************/ static int mc3xxx_enable_nodata(int en) { int res = 0; int retry = 0; bool power = false; if (en == 1) power = true; if (en == 0) power = false; for (retry = 0; retry < 3; retry++) { res = MC3XXX_SetPowerMode(mc3xxx_obj_i2c_data->client, power); if (res == 0) break; ACC_LOG("MC3XXX_SetPowerMode fail\n"); } if (res != 0) { ACC_LOG("MC3XXX_SetPowerMode fail!\n"); return -1; } return 0; } static int mc3xxx_set_delay(u64 ns) { int value = 0; value = (int)ns/1000/1000; return 0; } static int mc3xxx_get_data(int *x, int *y, int *z, int *status) { char buff[MC3XXX_BUF_SIZE]; int ret; MC3XXX_ReadSensorData(mc3xxx_obj_i2c_data->client, buff, MC3XXX_BUF_SIZE); ret = sscanf(buff, "%x %x %x", x, y, z); *status = SENSOR_STATUS_ACCURACY_MEDIUM; return 0; } static int mc3xxx_batch(int flag, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { int value = 0; /* * int err = 0; * int sample_delay = 0; */ value = (int)samplingPeriodNs/1000/1000; /*FIX ME */ /*NEED SUPPORT batch ?*/ /* * if (value <= 5) * sample_delay = MC3410_ACCEL_ODR_400HZ; * else if (value <= 10) * sample_delay = MC3410_ACCEL_ODR_200HZ; * else * sample_delay = MC3410_ACCEL_ODR_100HZ; * * err = MC3XXX_SetSampleRate(mc3xxx_obj_i2c_data->client); * * if (err < 0) { * ACC_PR_ERR("set delay parameter error!\n"); * return -1; * } * ACC_LOG("mc3xxx_batch acc set delay = (%d) ok.\n", value); */ return 0; } static int mc3xxx_flush(void) { return acc_flush_report(); } static int mc3xxx_factory_enable_sensor(bool enabledisable, int64_t sample_periods_ms) { int err; err = mc3xxx_enable_nodata(enabledisable == true ? 1 : 0); if (err) { ACC_PR_ERR("%s enable sensor failed!\n", __func__); return -1; } err = mc3xxx_batch(0, sample_periods_ms * 1000000, 0); if (err) { ACC_PR_ERR("%s enable set batch failed!\n", __func__); return -1; } return 0; } static int mc3xxx_factory_get_data(int32_t data[3], int *status) { return mc3xxx_get_data(&data[0], &data[1], &data[2], status); } static int mc3xxx_factory_get_raw_data(int32_t data[3]) { char strbuf[MC3XXX_BUF_SIZE] = { 0 }; MC3XXX_ReadRawData(mc3xxx_i2c_client, strbuf); return 0; } static int mc3xxx_factory_enable_calibration(void) { return 0; } static int mc3xxx_factory_clear_cali(void) { int err = 0; err = MC3XXX_ResetCalibration(mc3xxx_i2c_client); if (err) { ACC_PR_ERR("mc3xxx_ResetCalibration failed!\n"); return -1; } return 0; } static int mc3xxx_factory_set_cali(int32_t data[3]) { int err = 0; int cali[3] = { 0 }; /* obj */ mc3xxx_obj_i2c_data->cali_sw[MC3XXX_AXIS_X] += data[0]; mc3xxx_obj_i2c_data->cali_sw[MC3XXX_AXIS_Y] += data[1]; mc3xxx_obj_i2c_data->cali_sw[MC3XXX_AXIS_Z] += data[2]; cali[MC3XXX_AXIS_X] = data[0] * gsensor_gain.x / GRAVITY_EARTH_1000; cali[MC3XXX_AXIS_Y] = data[1] * gsensor_gain.y / GRAVITY_EARTH_1000; cali[MC3XXX_AXIS_Z] = data[2] * gsensor_gain.z / GRAVITY_EARTH_1000; err = MC3XXX_WriteCalibration(mc3xxx_i2c_client, cali); if (err) { ACC_PR_ERR("mc3xxx_WriteCalibration failed!\n"); return -1; } return 0; } static int mc3xxx_factory_get_cali(int32_t data[3]) { data[0] = mc3xxx_obj_i2c_data->cali_sw[MC3XXX_AXIS_X]; data[1] = mc3xxx_obj_i2c_data->cali_sw[MC3XXX_AXIS_Y]; data[2] = mc3xxx_obj_i2c_data->cali_sw[MC3XXX_AXIS_Z]; return 0; } static int mc3xxx_factory_do_self_test(void) { return 0; } static struct accel_factory_fops mc3xxx_factory_fops = { .enable_sensor = mc3xxx_factory_enable_sensor, .get_data = mc3xxx_factory_get_data, .get_raw_data = mc3xxx_factory_get_raw_data, .enable_calibration = mc3xxx_factory_enable_calibration, .clear_cali = mc3xxx_factory_clear_cali, .set_cali = mc3xxx_factory_set_cali, .get_cali = mc3xxx_factory_get_cali, .do_self_test = mc3xxx_factory_do_self_test, }; static struct accel_factory_public mc3xxx_factory_device = { .gain = 1, .sensitivity = 1, .fops = &mc3xxx_factory_fops, }; /***************************************** *** mc3xxx_i2c_probe *****************************************/ static int mc3xxx_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_client *new_client; struct mc3xxx_i2c_data *obj; struct acc_control_path ctl = {0}; struct acc_data_path data = {0}; int err = 0; err = get_accel_dts_func(client->dev.of_node, hw); if (err < 0) { ACC_PR_ERR("get cust_baro dts info fail\n"); goto exit; } if (_mc3xxx_i2c_auto_probe(client) != MC3XXX_RETCODE_SUCCESS) goto exit; obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (!obj) { err = -ENOMEM; goto exit; } obj->hw = hw; err = hwmsen_get_convert(obj->hw->direction, &obj->cvt); if (err) { ACC_PR_ERR("invalid direction: %d\n", obj->hw->direction); goto exit_kfree; } mc3xxx_obj_i2c_data = obj; obj->client = client; new_client = obj->client; i2c_set_clientdata(new_client, obj); atomic_set(&obj->trace, 0); atomic_set(&obj->suspend, 0); #ifdef _MC3XXX_SUPPORT_LPF_ if (obj->hw->firlen > C_MAX_FIR_LENGTH) atomic_set(&obj->firlen, C_MAX_FIR_LENGTH); else atomic_set(&obj->firlen, obj->hw->firlen); if (atomic_read(&obj->firlen) > 0) atomic_set(&obj->fir_en, 1); #endif mc3xxx_i2c_client = new_client; MC3XXX_reset(new_client); if (_mc3xxx_i2c_auto_probe(client) != MC3XXX_RETCODE_SUCCESS) goto exit_init_failed; MC3XXX_i2c_read_block(client, 0x21, offset_buf, 6); err = MC3XXX_Init(new_client, 1); if (err) goto exit_init_failed; mc3xxx_mutex_init(); ctl.is_use_common_factory = false; /* factory */ err = accel_factory_device_register(&mc3xxx_factory_device); if (err) { ACC_PR_ERR("acc_factory register failed.\n"); goto exit_misc_device_register_failed; } err = mc3xxx_create_attr( &(mc3xxx_init_info.platform_diver_addr->driver)); if (err) { ACC_PR_ERR("create attribute err = %d\n", err); goto exit_create_attr_failed; } ctl.open_report_data = mc3xxx_open_report_data; ctl.enable_nodata = mc3xxx_enable_nodata; ctl.batch = mc3xxx_batch; ctl.flush = mc3xxx_flush; ctl.set_delay = mc3xxx_set_delay; ctl.is_report_input_direct = false; ctl.is_support_batch = obj->hw->is_batch_supported; err = acc_register_control_path(&ctl); if (err) { ACC_PR_ERR("register acc control path err\n"); goto exit_kfree; } data.get_data = mc3xxx_get_data; data.vender_div = 1000; err = acc_register_data_path(&data); if (err) { ACC_PR_ERR("register acc data path err= %d\n", err); goto exit_kfree; } s_nInitFlag = MC3XXX_INIT_SUCC; return 0; exit_create_attr_failed: exit_misc_device_register_failed: exit_init_failed: exit_kfree: kfree(obj); obj = NULL; exit: ACC_PR_ERR("%s: err = %d\n", __func__, err); s_nInitFlag = MC3XXX_INIT_FAIL; return err; } /***************************************** *** mc3xxx_i2c_remove *****************************************/ static int mc3xxx_i2c_remove(struct i2c_client *client) { int err = 0; err = mc3xxx_delete_attr( &(mc3xxx_init_info.platform_diver_addr->driver)); if (err) ACC_PR_ERR("mc3xxx_delete_attr fail: %d\n", err); #ifdef _MC3XXX_SUPPORT_VPROXIMITY_SENSOR_ misc_deregister(&mcube_psensor_device); #endif mc3xxx_i2c_client = NULL; i2c_unregister_device(client); accel_factory_device_deregister(&mc3xxx_factory_device); kfree(i2c_get_clientdata(client)); return 0; } /***************************************** *** mc3xxx_remove *****************************************/ static int mc3xxx_remove(void) { MC3XXX_power(hw, 0); i2c_del_driver(&mc3xxx_i2c_driver); return 0; } /***************************************** *** mc3xxx_local_init *****************************************/ static int mc3xxx_local_init(void) { if (i2c_add_driver(&mc3xxx_i2c_driver)) { ACC_PR_ERR("add driver error\n"); return -1; } if (s_nInitFlag == MC3XXX_INIT_FAIL) return -1; return 0; } /***************************************** *** mc3xxx_init *****************************************/ static int __init mc3xxx_init(void) { acc_driver_add(&mc3xxx_init_info); return 0; } /***************************************** *** mc3xxx_exit *****************************************/ static void __exit mc3xxx_exit(void) { #ifdef CONFIG_CUSTOM_KERNEL_ACCELEROMETER_MODULE success_Flag = false; #endif } /*--------------------------------------------------------------------------*/ module_init(mc3xxx_init); module_exit(mc3xxx_exit); /*--------------------------------------------------------------------------*/ MODULE_DESCRIPTION("mc3XXX G-Sensor Driver"); MODULE_AUTHOR("Mediatek"); MODULE_LICENSE("GPL"); MODULE_VERSION(MC3XXX_DEV_DRIVER_VERSION);