From b09c0b051b24b989023f56061002fa3b32b8ae33 Mon Sep 17 00:00:00 2001 From: Wolfgang Wiedmeyer Date: Thu, 23 Feb 2017 14:36:24 +0100 Subject: drivers/sensorhub: update from GT-N7100_KK_Opensource_Update1 source drop The import already includes the build fixes from this commit: commit 7055ffb Author: Dheeraj CVR Date: 2014-12-22 12:55:48 +0530 drivers: sensorhub: fix compile Change-Id: Ice06c873e4f2fe50ccb1a4cac5ac761e4a872bd3 Signed-off-by: Wolfgang Wiedmeyer --- drivers/sensorhub/Kconfig | 126 +-- drivers/sensorhub/Makefile | 18 +- drivers/sensorhub/accel_lsm330.c | 306 ------- drivers/sensorhub/atmel/Kconfig | 144 ++++ drivers/sensorhub/atmel/Makefile | 21 + drivers/sensorhub/atmel/accel_lsm330.c | 306 +++++++ drivers/sensorhub/atmel/gyro_lsm330.c | 321 ++++++++ drivers/sensorhub/atmel/light_cm36651.c | 77 ++ drivers/sensorhub/atmel/magnetic_ak8963c.c | 271 +++++++ drivers/sensorhub/atmel/mcu_at32uc3l0128.c | 253 ++++++ drivers/sensorhub/atmel/pressure_bmp182.c | 195 +++++ drivers/sensorhub/atmel/prox_cm36651.c | 380 +++++++++ drivers/sensorhub/atmel/sensors_core.c | 107 +++ drivers/sensorhub/atmel/ssp.h | 409 ++++++++++ drivers/sensorhub/atmel/ssp_ak8963c.c | 111 +++ drivers/sensorhub/atmel/ssp_data.c | 275 +++++++ drivers/sensorhub/atmel/ssp_debug.c | 223 +++++ drivers/sensorhub/atmel/ssp_dev.c | 504 ++++++++++++ drivers/sensorhub/atmel/ssp_firmware.c | 495 ++++++++++++ drivers/sensorhub/atmel/ssp_i2c.c | 560 +++++++++++++ drivers/sensorhub/atmel/ssp_input.c | 371 +++++++++ drivers/sensorhub/atmel/ssp_sensorhub.c | 566 +++++++++++++ drivers/sensorhub/atmel/ssp_sensorhub.h | 71 ++ drivers/sensorhub/atmel/ssp_sysfs.c | 524 ++++++++++++ drivers/sensorhub/gyro_lsm330.c | 321 -------- drivers/sensorhub/light_cm36651.c | 77 -- drivers/sensorhub/magnetic_ak8963c.c | 271 ------- drivers/sensorhub/mcu_at32uc3l0128.c | 270 ------- drivers/sensorhub/pressure_bmp182.c | 195 ----- drivers/sensorhub/prox_cm36651.c | 378 --------- drivers/sensorhub/sensors_core.c | 107 --- drivers/sensorhub/ssp.h | 382 --------- drivers/sensorhub/ssp_ak8963c.c | 111 --- drivers/sensorhub/ssp_data.c | 268 ------ drivers/sensorhub/ssp_debug.c | 195 ----- drivers/sensorhub/ssp_dev.c | 475 ----------- drivers/sensorhub/ssp_firmware.c | 305 ------- drivers/sensorhub/ssp_i2c.c | 549 ------------- drivers/sensorhub/ssp_input.c | 371 --------- drivers/sensorhub/ssp_sensorhub.c | 574 ------------- drivers/sensorhub/ssp_sensorhub.h | 68 -- drivers/sensorhub/ssp_sysfs.c | 515 ------------ drivers/sensorhub/stm/Kconfig | 142 ++++ drivers/sensorhub/stm/Makefile | 23 + drivers/sensorhub/stm/factory/accel_mpu6500.c | 311 +++++++ drivers/sensorhub/stm/factory/gesture_max88920.c | 147 ++++ drivers/sensorhub/stm/factory/gyro_mpu6500.c | 674 ++++++++++++++++ drivers/sensorhub/stm/factory/light_cm3320.c | 77 ++ drivers/sensorhub/stm/factory/magnetic_yas532.c | 456 +++++++++++ drivers/sensorhub/stm/factory/mcu_atuc128l5har.c | 282 +++++++ drivers/sensorhub/stm/factory/mcu_stm32f401.c | 282 +++++++ drivers/sensorhub/stm/factory/pressure_bmp182.c | 197 +++++ drivers/sensorhub/stm/factory/prox_max88920.c | 457 +++++++++++ drivers/sensorhub/stm/factory/temphumidity_shtc1.c | 291 +++++++ drivers/sensorhub/stm/sensors_core.c | 173 ++++ drivers/sensorhub/stm/ssp.h | 547 +++++++++++++ drivers/sensorhub/stm/ssp_comm.c | 898 +++++++++++++++++++++ drivers/sensorhub/stm/ssp_data.c | 317 ++++++++ drivers/sensorhub/stm/ssp_debug.c | 226 ++++++ drivers/sensorhub/stm/ssp_dev.c | 566 +++++++++++++ drivers/sensorhub/stm/ssp_firmware.c | 709 ++++++++++++++++ drivers/sensorhub/stm/ssp_input.c | 601 ++++++++++++++ drivers/sensorhub/stm/ssp_sensorhub.c | 622 ++++++++++++++ drivers/sensorhub/stm/ssp_sensorhub.h | 72 ++ drivers/sensorhub/stm/ssp_spi.c | 255 ++++++ drivers/sensorhub/stm/ssp_sysfs.c | 600 ++++++++++++++ 66 files changed, 15122 insertions(+), 5869 deletions(-) delete mode 100644 drivers/sensorhub/accel_lsm330.c create mode 100755 drivers/sensorhub/atmel/Kconfig create mode 100755 drivers/sensorhub/atmel/Makefile create mode 100755 drivers/sensorhub/atmel/accel_lsm330.c create mode 100755 drivers/sensorhub/atmel/gyro_lsm330.c create mode 100755 drivers/sensorhub/atmel/light_cm36651.c create mode 100755 drivers/sensorhub/atmel/magnetic_ak8963c.c create mode 100755 drivers/sensorhub/atmel/mcu_at32uc3l0128.c create mode 100755 drivers/sensorhub/atmel/pressure_bmp182.c create mode 100755 drivers/sensorhub/atmel/prox_cm36651.c create mode 100755 drivers/sensorhub/atmel/sensors_core.c create mode 100755 drivers/sensorhub/atmel/ssp.h create mode 100755 drivers/sensorhub/atmel/ssp_ak8963c.c create mode 100755 drivers/sensorhub/atmel/ssp_data.c create mode 100755 drivers/sensorhub/atmel/ssp_debug.c create mode 100755 drivers/sensorhub/atmel/ssp_dev.c create mode 100755 drivers/sensorhub/atmel/ssp_firmware.c create mode 100755 drivers/sensorhub/atmel/ssp_i2c.c create mode 100755 drivers/sensorhub/atmel/ssp_input.c create mode 100755 drivers/sensorhub/atmel/ssp_sensorhub.c create mode 100755 drivers/sensorhub/atmel/ssp_sensorhub.h create mode 100755 drivers/sensorhub/atmel/ssp_sysfs.c delete mode 100644 drivers/sensorhub/gyro_lsm330.c delete mode 100644 drivers/sensorhub/light_cm36651.c delete mode 100644 drivers/sensorhub/magnetic_ak8963c.c delete mode 100644 drivers/sensorhub/mcu_at32uc3l0128.c delete mode 100644 drivers/sensorhub/pressure_bmp182.c delete mode 100644 drivers/sensorhub/prox_cm36651.c delete mode 100644 drivers/sensorhub/sensors_core.c delete mode 100644 drivers/sensorhub/ssp.h delete mode 100644 drivers/sensorhub/ssp_ak8963c.c delete mode 100644 drivers/sensorhub/ssp_data.c delete mode 100644 drivers/sensorhub/ssp_debug.c delete mode 100644 drivers/sensorhub/ssp_dev.c delete mode 100644 drivers/sensorhub/ssp_firmware.c delete mode 100644 drivers/sensorhub/ssp_i2c.c delete mode 100644 drivers/sensorhub/ssp_input.c delete mode 100644 drivers/sensorhub/ssp_sensorhub.c delete mode 100644 drivers/sensorhub/ssp_sensorhub.h delete mode 100644 drivers/sensorhub/ssp_sysfs.c create mode 100755 drivers/sensorhub/stm/Kconfig create mode 100755 drivers/sensorhub/stm/Makefile create mode 100755 drivers/sensorhub/stm/factory/accel_mpu6500.c create mode 100755 drivers/sensorhub/stm/factory/gesture_max88920.c create mode 100755 drivers/sensorhub/stm/factory/gyro_mpu6500.c create mode 100755 drivers/sensorhub/stm/factory/light_cm3320.c create mode 100755 drivers/sensorhub/stm/factory/magnetic_yas532.c create mode 100755 drivers/sensorhub/stm/factory/mcu_atuc128l5har.c create mode 100755 drivers/sensorhub/stm/factory/mcu_stm32f401.c create mode 100755 drivers/sensorhub/stm/factory/pressure_bmp182.c create mode 100755 drivers/sensorhub/stm/factory/prox_max88920.c create mode 100755 drivers/sensorhub/stm/factory/temphumidity_shtc1.c create mode 100755 drivers/sensorhub/stm/sensors_core.c create mode 100755 drivers/sensorhub/stm/ssp.h create mode 100755 drivers/sensorhub/stm/ssp_comm.c create mode 100755 drivers/sensorhub/stm/ssp_data.c create mode 100755 drivers/sensorhub/stm/ssp_debug.c create mode 100755 drivers/sensorhub/stm/ssp_dev.c create mode 100755 drivers/sensorhub/stm/ssp_firmware.c create mode 100755 drivers/sensorhub/stm/ssp_input.c create mode 100755 drivers/sensorhub/stm/ssp_sensorhub.c create mode 100755 drivers/sensorhub/stm/ssp_sensorhub.h create mode 100755 drivers/sensorhub/stm/ssp_spi.c create mode 100755 drivers/sensorhub/stm/ssp_sysfs.c diff --git a/drivers/sensorhub/Kconfig b/drivers/sensorhub/Kconfig index 609e854f3e9..a724db21d7b 100644 --- a/drivers/sensorhub/Kconfig +++ b/drivers/sensorhub/Kconfig @@ -1,133 +1,29 @@ # # sensor drivers configuration # -config SENSORS_SYSFS - tristate "Sensors sysfs" - help - Support sysfs for sensors. - If you say yes here you get sysfs support for - sensor factory test. - To compile this driver as a module, choose M here: the - module will be called sensors_core. -config SENSORS_SSP - tristate "Sensors ssp" +config SENSORS_SSP_ATMEL + tristate "Sensors ssp ATMEL" default n depends on I2C help - ssp driver for sensor hub. + ssp driver for ATMEL sensor hub. If you say yes here you get ssp support for sensor hub. To compile this driver as a module, choose M here: the module will be called ssp. -config SENSORS_SSP_LSM330 - tristate "Sensors ssp lsm330" +config SENSORS_SSP_STM + tristate "Sensors ssp STM" default n - depends on I2C - help - lsm330 file for factory test in ssp driver. - If you say yes here you get lsm330 support for - factory test. - To compile this driver as a module, choose M here: the - module will be called ssp. - -config SENSORS_SSP_AK8963C - tristate "Sensors ssp ak8963c" - default n - depends on I2C - help - ak8963c file for factory test in ssp driver. - If you say yes here you get ak8963c support for - factory test. - To compile this driver as a module, choose M here: the - module will be called ssp. - -config SENSORS_SSP_CM36651 - tristate "Sensors ssp cm36651" - default n - depends on I2C - help - cm36651 file for factory test in ssp driver. - If you say yes here you get cm36651 support for - factory test. - To compile this driver as a module, choose M here: the - module will be called ssp. - -config SENSORS_SSP_BMP182 - tristate "Sensors ssp bmp182" - default n - depends on I2C + depends on SPI help - bmp182 file for factory test in ssp driver. - If you say yes here you get bmp182 support for - factory test. - To compile this driver as a module, choose M here: the - module will be called ssp. - -config SENSORS_SSP_AT32UC3L0128 - tristate "Sensors ssp at32uc3l0128" - default n - depends on I2C - help - at32uc3l0128 file for factory test in ssp driver. - If you say yes here you get at32uc3l0128 support for - factory test. - To compile this driver as a module, choose M here: the - module will be called ssp. - -config SENSORS_SSP_ACCELEROMETER_POSITION - int "Accelerometer Sensor Mounting Position on Board" - depends on SENSORS_SSP - default "0" - help - X Y Z axis position. - 0: X, Y, Z - 1: Y,-X, Z - 2: -X,-Y, Z - 3: -Y, X, Z - 4: -X, Y,-Z - 5: Y, X,-Z - 6: X,-Y,-Z - 7: -Y,-X,-Z - -config SENSORS_SSP_GYROSCOPE_POSITION - int "Gyroscope Sensor Mounting Position on Board" - depends on SENSORS_SSP - default "0" - help - X Y Z axis position. - 0: X, Y, Z - 1: Y,-X, Z - 2: -X,-Y, Z - 3: -Y, X, Z - 4: -X, Y,-Z - 5: Y, X,-Z - 6: X,-Y,-Z - 7: -Y,-X,-Z - -config SENSORS_SSP_MAGNETOMETER_POSITION - int "Geomagnetic Sensor Mounting Position on Board" - depends on SENSORS_SSP - default "0" - help - X Y Z axis position. - 0: X, Y, Z - 1: Y,-X, Z - 2: -X,-Y, Z - 3: -Y, X, Z - 4: -X, Y,-Z - 5: Y, X,-Z - 6: X,-Y,-Z - 7: -Y,-X,-Z - -config SENSORS_SSP_SENSORHUB - tristate "Sensors ssp sensorhub" - default n - depends on I2C - help - ssp sensor hub driver for sensor hub. + ssp driver for STM sensor hub. If you say yes here you get ssp support for sensor hub. To compile this driver as a module, choose M here: the module will be called ssp. + +source "drivers/sensorhub/atmel/Kconfig" +source "drivers/sensorhub/stm/Kconfig" + diff --git a/drivers/sensorhub/Makefile b/drivers/sensorhub/Makefile index e5650e15a27..e9cb9fdf0d7 100644 --- a/drivers/sensorhub/Makefile +++ b/drivers/sensorhub/Makefile @@ -3,19 +3,5 @@ # # Each configuration option enables a list of files. -obj-$(CONFIG_SENSORS_SSP) += ssp_dev.o ssp_i2c.o ssp_data.o ssp_sysfs.o\ - ssp_input.o ssp_firmware.o ssp_debug.o - -obj-$(CONFIG_SENSORS_SYSFS) += sensors_core.o - -obj-$(CONFIG_SENSORS_SSP_LSM330) += accel_lsm330.o gyro_lsm330.o - -obj-$(CONFIG_SENSORS_SSP_CM36651) += light_cm36651.o prox_cm36651.o - -obj-$(CONFIG_SENSORS_SSP_AK8963C) += ssp_ak8963c.o magnetic_ak8963c.o - -obj-$(CONFIG_SENSORS_SSP_BMP182) += pressure_bmp182.o - -obj-$(CONFIG_SENSORS_SSP_AT32UC3L0128) += mcu_at32uc3l0128.o - -obj-$(CONFIG_SENSORS_SSP_SENSORHUB) += ssp_sensorhub.o +obj-$(CONFIG_SENSORS_SSP_ATMEL) += atmel/ +obj-$(CONFIG_SENSORS_SSP_STM) += stm/ \ No newline at end of file diff --git a/drivers/sensorhub/accel_lsm330.c b/drivers/sensorhub/accel_lsm330.c deleted file mode 100644 index 1f236636e0a..00000000000 --- a/drivers/sensorhub/accel_lsm330.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -/*************************************************************************/ -/* factory Sysfs */ -/*************************************************************************/ - -#define VENDOR "STM" -#define CHIP_ID "LSM330" - -#define CALIBRATION_FILE_PATH "/efs/calibration_data" -#define CALIBRATION_DATA_AMOUNT 20 - -static ssize_t accel_vendor_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", VENDOR); -} - -static ssize_t accel_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", CHIP_ID); -} - -int accel_open_calibration(struct ssp_data *data) -{ - int iRet = 0; - mm_segment_t old_fs; - struct file *cal_filp = NULL; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); - if (IS_ERR(cal_filp)) { - set_fs(old_fs); - iRet = PTR_ERR(cal_filp); - - data->accelcal.x = 0; - data->accelcal.y = 0; - data->accelcal.z = 0; - - return iRet; - } - - iRet = cal_filp->f_op->read(cal_filp, (char *)&data->accelcal, - 3 * sizeof(int), &cal_filp->f_pos); - if (iRet != 3 * sizeof(int)) - iRet = -EIO; - - filp_close(cal_filp, current->files); - set_fs(old_fs); - - ssp_dbg("[SSP]: open accel calibration %d, %d, %d\n", - data->accelcal.x, data->accelcal.y, data->accelcal.z); - - if ((data->accelcal.x == 0) && (data->accelcal.y == 0) - && (data->accelcal.z == 0)) - return ERROR; - - return iRet; -} - -static int enable_accel_for_cal(struct ssp_data *data) -{ - u8 uBuf[2] = {0, 10}; - - if (atomic_read(&data->aSensorEnable) & (1 << ACCELEROMETER_SENSOR)) { - if (get_msdelay(data->adDelayBuf[ACCELEROMETER_SENSOR]) != 10) { - send_instruction(data, CHANGE_DELAY, - ACCELEROMETER_SENSOR, uBuf, 2); - return SUCCESS; - } - } else { - send_instruction(data, ADD_SENSOR, - ACCELEROMETER_SENSOR, uBuf, 2); - } - - return FAIL; -} - -static void disable_accel_for_cal(struct ssp_data *data, int iDelayChanged) -{ - u8 uBuf[2] = {0, 10}; - - if (atomic_read(&data->aSensorEnable) & (1 << ACCELEROMETER_SENSOR)) { - uBuf[1] = get_msdelay(data->adDelayBuf[ACCELEROMETER_SENSOR]); - uBuf[0] = get_delay_cmd(uBuf[1]); - if (iDelayChanged) - send_instruction(data, CHANGE_DELAY, - ACCELEROMETER_SENSOR, uBuf, 2); - } else { - send_instruction(data, REMOVE_SENSOR, - ACCELEROMETER_SENSOR, uBuf, 2); - } -} - -static int accel_do_calibrate(struct ssp_data *data, int iEnable) -{ - int iSum[3] = { 0, }; - int iRet = 0, iCount; - struct file *cal_filp = NULL; - mm_segment_t old_fs; - - if (iEnable) { - data->accelcal.x = 0; - data->accelcal.y = 0; - data->accelcal.z = 0; - - iRet = enable_accel_for_cal(data); - msleep(300); - - for (iCount = 0; iCount < CALIBRATION_DATA_AMOUNT; iCount++) { - iSum[0] += data->buf[ACCELEROMETER_SENSOR].x; - iSum[1] += data->buf[ACCELEROMETER_SENSOR].y; - iSum[2] += (data->buf[ACCELEROMETER_SENSOR].z - 1024); - mdelay(10); - } - disable_accel_for_cal(data, iRet); - - data->accelcal.x = (iSum[0] / CALIBRATION_DATA_AMOUNT); - data->accelcal.y = (iSum[1] / CALIBRATION_DATA_AMOUNT); - data->accelcal.z = (iSum[2] / CALIBRATION_DATA_AMOUNT); - } else { - data->accelcal.x = 0; - data->accelcal.y = 0; - data->accelcal.z = 0; - } - - ssp_dbg("[SSP]: do accel calibrate %d, %d, %d\n", - data->accelcal.x, data->accelcal.y, data->accelcal.z); - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); - if (IS_ERR(cal_filp)) { - pr_err("[SSP]: %s - Can't open calibration file\n", __func__); - set_fs(old_fs); - iRet = PTR_ERR(cal_filp); - return iRet; - } - - iRet = cal_filp->f_op->write(cal_filp, (char *)&data->accelcal, - 3 * sizeof(int), &cal_filp->f_pos); - if (iRet != 3 * sizeof(int)) { - pr_err("[SSP]: %s - Can't write the accelcal to file\n", - __func__); - iRet = -EIO; - } - - filp_close(cal_filp, current->files); - set_fs(old_fs); - - return iRet; -} - -static ssize_t accel_calibration_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int iRet; - int iCount = 0; - struct ssp_data *data = dev_get_drvdata(dev); - - iRet = accel_open_calibration(data); - if (iRet < 0) - pr_err("[SSP]: %s - calibration open failed\n", __func__); - - ssp_dbg("[SSP] Cal data : %d %d %d - %d\n", - data->accelcal.x, data->accelcal.y, data->accelcal.z, iRet); - - iCount = sprintf(buf, "%d %d %d %d\n", iRet, data->accelcal.x, - data->accelcal.y, data->accelcal.z); - return iCount; -} - -static ssize_t accel_calibration_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int iRet; - int64_t dEnable; - struct ssp_data *data = dev_get_drvdata(dev); - - iRet = strict_strtoll(buf, 10, &dEnable); - if (iRet < 0) - return iRet; - - iRet = accel_do_calibrate(data, (int)dEnable); - if (iRet < 0) - pr_err("[SSP]: %s - accel_do_calibrate() failed\n", __func__); - - return size; -} - -static ssize_t raw_data_read(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", - data->buf[ACCELEROMETER_SENSOR].x, - data->buf[ACCELEROMETER_SENSOR].y, - data->buf[ACCELEROMETER_SENSOR].z); -} - -static ssize_t accel_reactive_alert_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - char chTempBuf[2] = {0, 10}; - int iRet, iDelayCnt = 0; - struct ssp_data *data = dev_get_drvdata(dev); - - if (sysfs_streq(buf, "1")) - ssp_dbg("[SSP]: %s - on\n", __func__); - else if (sysfs_streq(buf, "0")) - ssp_dbg("[SSP]: %s - off\n", __func__); - else if (sysfs_streq(buf, "2")) { - ssp_dbg("[SSP]: %s - factory\n", __func__); - - data->uFactorydataReady = 0; - memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); - - data->bAccelAlert = false; - iRet = send_instruction(data, FACTORY_MODE, - ACCELEROMETER_FACTORY, chTempBuf, 2); - - while (!(data->uFactorydataReady & (1 << ACCELEROMETER_FACTORY)) - && (iDelayCnt++ < 150) - && (iRet == SUCCESS)) - msleep(20); - - if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { - pr_err("[SSP]: %s - accel Selftest Timeout!!\n", - __func__); - goto exit; - } - - mdelay(5); - - data->bAccelAlert = data->uFactorydata[0]; - ssp_dbg("[SSP]: %s factory test success!\n", __func__); - } else { - pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); - return -EINVAL; - } -exit: - return size; -} - -static ssize_t accel_reactive_alert_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool bSuccess = false; - struct ssp_data *data = dev_get_drvdata(dev); - - if (data->bAccelAlert == true) - bSuccess = true; - else - bSuccess = false; - - data->bAccelAlert = false; - return sprintf(buf, "%u\n", bSuccess); -} - -static DEVICE_ATTR(name, S_IRUGO, accel_name_show, NULL); -static DEVICE_ATTR(vendor, S_IRUGO, accel_vendor_show, NULL); -static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, - accel_calibration_show, accel_calibration_store); -static DEVICE_ATTR(raw_data, S_IRUGO, raw_data_read, NULL); -static DEVICE_ATTR(reactive_alert, S_IRUGO | S_IWUSR | S_IWGRP, - accel_reactive_alert_show, accel_reactive_alert_store); - -static struct device_attribute *acc_attrs[] = { - &dev_attr_name, - &dev_attr_vendor, - &dev_attr_calibration, - &dev_attr_raw_data, - &dev_attr_reactive_alert, - NULL, -}; - -void initialize_accel_factorytest(struct ssp_data *data) -{ - sensors_register(data->acc_device, data, acc_attrs, - "accelerometer_sensor"); -} - -void remove_accel_factorytest(struct ssp_data *data) -{ - sensors_unregister(data->acc_device, acc_attrs); -} diff --git a/drivers/sensorhub/atmel/Kconfig b/drivers/sensorhub/atmel/Kconfig new file mode 100755 index 00000000000..c75cb9299cc --- /dev/null +++ b/drivers/sensorhub/atmel/Kconfig @@ -0,0 +1,144 @@ +# +# sensor drivers configuration +# +config SENSORS_SYSFS + tristate "Sensors sysfs" + help + Support sysfs for sensors. + If you say yes here you get sysfs support for + sensor factory test. + To compile this driver as a module, choose M here: the + module will be called sensors_core. + +config SENSORS_SSP + tristate "Sensors ssp" + default n + depends on I2C + help + ssp driver for sensor hub. + If you say yes here you get ssp support for + sensor hub. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_ATMEL + tristate "Sensors ssp atmel" + default n + depends on I2C + help + ssp driver for sensor hub. + If you say yes here you get ssp support for + sensor hub. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_LSM330 + tristate "Sensors ssp lsm330" + default n + depends on I2C + help + lsm330 file for factory test in ssp driver. + If you say yes here you get lsm330 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_AK8963C + tristate "Sensors ssp ak8963c" + default n + depends on I2C + help + ak8963c file for factory test in ssp driver. + If you say yes here you get ak8963c support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_CM36651 + tristate "Sensors ssp cm36651" + default n + depends on I2C + help + cm36651 file for factory test in ssp driver. + If you say yes here you get cm36651 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_BMP182 + tristate "Sensors ssp bmp182" + default n + depends on I2C + help + bmp182 file for factory test in ssp driver. + If you say yes here you get bmp182 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_AT32UC3L0128 + tristate "Sensors ssp at32uc3l0128" + default n + depends on I2C + help + at32uc3l0128 file for factory test in ssp driver. + If you say yes here you get at32uc3l0128 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_ACCELEROMETER_POSITION + int "Accelerometer Sensor Mounting Position on Board" + depends on SENSORS_SSP + default "0" + help + X Y Z axis position. + 0: X, Y, Z + 1: Y,-X, Z + 2: -X,-Y, Z + 3: -Y, X, Z + 4: -X, Y,-Z + 5: Y, X,-Z + 6: X,-Y,-Z + 7: -Y,-X,-Z + +config SENSORS_SSP_GYROSCOPE_POSITION + int "Gyroscope Sensor Mounting Position on Board" + depends on SENSORS_SSP + default "0" + help + X Y Z axis position. + 0: X, Y, Z + 1: Y,-X, Z + 2: -X,-Y, Z + 3: -Y, X, Z + 4: -X, Y,-Z + 5: Y, X,-Z + 6: X,-Y,-Z + 7: -Y,-X,-Z + +config SENSORS_SSP_MAGNETOMETER_POSITION + int "Geomagnetic Sensor Mounting Position on Board" + depends on SENSORS_SSP + default "0" + help + X Y Z axis position. + 0: X, Y, Z + 1: Y,-X, Z + 2: -X,-Y, Z + 3: -Y, X, Z + 4: -X, Y,-Z + 5: Y, X,-Z + 6: X,-Y,-Z + 7: -Y,-X,-Z + +config SENSORS_SSP_SENSORHUB + tristate "Sensors ssp sensorhub" + default n + depends on I2C + help + ssp sensor hub driver for sensor hub. + If you say yes here you get ssp support for + sensor hub. + To compile this driver as a module, choose M here: the + module will be called ssp. diff --git a/drivers/sensorhub/atmel/Makefile b/drivers/sensorhub/atmel/Makefile new file mode 100755 index 00000000000..e6137c83312 --- /dev/null +++ b/drivers/sensorhub/atmel/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the sensor drivers. +# + +# Each configuration option enables a list of files. +obj-$(CONFIG_SENSORS_SSP_ATMEL) += ssp_dev.o ssp_i2c.o ssp_data.o ssp_sysfs.o\ + ssp_input.o ssp_firmware.o ssp_debug.o + +obj-$(CONFIG_SENSORS_SYSFS) += sensors_core.o + +obj-$(CONFIG_SENSORS_SSP_LSM330) += accel_lsm330.o gyro_lsm330.o + +obj-$(CONFIG_SENSORS_SSP_CM36651) += light_cm36651.o prox_cm36651.o + +obj-$(CONFIG_SENSORS_SSP_AK8963C) += ssp_ak8963c.o magnetic_ak8963c.o + +obj-$(CONFIG_SENSORS_SSP_BMP182) += pressure_bmp182.o + +obj-$(CONFIG_SENSORS_SSP_AT32UC3L0128) += mcu_at32uc3l0128.o + +obj-$(CONFIG_SENSORS_SSP_SENSORHUB) += ssp_sensorhub.o diff --git a/drivers/sensorhub/atmel/accel_lsm330.c b/drivers/sensorhub/atmel/accel_lsm330.c new file mode 100755 index 00000000000..53aef948fab --- /dev/null +++ b/drivers/sensorhub/atmel/accel_lsm330.c @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "STM" +#define CHIP_ID "LSM330" + +#define CALIBRATION_FILE_PATH "/efs/calibration_data" +#define CALIBRATION_DATA_AMOUNT 20 + +static ssize_t accel_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t accel_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +int accel_open_calibration(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + + return iRet; + } + + iRet = cal_filp->f_op->read(cal_filp, (char *)&data->accelcal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) + iRet = -EIO; + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + ssp_dbg("[SSP]: open accel calibration %d, %d, %d\n", + data->accelcal.x, data->accelcal.y, data->accelcal.z); + + if ((data->accelcal.x == 0) && (data->accelcal.y == 0) + && (data->accelcal.z == 0)) + return ERROR; + + return iRet; +} + +static int enable_accel_for_cal(struct ssp_data *data) +{ + u8 uBuf[2] = {0, 10}; + + if (atomic_read(&data->aSensorEnable) & (1 << ACCELEROMETER_SENSOR)) { + if (get_msdelay(data->adDelayBuf[ACCELEROMETER_SENSOR]) != 10) { + send_instruction(data, CHANGE_DELAY, + ACCELEROMETER_SENSOR, uBuf, 2); + return SUCCESS; + } + } else { + send_instruction(data, ADD_SENSOR, + ACCELEROMETER_SENSOR, uBuf, 2); + } + + return FAIL; +} + +static void disable_accel_for_cal(struct ssp_data *data, int iDelayChanged) +{ + u8 uBuf[2] = {0, 10}; + + if (atomic_read(&data->aSensorEnable) & (1 << ACCELEROMETER_SENSOR)) { + uBuf[1] = get_msdelay(data->adDelayBuf[ACCELEROMETER_SENSOR]); + uBuf[0] = get_delay_cmd(uBuf[1]); + if (iDelayChanged) + send_instruction(data, CHANGE_DELAY, + ACCELEROMETER_SENSOR, uBuf, 2); + } else { + send_instruction(data, REMOVE_SENSOR, + ACCELEROMETER_SENSOR, uBuf, 2); + } +} + +static int accel_do_calibrate(struct ssp_data *data, int iEnable) +{ + int iSum[3] = { 0, }; + int iRet = 0, iCount; + struct file *cal_filp = NULL; + mm_segment_t old_fs; + + if (iEnable) { + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + + iRet = enable_accel_for_cal(data); + msleep(300); + + for (iCount = 0; iCount < CALIBRATION_DATA_AMOUNT; iCount++) { + iSum[0] += data->buf[ACCELEROMETER_SENSOR].x; + iSum[1] += data->buf[ACCELEROMETER_SENSOR].y; + iSum[2] += (data->buf[ACCELEROMETER_SENSOR].z - 1024); + mdelay(10); + } + disable_accel_for_cal(data, iRet); + + data->accelcal.x = (iSum[0] / CALIBRATION_DATA_AMOUNT); + data->accelcal.y = (iSum[1] / CALIBRATION_DATA_AMOUNT); + data->accelcal.z = (iSum[2] / CALIBRATION_DATA_AMOUNT); + } else { + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + } + + ssp_dbg("[SSP]: do accel calibrate %d, %d, %d\n", + data->accelcal.x, data->accelcal.y, data->accelcal.z); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[SSP]: %s - Can't open calibration file\n", __func__); + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + return iRet; + } + + iRet = cal_filp->f_op->write(cal_filp, (char *)&data->accelcal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) { + pr_err("[SSP]: %s - Can't write the accelcal to file\n", + __func__); + iRet = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return iRet; +} + +static ssize_t accel_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int iRet; + int iCount = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = accel_open_calibration(data); + if (iRet < 0) + pr_err("[SSP]: %s - calibration open failed(%d)\n", __func__, iRet); + + ssp_dbg("[SSP] Cal data : %d %d %d - %d\n", + data->accelcal.x, data->accelcal.y, data->accelcal.z, iRet); + + iCount = sprintf(buf, "%d %d %d %d\n", iRet, data->accelcal.x, + data->accelcal.y, data->accelcal.z); + return iCount; +} + +static ssize_t accel_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int iRet; + int64_t dEnable; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtoll(buf, 10, &dEnable); + if (iRet < 0) + return iRet; + + iRet = accel_do_calibrate(data, (int)dEnable); + if (iRet < 0) + pr_err("[SSP]: %s - accel_do_calibrate() failed\n", __func__); + + return size; +} + +static ssize_t raw_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", + data->buf[ACCELEROMETER_SENSOR].x, + data->buf[ACCELEROMETER_SENSOR].y, + data->buf[ACCELEROMETER_SENSOR].z); +} + +static ssize_t accel_reactive_alert_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + char chTempBuf[2] = {0, 10}; + int iRet, iDelayCnt = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "1")) + ssp_dbg("[SSP]: %s - on\n", __func__); + else if (sysfs_streq(buf, "0")) + ssp_dbg("[SSP]: %s - off\n", __func__); + else if (sysfs_streq(buf, "2")) { + ssp_dbg("[SSP]: %s - factory\n", __func__); + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + data->bAccelAlert = false; + iRet = send_instruction(data, FACTORY_MODE, + ACCELEROMETER_FACTORY, chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << ACCELEROMETER_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - accel Selftest Timeout!!\n", + __func__); + goto exit; + } + + mdelay(5); + + data->bAccelAlert = data->uFactorydata[0]; + ssp_dbg("[SSP]: %s factory test success!\n", __func__); + } else { + pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } +exit: + return size; +} + +static ssize_t accel_reactive_alert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->bAccelAlert == true) + bSuccess = true; + else + bSuccess = false; + + data->bAccelAlert = false; + return sprintf(buf, "%u\n", bSuccess); +} + +static DEVICE_ATTR(name, S_IRUGO, accel_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, accel_vendor_show, NULL); +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, + accel_calibration_show, accel_calibration_store); +static DEVICE_ATTR(raw_data, S_IRUGO, raw_data_read, NULL); +static DEVICE_ATTR(reactive_alert, S_IRUGO | S_IWUSR | S_IWGRP, + accel_reactive_alert_show, accel_reactive_alert_store); + +static struct device_attribute *acc_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_calibration, + &dev_attr_raw_data, + &dev_attr_reactive_alert, + NULL, +}; + +void initialize_accel_factorytest(struct ssp_data *data) +{ + sensors_register(data->acc_device, data, acc_attrs, + "accelerometer_sensor"); +} + +void remove_accel_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->acc_device, acc_attrs); +} diff --git a/drivers/sensorhub/atmel/gyro_lsm330.c b/drivers/sensorhub/atmel/gyro_lsm330.c new file mode 100755 index 00000000000..0a3a473f107 --- /dev/null +++ b/drivers/sensorhub/atmel/gyro_lsm330.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "STM" +#define CHIP_ID "LSM330" + +#define CALIBRATION_FILE_PATH "/efs/gyro_cal_data" +#define CALIBRATION_DATA_AMOUNT 20 + +static ssize_t gyro_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t gyro_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +int gyro_open_calibration(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + + data->gyrocal.x = 0; + data->gyrocal.y = 0; + data->gyrocal.z = 0; + + return iRet; + } + + iRet = cal_filp->f_op->read(cal_filp, (char *)&data->gyrocal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) + iRet = -EIO; + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + ssp_dbg("[SSP]: open gyro calibration %d, %d, %d\n", + data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); + return iRet; +} + +static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) +{ + int iRet = 0; + struct file *cal_filp = NULL; + mm_segment_t old_fs; + + data->gyrocal.x = iCalData[0]; + data->gyrocal.y = iCalData[1]; + data->gyrocal.z = iCalData[2]; + + ssp_dbg("[SSP]: do gyro calibrate %d, %d, %d\n", + data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[SSP]: %s - Can't open calibration file\n", __func__); + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + return -EIO; + } + + iRet = cal_filp->f_op->write(cal_filp, (char *)&data->gyrocal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) { + pr_err("[SSP]: %s - Can't write gyro cal to file\n", __func__); + iRet = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return iRet; +} + +static ssize_t gyro_power_off(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssp_dbg("[SSP]: %s\n", __func__); + + return sprintf(buf, "%d\n", 1); +} + +static ssize_t gyro_power_on(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssp_dbg("[SSP]: %s\n", __func__); + + return sprintf(buf, "%d\n", 1); +} + +static ssize_t gyro_get_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char chTempBuf[2] = { 0, 10}, chTemp = 0; + int iDelayCnt = 0, iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + if (!(data->uSensorState & (1 << GYROSCOPE_SENSOR))) + goto exit; + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_TEMP_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GYROSCOPE_TEMP_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Gyro Temp Timeout!!\n", __func__); + goto exit; + } + + mdelay(5); + + chTemp = (char)data->uFactorydata[0]; + ssp_dbg("[SSP]: %s - %d\n", __func__, chTemp); +exit: + return sprintf(buf, "%d\n", chTemp); +} + +static ssize_t gyro_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char chTempBuf[2] = { 3, 200}; + u8 uFifoPass = 2; + u8 uBypassPass = 2; + u8 uCalPass = 0; + s16 iNOST[3] = {0,}, iST[3] = {0,}, iCalData[3] = {0,}; + int iZeroRateData[3] = {0,}; + int iDelayCnt = 0, iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GYROSCOPE_FACTORY)) + && (iDelayCnt++ < 250) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 250) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Gyro Selftest Timeout!!\n", __func__); + goto exit; + } + mdelay(5); + + iNOST[0] = (s16)((data->uFactorydata[0] << 8) + data->uFactorydata[1]); + iNOST[1] = (s16)((data->uFactorydata[2] << 8) + data->uFactorydata[3]); + iNOST[2] = (s16)((data->uFactorydata[4] << 8) + data->uFactorydata[5]); + + iST[0] = (s16)((data->uFactorydata[6] << 8) + data->uFactorydata[7]); + iST[1] = (s16)((data->uFactorydata[8] << 8) + data->uFactorydata[9]); + iST[2] = (s16)((data->uFactorydata[10] << 8) + data->uFactorydata[11]); + + iCalData[0] = + (s16)((data->uFactorydata[12] << 8) + data->uFactorydata[13]); + iCalData[1] = + (s16)((data->uFactorydata[14] << 8) + data->uFactorydata[15]); + iCalData[2] = + (s16)((data->uFactorydata[16] << 8) + data->uFactorydata[17]); + + iZeroRateData[0] = + (s16)((data->uFactorydata[18] << 8) + data->uFactorydata[19]); + iZeroRateData[1] = + (s16)((data->uFactorydata[20] << 8) + data->uFactorydata[21]); + iZeroRateData[2] = + (s16)((data->uFactorydata[22] << 8) + data->uFactorydata[23]); + + uCalPass = data->uFactorydata[24]; + uFifoPass = data->uFactorydata[25]; + uBypassPass = data->uFactorydata[26]; + + if (uFifoPass && uBypassPass && uCalPass) + save_gyro_caldata(data, iCalData); + +exit: + ssp_dbg("[SSP]: Gyro Selftest - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + iNOST[0], iNOST[1], iNOST[2], iST[0], iST[1], iST[2], + iZeroRateData[0], iZeroRateData[1], iZeroRateData[2], + uFifoPass & uBypassPass & uCalPass, uFifoPass, uCalPass); + + return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + iNOST[0], iNOST[1], iNOST[2], iST[0], iST[1], iST[2], + iZeroRateData[0], iZeroRateData[1], iZeroRateData[2], + uFifoPass & uBypassPass & uCalPass, uFifoPass, uCalPass); +} + +static ssize_t gyro_selftest_dps_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int iNewDps = 0; + int iDelayCnt = 0, iRet = 0; + char chTempBuf[2] = { 0, 10 }; + + struct ssp_data *data = dev_get_drvdata(dev); + + if (!(data->uSensorState & (1 << GYROSCOPE_SENSOR))) + goto exit; + + sscanf(buf, "%d", &iNewDps); + + if (iNewDps == GYROSCOPE_DPS250) + chTempBuf[0] = 0; + else if (iNewDps == GYROSCOPE_DPS500) + chTempBuf[0] = 1; + else if (iNewDps == GYROSCOPE_DPS2000) + chTempBuf[0] = 2; + else { + chTempBuf[0] = 1; + iNewDps = GYROSCOPE_DPS500; + } + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_DPS_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GYROSCOPE_DPS_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Gyro Selftest DPS Timeout!!\n", __func__); + goto exit; + } + + mdelay(5); + + if (data->uFactorydata[0] != SUCCESS) { + pr_err("[SSP]: %s - Gyro Selftest DPS Error!!\n", __func__); + goto exit; + } + + data->uGyroDps = (unsigned int)iNewDps; + pr_err("[SSP]: %s - %u dps stored\n", __func__, data->uGyroDps); +exit: + return count; +} + +static ssize_t gyro_selftest_dps_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", data->uGyroDps); +} + +static DEVICE_ATTR(name, S_IRUGO, gyro_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, gyro_vendor_show, NULL); +static DEVICE_ATTR(power_off, S_IRUGO, gyro_power_off, NULL); +static DEVICE_ATTR(power_on, S_IRUGO, gyro_power_on, NULL); +static DEVICE_ATTR(temperature, S_IRUGO, gyro_get_temp, NULL); +static DEVICE_ATTR(selftest, S_IRUGO, gyro_selftest_show, NULL); +static DEVICE_ATTR(selftest_dps, S_IRUGO | S_IWUSR | S_IWGRP, + gyro_selftest_dps_show, gyro_selftest_dps_store); + +static struct device_attribute *gyro_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_selftest, + &dev_attr_power_on, + &dev_attr_power_off, + &dev_attr_temperature, + &dev_attr_selftest_dps, + NULL, +}; + +void initialize_gyro_factorytest(struct ssp_data *data) +{ + sensors_register(data->gyro_device, data, gyro_attrs, "gyro_sensor"); +} + +void remove_gyro_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->gyro_device, gyro_attrs); +} diff --git a/drivers/sensorhub/atmel/light_cm36651.c b/drivers/sensorhub/atmel/light_cm36651.c new file mode 100755 index 00000000000..68081e44deb --- /dev/null +++ b/drivers/sensorhub/atmel/light_cm36651.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +#define VENDOR "CAPELLA" +#define CHIP_ID "CM36651" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +static ssize_t light_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t light_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +static ssize_t light_lux_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u,%u,%u,%u\n", + data->buf[LIGHT_SENSOR].r, data->buf[LIGHT_SENSOR].g, + data->buf[LIGHT_SENSOR].b, data->buf[LIGHT_SENSOR].w); +} + +static ssize_t light_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u,%u,%u,%u\n", + data->buf[LIGHT_SENSOR].r, data->buf[LIGHT_SENSOR].g, + data->buf[LIGHT_SENSOR].b, data->buf[LIGHT_SENSOR].w); +} + +static DEVICE_ATTR(vendor, S_IRUGO, light_vendor_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, light_name_show, NULL); +static DEVICE_ATTR(lux, S_IRUGO, light_lux_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, light_data_show, NULL); + +static struct device_attribute *light_attrs[] = { + &dev_attr_vendor, + &dev_attr_name, + &dev_attr_lux, + &dev_attr_raw_data, + NULL, +}; + +void initialize_light_factorytest(struct ssp_data *data) +{ + sensors_register(data->light_device, data, light_attrs, "light_sensor"); +} + +void remove_light_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->light_device, light_attrs); +} diff --git a/drivers/sensorhub/atmel/magnetic_ak8963c.c b/drivers/sensorhub/atmel/magnetic_ak8963c.c new file mode 100755 index 00000000000..ccd1723bdae --- /dev/null +++ b/drivers/sensorhub/atmel/magnetic_ak8963c.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "AKM" +#define CHIP_ID "AK8963C" + +#define GYROSCOPE_DATA_SPEC_MIN -6500 +#define GYROSCOPE_DATA_SPEC_MAX 6500 + +#define GYROSCOPE_SELFTEST_X_SPEC_MIN -200 +#define GYROSCOPE_SELFTEST_X_SPEC_MAX 200 + +#define GYROSCOPE_SELFTEST_Y_SPEC_MIN -200 +#define GYROSCOPE_SELFTEST_Y_SPEC_MAX 200 + +#define GYROSCOPE_SELFTEST_Z_SPEC_MIN -3200 +#define GYROSCOPE_SELFTEST_Z_SPEC_MAX -800 + +static ssize_t magnetic_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t magnetic_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +static ssize_t raw_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", + data->buf[GEOMAGNETIC_SENSOR].x, + data->buf[GEOMAGNETIC_SENSOR].y, + data->buf[GEOMAGNETIC_SENSOR].z); +} + +static int check_data_spec(struct ssp_data *data) +{ + if ((data->buf[GEOMAGNETIC_SENSOR].x == 0) && + (data->buf[GEOMAGNETIC_SENSOR].y == 0) && + (data->buf[GEOMAGNETIC_SENSOR].z == 0)) + return FAIL; + else if ((data->buf[GEOMAGNETIC_SENSOR].x > GYROSCOPE_DATA_SPEC_MAX) || + (data->buf[GEOMAGNETIC_SENSOR].x < GYROSCOPE_DATA_SPEC_MIN) || + (data->buf[GEOMAGNETIC_SENSOR].y > GYROSCOPE_DATA_SPEC_MAX) || + (data->buf[GEOMAGNETIC_SENSOR].y < GYROSCOPE_DATA_SPEC_MIN) || + (data->buf[GEOMAGNETIC_SENSOR].z > GYROSCOPE_DATA_SPEC_MAX) || + (data->buf[GEOMAGNETIC_SENSOR].z < GYROSCOPE_DATA_SPEC_MIN)) + return FAIL; + else + return SUCCESS; +} + +static ssize_t adc_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + u8 chTempbuf[2] = {1, 20}; + s16 iSensorBuf[3] = {0, }; + int iRetries = 20; + struct ssp_data *data = dev_get_drvdata(dev); + + data->buf[GEOMAGNETIC_SENSOR].x = 0; + data->buf[GEOMAGNETIC_SENSOR].y = 0; + data->buf[GEOMAGNETIC_SENSOR].z = 0; + + if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_SENSOR))) + send_instruction(data, ADD_SENSOR, GEOMAGNETIC_SENSOR, + chTempbuf, 2); + + do { + msleep(50); + if (check_data_spec(data) == SUCCESS) + break; + } while (--iRetries); + + if (iRetries > 0) + bSuccess = true; + + iSensorBuf[0] = data->buf[GEOMAGNETIC_SENSOR].x; + iSensorBuf[1] = data->buf[GEOMAGNETIC_SENSOR].y; + iSensorBuf[2] = data->buf[GEOMAGNETIC_SENSOR].z; + + if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_SENSOR))) + send_instruction(data, REMOVE_SENSOR, GEOMAGNETIC_SENSOR, + chTempbuf, 2); + + pr_info("[SSP]: %s - x = %d, y = %d, z = %d\n", __func__, + iSensorBuf[0], iSensorBuf[1], iSensorBuf[2]); + + return sprintf(buf, "%s,%d,%d,%d\n", (bSuccess ? "OK" : "NG"), + iSensorBuf[0], iSensorBuf[1], iSensorBuf[2]); +} + +static ssize_t magnetic_get_asa(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%d,%d,%d\n", (s16)data->uFuseRomData[0], + (s16)data->uFuseRomData[1], (s16)data->uFuseRomData[2]); +} + +static ssize_t magnetic_get_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess; + struct ssp_data *data = dev_get_drvdata(dev); + + if ((data->uFuseRomData[0] == 0) || + (data->uFuseRomData[0] == 0xff) || + (data->uFuseRomData[1] == 0) || + (data->uFuseRomData[1] == 0xff) || + (data->uFuseRomData[2] == 0) || + (data->uFuseRomData[2] == 0xff)) + bSuccess = false; + else + bSuccess = true; + + return sprintf(buf, "%s,%u\n", (bSuccess ? "OK" : "NG"), bSuccess); +} + +static ssize_t magnetic_get_selftest(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSelftestPassed = false; + char chTempBuf[2] = { 0, 10 }; + s16 iSF_X = 0, iSF_Y = 0, iSF_Z = 0; + int iDelayCnt = 0, iRet = 0, iTimeoutReties = 0, iSpecOutReties = 0; + struct ssp_data *data = dev_get_drvdata(dev); + +reties: + iDelayCnt = 0; + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GEOMAGNETIC_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GEOMAGNETIC_FACTORY)) + && (iDelayCnt++ < 50) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 50) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Magnetic Selftest Timeout!! %d\n", + __func__, iRet); + if (iTimeoutReties++ < 3) + goto reties; + else + goto exit; + } + + mdelay(5); + + iSF_X = (s16)((data->uFactorydata[0] << 8) + data->uFactorydata[1]); + iSF_Y = (s16)((data->uFactorydata[2] << 8) + data->uFactorydata[3]); + iSF_Z = (s16)((data->uFactorydata[4] << 8) + data->uFactorydata[5]); + + iSF_X = (s16)(((int)iSF_X * ((int)data->uFuseRomData[0] + 128)) >> 8); + iSF_Y = (s16)(((int)iSF_Y * ((int)data->uFuseRomData[1] + 128)) >> 8); + iSF_Z = (s16)(((int)iSF_Z * ((int)data->uFuseRomData[2] + 128)) >> 8); + + pr_info("[SSP] %s: self test x = %d, y = %d, z = %d\n", + __func__, iSF_X, iSF_Y, iSF_Z); + if ((iSF_X >= GYROSCOPE_SELFTEST_X_SPEC_MIN) + && (iSF_X <= GYROSCOPE_SELFTEST_X_SPEC_MAX)) + pr_info("[SSP] x passed self test, expect -200<=x<=200\n"); + else + pr_info("[SSP] x failed self test, expect -200<=x<=200\n"); + if ((iSF_Y >= GYROSCOPE_SELFTEST_Y_SPEC_MIN) + && (iSF_Y <= GYROSCOPE_SELFTEST_Y_SPEC_MAX)) + pr_info("[SSP] y passed self test, expect -200<=y<=200\n"); + else + pr_info("[SSP] y failed self test, expect -200<=y<=200\n"); + if ((iSF_Z >= GYROSCOPE_SELFTEST_Z_SPEC_MIN) + && (iSF_Z <= GYROSCOPE_SELFTEST_Z_SPEC_MAX)) + pr_info("[SSP] z passed self test, expect -3200<=z<=-800\n"); + else + pr_info("[SSP] z failed self test, expect -3200<=z<=-800\n"); + + if ((iSF_X >= GYROSCOPE_SELFTEST_X_SPEC_MIN) + && (iSF_X <= GYROSCOPE_SELFTEST_X_SPEC_MAX) + && (iSF_Y >= GYROSCOPE_SELFTEST_Y_SPEC_MIN) + && (iSF_Y <= GYROSCOPE_SELFTEST_Y_SPEC_MAX) + && (iSF_Z >= GYROSCOPE_SELFTEST_Z_SPEC_MIN) + && (iSF_Z <= GYROSCOPE_SELFTEST_Z_SPEC_MAX)) + bSelftestPassed = true; + + if ((bSelftestPassed == false) && (iSpecOutReties++ < 5)) + goto reties; +exit: + return sprintf(buf, "%u,%d,%d,%d\n", + bSelftestPassed, iSF_X, iSF_Y, iSF_Z); +} + +static ssize_t magnetic_check_registers(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 uBuf[13] = {0,}; + + return sprintf(buf, "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n", + uBuf[0], uBuf[1], uBuf[2], uBuf[3], uBuf[4], uBuf[5], + uBuf[6], uBuf[7], uBuf[8], uBuf[9], uBuf[10], uBuf[11], + uBuf[12]); +} + +static ssize_t magnetic_check_cntl(struct device *dev, + struct device_attribute *attr, char *strbuf) +{ + bool bSuccess = false; + + return sprintf(strbuf, "%s,%d,%d,%d\n", + (!bSuccess ? "OK" : "NG"), 0, 0, 0); +} + +static DEVICE_ATTR(name, S_IRUGO, magnetic_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, magnetic_vendor_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, raw_data_read, NULL); +static DEVICE_ATTR(status, S_IRUGO, magnetic_get_status, NULL); +static DEVICE_ATTR(adc, S_IRUGO, adc_data_read, NULL); +static DEVICE_ATTR(dac, S_IRUGO, magnetic_check_cntl, NULL); +static DEVICE_ATTR(selftest, S_IRUGO, magnetic_get_selftest, NULL); +static DEVICE_ATTR(ak8963_asa, S_IRUGO, magnetic_get_asa, NULL); +static DEVICE_ATTR(ak8963_chk_registers, S_IRUGO, + magnetic_check_registers, NULL); + +static struct device_attribute *mag_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_adc, + &dev_attr_raw_data, + &dev_attr_status, + &dev_attr_selftest, + &dev_attr_ak8963_asa, + &dev_attr_ak8963_chk_registers, + &dev_attr_dac, + NULL, +}; + +void initialize_magnetic_factorytest(struct ssp_data *data) +{ + sensors_register(data->mag_device, data, mag_attrs, "magnetic_sensor"); +} + +void remove_magnetic_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->mag_device, mag_attrs); +} diff --git a/drivers/sensorhub/atmel/mcu_at32uc3l0128.c b/drivers/sensorhub/atmel/mcu_at32uc3l0128.c new file mode 100755 index 00000000000..9c2fa7d29d8 --- /dev/null +++ b/drivers/sensorhub/atmel/mcu_at32uc3l0128.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define MODEL_NAME "AT32UC3L0128" + +ssize_t mcu_revision_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "AT0112%u,AT0112%u\n", get_module_rev(), + data->uCurFirmRev); +} + +ssize_t mcu_model_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", MODEL_NAME); +} + +ssize_t mcu_update_kernel_bin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + iRet = forced_to_download_binary(data, UMS_BINARY); + if (iRet == SUCCESS) { + bSuccess = true; + goto out; + } + + iRet = forced_to_download_binary(data, KERNEL_BINARY); + if (iRet == SUCCESS) + bSuccess = true; + else + bSuccess = false; +out: + return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); +} + +ssize_t mcu_update_kernel_crashed_bin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + iRet = forced_to_download_binary(data, UMS_BINARY); + if (iRet == SUCCESS) { + bSuccess = true; + goto out; + } + + iRet = forced_to_download_binary(data, KERNEL_CRASHED_BINARY); + if (iRet == SUCCESS) + bSuccess = true; + else + bSuccess = false; +out: + return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); +} + +ssize_t mcu_update_ums_bin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + iRet = forced_to_download_binary(data, UMS_BINARY); + if (iRet == SUCCESS) + bSuccess = true; + else + bSuccess = false; + + return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); +} + +ssize_t mcu_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + reset_mcu(data); + + return sprintf(buf, "OK\n"); +} + +ssize_t mcu_factorytest_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + char chTempBuf[2] = {0, 10}; + int iRet = 0; + + if (sysfs_streq(buf, "1")) { + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + data->bMcuIRQTestSuccessed = false; + data->uTimeOutCnt = 0; + + iRet = send_instruction(data, FACTORY_MODE, + MCU_FACTORY, chTempBuf, 2); + if (data->uTimeOutCnt == 0) + data->bMcuIRQTestSuccessed = true; + } else { + pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + ssp_dbg("[SSP]: MCU Factory Test Start! - %d\n", iRet); + + return size; +} + +ssize_t mcu_factorytest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bMcuTestSuccessed = false; + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->bSspShutdown == true) { + ssp_dbg("[SSP]: %s - MCU Bin is crashed\n", __func__); + return sprintf(buf, "NG,NG,NG\n"); + } + + if (data->uFactorydataReady & (1 << MCU_FACTORY)) { + ssp_dbg("[SSP] MCU Factory Test Data : %u, %u, %u, %u, %u\n", + data->uFactorydata[0], data->uFactorydata[1], + data->uFactorydata[2], data->uFactorydata[3], + data->uFactorydata[4]); + + /* system clock, RTC, I2C Master, I2C Slave, externel pin */ + if ((data->uFactorydata[0] == SUCCESS) + && (data->uFactorydata[1] == SUCCESS) + && (data->uFactorydata[2] == SUCCESS) + && (data->uFactorydata[3] == SUCCESS) + && (data->uFactorydata[4] == SUCCESS)) + bMcuTestSuccessed = true; + } else { + pr_err("[SSP]: %s - The Sensorhub is not ready %u\n", __func__, + data->uFactorydataReady); + } + + ssp_dbg("[SSP]: MCU Factory Test Result - %s, %s, %s\n", MODEL_NAME, + (data->bMcuIRQTestSuccessed ? "OK" : "NG"), + (bMcuTestSuccessed ? "OK" : "NG")); + + return sprintf(buf, "%s,%s,%s\n", MODEL_NAME, + (data->bMcuIRQTestSuccessed ? "OK" : "NG"), + (bMcuTestSuccessed ? "OK" : "NG")); +} + +ssize_t mcu_sleep_factorytest_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + char chTempBuf[2] = {0, 10}; + int iRet = 0; + + if (sysfs_streq(buf, "1")) { + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, + MCU_SLEEP_FACTORY, chTempBuf, 2); + } else { + pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + ssp_dbg("[SSP]: MCU Sleep Factory Test Start! - %d\n", iRet); + + return size; +} + +ssize_t mcu_sleep_factorytest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int iDataIdx, iSensorData = 0; + struct ssp_data *data = dev_get_drvdata(dev); + struct sensor_value fsb[SENSOR_MAX]; + + if (!(data->uFactorydataReady & (1 << MCU_SLEEP_FACTORY))) { + pr_err("[SSP]: %s - The Sensorhub is not ready\n", __func__); + goto exit; + } + + for (iDataIdx = 0; iDataIdx < FACTORY_DATA_MAX;) { + iSensorData = (int)data->uFactorydata[iDataIdx++]; + if ((iSensorData < 0) || + (iSensorData >= (SENSOR_MAX - 1))) { + pr_err("[SSP]: %s - Mcu data frame error %d\n", + __func__, iSensorData); + goto exit; + } + + data->get_sensor_data[iSensorData]((char *)data->uFactorydata, + &iDataIdx, &(fsb[iSensorData])); + } + + convert_acc_data(&fsb[ACCELEROMETER_SENSOR].x); + convert_acc_data(&fsb[ACCELEROMETER_SENSOR].y); + convert_acc_data(&fsb[ACCELEROMETER_SENSOR].z); + +exit: + ssp_dbg("[SSP]: %s Result - " + "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%u,%u,%u,%u,%u\n", __func__, + fsb[ACCELEROMETER_SENSOR].x, fsb[ACCELEROMETER_SENSOR].y, + fsb[ACCELEROMETER_SENSOR].z, fsb[GYROSCOPE_SENSOR].x, + fsb[GYROSCOPE_SENSOR].y, fsb[GYROSCOPE_SENSOR].z, + fsb[GEOMAGNETIC_SENSOR].x, fsb[GEOMAGNETIC_SENSOR].y, + fsb[GEOMAGNETIC_SENSOR].z, fsb[PRESSURE_SENSOR].pressure[0], + fsb[PRESSURE_SENSOR].pressure[1], fsb[PROXIMITY_SENSOR].prox[1], + fsb[LIGHT_SENSOR].r, fsb[LIGHT_SENSOR].g, fsb[LIGHT_SENSOR].b, + fsb[LIGHT_SENSOR].w); + + return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%u,%u,%u,%u,%u\n", + fsb[ACCELEROMETER_SENSOR].x, fsb[ACCELEROMETER_SENSOR].y, + fsb[ACCELEROMETER_SENSOR].z, fsb[GYROSCOPE_SENSOR].x, + fsb[GYROSCOPE_SENSOR].y, fsb[GYROSCOPE_SENSOR].z, + fsb[GEOMAGNETIC_SENSOR].x, fsb[GEOMAGNETIC_SENSOR].y, + fsb[GEOMAGNETIC_SENSOR].z, fsb[PRESSURE_SENSOR].pressure[0], + fsb[PRESSURE_SENSOR].pressure[1], fsb[PROXIMITY_SENSOR].prox[1], + fsb[LIGHT_SENSOR].r, fsb[LIGHT_SENSOR].g, fsb[LIGHT_SENSOR].b, + fsb[LIGHT_SENSOR].w); +} diff --git a/drivers/sensorhub/atmel/pressure_bmp182.c b/drivers/sensorhub/atmel/pressure_bmp182.c new file mode 100755 index 00000000000..d5896f32bc2 --- /dev/null +++ b/drivers/sensorhub/atmel/pressure_bmp182.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +#define VENDOR "BOSCH" +#define CHIP_ID "BMP180" + +#define CALIBRATION_FILE_PATH "/efs/FactoryApp/baro_delta" + +#define PR_ABS_MAX 8388607 /* 24 bit 2'compl */ +#define PR_ABS_MIN -8388608 + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +static ssize_t sea_level_pressure_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + int iNewSeaLevelPressure; + + sscanf(buf, "%d", &iNewSeaLevelPressure); + + if (iNewSeaLevelPressure == 0) { + pr_info("%s, our->temperature = 0\n", __func__); + iNewSeaLevelPressure = -1; + } + + input_report_rel(data->pressure_input_dev, REL_DIAL, + iNewSeaLevelPressure); + input_sync(data->pressure_input_dev); + + return size; +} + +int pressure_open_calibration(struct ssp_data *data) +{ + char chBuf[10] = {0,}; + int iErr = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + iErr = PTR_ERR(cal_filp); + if (iErr != -ENOENT) + pr_err("[SSP]: %s - Can't open calibration file(%d)\n", + __func__, iErr); + set_fs(old_fs); + return iErr; + } + iErr = cal_filp->f_op->read(cal_filp, + chBuf, 10 * sizeof(char), &cal_filp->f_pos); + if (iErr < 0) { + pr_err("[SSP]: %s - Can't read the cal data from file (%d)\n", + __func__, iErr); + return iErr; + } + filp_close(cal_filp, current->files); + set_fs(old_fs); + + iErr = kstrtoint(chBuf, 10, &data->iPressureCal); + if (iErr < 0) { + pr_err("[SSP]: %s - kstrtoint failed. %d", __func__, iErr); + return iErr; + } + + ssp_dbg("[SSP]: open barometer calibration %d\n", data->iPressureCal); + + if (data->iPressureCal < PR_ABS_MIN || data->iPressureCal > PR_ABS_MAX) + pr_err("[SSP]: %s - wrong offset value!!!\n", __func__); + + return iErr; +} + +static ssize_t pressure_cabratioin_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + int iPressureCal = 0, iErr = 0; + + iErr = kstrtoint(buf, 10, &iPressureCal); + if (iErr < 0) { + pr_err("[SSP]: %s - kstrtoint failed.(%d)", __func__, iErr); + return iErr; + } + + if (iPressureCal < PR_ABS_MIN || iPressureCal > PR_ABS_MAX) + return -EINVAL; + + data->iPressureCal = (s32)iPressureCal; + + return size; +} + +static ssize_t pressure_cabratioin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + pressure_open_calibration(data); + + return sprintf(buf, "%d\n", data->iPressureCal); +} + +static ssize_t eeprom_check_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + char chTempBuf[2] = {0, 10}; + int iRet, iDelayCnt = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, PRESSURE_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << PRESSURE_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Pressure Selftest Timeout!!\n", + __func__); + goto exit; + } + + mdelay(5); + + bSuccess = (bool)(!!data->uFactorydata[0]); + ssp_dbg("[SSP]: %s - %u\n", __func__, bSuccess); + +exit: + return snprintf(buf, PAGE_SIZE, "%d", bSuccess); +} + +/* sysfs for vendor & name */ +static ssize_t pressure_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t pressure_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +static DEVICE_ATTR(vendor, S_IRUGO, pressure_vendor_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, pressure_name_show, NULL); +static DEVICE_ATTR(eeprom_check, S_IRUGO, eeprom_check_show, NULL); +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, + pressure_cabratioin_show, pressure_cabratioin_store); +static DEVICE_ATTR(sea_level_pressure, S_IRUGO | S_IWUSR | S_IWGRP, + NULL, sea_level_pressure_store); + +static struct device_attribute *pressure_attrs[] = { + &dev_attr_vendor, + &dev_attr_name, + &dev_attr_calibration, + &dev_attr_sea_level_pressure, + &dev_attr_eeprom_check, + NULL, +}; + +void initialize_pressure_factorytest(struct ssp_data *data) +{ + sensors_register(data->prs_device, data, pressure_attrs, + "barometer_sensor"); +} + +void remove_pressure_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->prs_device, pressure_attrs); +} diff --git a/drivers/sensorhub/atmel/prox_cm36651.c b/drivers/sensorhub/atmel/prox_cm36651.c new file mode 100755 index 00000000000..797261dbd96 --- /dev/null +++ b/drivers/sensorhub/atmel/prox_cm36651.c @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +#define VENDOR "CAPELLA" +#define CHIP_ID "CM36651" + +#define CANCELATION_FILE_PATH "/efs/prox_cal" +#define LCD_LDI_FILE_PATH "/sys/class/lcd/panel/window_type" + +#define LINE_1 '4' +#define LINE_2 '2' + +#define LDI_OTHERS '0' +#define LDI_GRAY '1' +#define LDI_WHITE '2' + +#define CANCELATION_THRESHOLD 9 +#define DEFAULT_THRESHOLD 13 +#define OTHERS_OCTA_DEFAULT_THRESHOLD 14 +#define WHITE_OCTA_DEFAULT_THRESHOLD 13 +#define GRAY_OCTA_DEFAULT_THRESHOLD 12 + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +static ssize_t prox_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t prox_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +static ssize_t proximity_avg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", + data->buf[PROXIMITY_RAW].prox[1], + data->buf[PROXIMITY_RAW].prox[2], + data->buf[PROXIMITY_RAW].prox[3]); +} + +static ssize_t proximity_avg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + char chTempbuf[2] = { 1, 20}; + int iRet; + int64_t dEnable; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtoll(buf, 10, &dEnable); + if (iRet < 0) + return iRet; + + if (dEnable) { + send_instruction(data, ADD_SENSOR, PROXIMITY_RAW, chTempbuf, 2); + data->bProximityRawEnabled = true; + } else { + send_instruction(data, REMOVE_SENSOR, PROXIMITY_RAW, + chTempbuf, 2); + data->bProximityRawEnabled = false; + } + + return size; +} + +static unsigned char get_proximity_rawdata(struct ssp_data *data) +{ + unsigned char uRowdata = 0; + char chTempbuf[2] = { 1, 20}; + + if (data->bProximityRawEnabled == false) { + send_instruction(data, ADD_SENSOR, PROXIMITY_RAW, chTempbuf, 2); + msleep(200); + uRowdata = data->buf[PROXIMITY_RAW].prox[0]; + send_instruction(data, REMOVE_SENSOR, PROXIMITY_RAW, + chTempbuf, 2); + } else { + uRowdata = data->buf[PROXIMITY_RAW].prox[0]; + } + + return uRowdata; +} + +static ssize_t proximity_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", get_proximity_rawdata(data)); +} + +static void change_proximity_default_threshold(struct ssp_data *data) +{ + switch (data->chLcdLdi[1]) { + case LDI_GRAY: + data->uProxHiThresh = GRAY_OCTA_DEFAULT_THRESHOLD; + break; + case LDI_WHITE: + data->uProxHiThresh = WHITE_OCTA_DEFAULT_THRESHOLD; + break; + case LDI_OTHERS: + data->uProxHiThresh = OTHERS_OCTA_DEFAULT_THRESHOLD; + break; + default: + data->uProxHiThresh = DEFAULT_THRESHOLD; + break; + } +} + +int proximity_open_lcd_ldi(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cancel_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cancel_filp)) { + iRet = PTR_ERR(cancel_filp); + if (iRet != -ENOENT) + pr_err("[SSP]: %s - Can't open lcd ldi file\n", + __func__); + set_fs(old_fs); + data->chLcdLdi[0] = 0; + data->chLcdLdi[1] = 0; + goto exit; + } + + iRet = cancel_filp->f_op->read(cancel_filp, + (u8 *)data->chLcdLdi, sizeof(u8) * 2, &cancel_filp->f_pos); + if (iRet != (sizeof(u8) * 2)) { + pr_err("[SSP]: %s - Can't read the lcd ldi data\n", __func__); + iRet = -EIO; + } + + ssp_dbg("[SSP]: %s - %c%c\n", __func__, + data->chLcdLdi[0], data->chLcdLdi[1]); + + filp_close(cancel_filp, current->files); + set_fs(old_fs); + +exit: + change_proximity_default_threshold(data); + return iRet; +} + +int proximity_open_calibration(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cancel_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cancel_filp)) { + iRet = PTR_ERR(cancel_filp); + if (iRet != -ENOENT) + pr_err("[SSP]: %s - Can't open cancelation file\n", + __func__); + set_fs(old_fs); + goto exit; + } + + iRet = cancel_filp->f_op->read(cancel_filp, + (u8 *)&data->uProxCanc, sizeof(u8), &cancel_filp->f_pos); + if (iRet != sizeof(u8)) { + pr_err("[SSP]: %s - Can't read the cancel data\n", __func__); + iRet = -EIO; + } + + if (data->uProxCanc != 0) /* If there is an offset cal data. */ + data->uProxHiThresh = CANCELATION_THRESHOLD; + + pr_info("%s: proximity ps_canc = %d, ps_thresh = %d\n", + __func__, data->uProxCanc, data->uProxHiThresh); + + filp_close(cancel_filp, current->files); + set_fs(old_fs); + +exit: + set_proximity_threshold(data, data->uProxHiThresh, data->uProxCanc); + + return iRet; +} + +static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cancel_filp = NULL; + + if (iCalCMD) { + data->uProxHiThresh = CANCELATION_THRESHOLD; + data->uProxCanc = get_proximity_rawdata(data); + } else { + change_proximity_default_threshold(data); + data->uProxCanc = 0; + } + + set_proximity_threshold(data, data->uProxHiThresh, data->uProxCanc); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(CANCELATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + if (IS_ERR(cancel_filp)) { + pr_err("%s: Can't open cancelation file\n", __func__); + set_fs(old_fs); + iRet = PTR_ERR(cancel_filp); + return iRet; + } + + iRet = cancel_filp->f_op->write(cancel_filp, (u8 *)&data->uProxCanc, + sizeof(u8), &cancel_filp->f_pos); + if (iRet != sizeof(u8)) { + pr_err("%s: Can't write the cancel data to file\n", __func__); + iRet = -EIO; + } + + filp_close(cancel_filp, current->files); + set_fs(old_fs); + + return iRet; +} + +static ssize_t proximity_cancel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: uProxThresh = %u, uProxCanc = %u\n", + data->uProxHiThresh, data->uProxCanc); + + return sprintf(buf, "%u,%u\n", data->uProxCanc, data->uProxHiThresh); +} + +static ssize_t proximity_cancel_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int iCalCMD = 0, iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "1")) /* calibrate cancelation value */ + iCalCMD = 1; + else if (sysfs_streq(buf, "0")) /* reset cancelation value */ + iCalCMD = 0; + else { + pr_debug("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + iRet = proximity_store_cancelation(data, iCalCMD); + if (iRet < 0) { + pr_err("[SSP]: - %s proximity_store_cancelation() failed\n", + __func__); + return iRet; + } + + ssp_dbg("[SSP]: %s - %u\n", __func__, iCalCMD); + return size; +} + +static ssize_t proximity_thresh_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: uProxThresh = %u\n", data->uProxHiThresh); + + return sprintf(buf, "%u\n", data->uProxHiThresh); +} + +static ssize_t proximity_thresh_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 uNewThresh = 0x09; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtou8(buf, 10, &uNewThresh); + if (iRet < 0) + pr_err("[SSP]: %s - kstrtoint failed.", __func__); + + data->uProxHiThresh = uNewThresh; + set_proximity_threshold(data, data->uProxHiThresh, data->uProxCanc); + + ssp_dbg("[SSP]: %s - new prox threshold = 0x%x\n", + __func__, data->uProxHiThresh); + + return size; +} + +static ssize_t barcode_emul_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", data->bBarcodeEnabled); +} + +static ssize_t barcode_emul_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int iRet; + int64_t dEnable; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtoll(buf, 10, &dEnable); + if (iRet < 0) + return iRet; + + if (dEnable) + set_proximity_barcode_enable(data, true); + else + set_proximity_barcode_enable(data, false); + + return size; +} + +static DEVICE_ATTR(vendor, S_IRUGO, prox_vendor_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, prox_name_show, NULL); +static DEVICE_ATTR(state, S_IRUGO, proximity_state_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, proximity_state_show, NULL); +static DEVICE_ATTR(barcode_emul_en, S_IRUGO | S_IWUSR | S_IWGRP, + barcode_emul_enable_show, barcode_emul_enable_store); +static DEVICE_ATTR(prox_avg, S_IRUGO | S_IWUSR | S_IWGRP, + proximity_avg_show, proximity_avg_store); +static DEVICE_ATTR(prox_cal, S_IRUGO | S_IWUSR | S_IWGRP, + proximity_cancel_show, proximity_cancel_store); +static DEVICE_ATTR(prox_thresh, S_IRUGO | S_IWUSR | S_IWGRP, + proximity_thresh_show, proximity_thresh_store); + +static struct device_attribute *prox_attrs[] = { + &dev_attr_vendor, + &dev_attr_name, + &dev_attr_state, + &dev_attr_raw_data, + &dev_attr_prox_avg, + &dev_attr_prox_cal, + &dev_attr_prox_thresh, + &dev_attr_barcode_emul_en, + NULL, +}; + +void initialize_prox_factorytest(struct ssp_data *data) +{ + sensors_register(data->prox_device, data, + prox_attrs, "proximity_sensor"); +} + +void remove_prox_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->prox_device, prox_attrs); +} diff --git a/drivers/sensorhub/atmel/sensors_core.c b/drivers/sensorhub/atmel/sensors_core.c new file mode 100755 index 00000000000..f968df82610 --- /dev/null +++ b/drivers/sensorhub/atmel/sensors_core.c @@ -0,0 +1,107 @@ +/* + * Universal sensors core class + * + * Author : Ryunkyun Park + */ + +#include +#include +#include +#include +#include +#include + +struct class *sensors_class; +static atomic_t sensor_count; + +/* + * Create sysfs interface + */ +static void set_sensor_attr(struct device *dev, + struct device_attribute *attributes[]) +{ + int i; + + for (i = 0; attributes[i] != NULL; i++) + if ((device_create_file(dev, attributes[i])) < 0) + printk(KERN_INFO "[SENSOR CORE] fail device_create_file" + "(dev, attributes[%d])\n", i); +} + +int sensors_register(struct device *dev, void * drvdata, + struct device_attribute *attributes[], char *name) +{ + int ret = 0; + + if (!sensors_class) { + sensors_class = class_create(THIS_MODULE, "sensors"); + if (IS_ERR(sensors_class)) + return PTR_ERR(sensors_class); + } + + dev = device_create(sensors_class, NULL, 0, drvdata, "%s", name); + + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + printk(KERN_ERR "[SENSORS CORE] device_create failed!" + "[%d]\n", ret); + return ret; + } + + set_sensor_attr(dev, attributes); + atomic_inc(&sensor_count); + + return 0; +} +EXPORT_SYMBOL_GPL(sensors_register); + +void sensors_unregister(struct device *dev, + struct device_attribute *attributes[]) +{ + int i; + + for (i = 0; attributes[i] != NULL; i++) + device_remove_file(dev, attributes[i]); +} +EXPORT_SYMBOL_GPL(sensors_unregister); + +void destroy_sensor_class(void) +{ + if (sensors_class) { + class_destroy(sensors_class); + sensors_class = NULL; + } +} +EXPORT_SYMBOL_GPL(destroy_sensor_class); + +static int __init sensors_class_init(void) +{ + printk(KERN_INFO "[SENSORS CORE] sensors_class_init\n"); + sensors_class = class_create(THIS_MODULE, "sensors"); + + if (IS_ERR(sensors_class)) + return PTR_ERR(sensors_class); + + atomic_set(&sensor_count, 0); + sensors_class->dev_uevent = NULL; + + return 0; +} + +static void __exit sensors_class_exit(void) +{ + if (sensors_class) { + class_destroy(sensors_class); + sensors_class = NULL; + } +} + +/* exported for the APM Power driver, APM emulation */ +EXPORT_SYMBOL_GPL(sensors_class); + +subsys_initcall(sensors_class_init); +module_exit(sensors_class_exit); + +MODULE_DESCRIPTION("Universal sensors core class"); +MODULE_AUTHOR("Ryunkyun Park "); +MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/atmel/ssp.h b/drivers/sensorhub/atmel/ssp.h new file mode 100755 index 00000000000..904286884d6 --- /dev/null +++ b/drivers/sensorhub/atmel/ssp.h @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SSP_PRJ_H__ +#define __SSP_PRJ_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB +#include "ssp_sensorhub.h" +#endif + +#define SUCCESS 1 +#define FAIL 0 +#define ERROR -1 + +#define FACTORY_DATA_MAX 39 + +#define SSP_DBG 1 + +#if SSP_DBG +#define SSP_FUNC_DBG 1 + +#define ssp_dbg(dev, format, ...) do { \ + printk(KERN_INFO dev, format, ##__VA_ARGS__); \ + } while (0) +#else +#define ssp_dbg(dev, format, ...) +#endif + +#if SSP_FUNC_DBG +#define func_dbg() do { \ + printk(KERN_INFO "[SSP]: %s\n", __func__); \ + } while (0) +#else +#define func_dbg() +#endif + +#define SSP_SW_RESET_TIME 3000 +#define DEFUALT_POLLING_DELAY (200 * NSEC_PER_MSEC) +#define PROX_AVG_READ_NUM 80 +#define DEFAULT_RETRIES 3 + +/* SSP Binary Type */ +enum { + KERNEL_BINARY = 0, + KERNEL_CRASHED_BINARY, + UMS_BINARY, +}; + +/* Sensor Sampling Time Define */ +enum { + SENSOR_NS_DELAY_FASTEST = 10000000, /* 10msec */ + SENSOR_NS_DELAY_GAME = 20000000, /* 20msec */ + SENSOR_NS_DELAY_UI = 66700000, /* 66.7msec */ + SENSOR_NS_DELAY_NORMAL = 200000000, /* 200msec */ +}; + +enum { + SENSOR_MS_DELAY_FASTEST = 10, /* 10msec */ + SENSOR_MS_DELAY_GAME = 20, /* 20msec */ + SENSOR_MS_DELAY_UI = 66, /* 66.7msec */ + SENSOR_MS_DELAY_NORMAL = 200, /* 200msec */ +}; + +enum { + SENSOR_CMD_DELAY_FASTEST = 0, /* 10msec */ + SENSOR_CMD_DELAY_GAME, /* 20msec */ + SENSOR_CMD_DELAY_UI, /* 66.7msec */ + SENSOR_CMD_DELAY_NORMAL, /* 200msec */ +}; + +/* + * SENSOR_DELAY_SET_STATE + * Check delay set to avoid sending ADD instruction twice + */ +enum { + INITIALIZATION_STATE = 0, + NO_SENSOR_STATE, + ADD_SENSOR_STATE, + RUNNING_SENSOR_STATE, +}; + +/* Gyroscope DPS */ +#define GYROSCOPE_DPS250 250 +#define GYROSCOPE_DPS500 500 +#define GYROSCOPE_DPS2000 2000 + +/* kernel -> ssp manager cmd*/ +#define SSP_LIBRARY_SLEEP_CMD (1 << 5) +#define SSP_LIBRARY_LARGE_DATA_CMD (1 << 6) +#define SSP_LIBRARY_WAKEUP_CMD (1 << 7) + +/* ioctl command */ +#define AKMIO 0xA1 +#define ECS_IOCTL_GET_FUSEROMDATA _IOR(AKMIO, 0x01, unsigned char[3]) +#define ECS_IOCTL_GET_MAGDATA _IOR(AKMIO, 0x02, unsigned char[8]) +#define ECS_IOCTL_GET_ACCDATA _IOR(AKMIO, 0x03, int[3]) + +/* AP -> SSP Instruction */ +#define MSG2SSP_INST_BYPASS_SENSOR_ADD 0xA1 +#define MSG2SSP_INST_BYPASS_SENSOR_REMOVE 0xA2 +#define MSG2SSP_INST_REMOVE_ALL 0xA3 +#define MSG2SSP_INST_CHANGE_DELAY 0xA4 +#define MSG2SSP_INST_SENSOR_SELFTEST 0xA8 +#define MSG2SSP_INST_LIBRARY_ADD 0xB1 +#define MSG2SSP_INST_LIBRARY_REMOVE 0xB2 + +#define MSG2SSP_AP_STT 0xC8 +#define MSG2SSP_AP_STATUS_WAKEUP 0xD1 +#define MSG2SSP_AP_STATUS_SLEEP 0xD2 +#define MSG2SSP_AP_STATUS_RESET 0xD3 +#define MSG2SSP_AP_STATUS_RESUME 0xD5 +#define MSG2SSP_AP_STATUS_SUSPEND 0xD6 + +#define MSG2SSP_AP_WHOAMI 0x0F +#define MSG2SSP_AP_FIRMWARE_REV 0xF0 +#define MSG2SSP_AP_SENSOR_FORMATION 0xF1 +#define MSG2SSP_AP_SENSOR_PROXTHRESHOLD 0xF2 +#define MSG2SSP_AP_SENSOR_BARCODE_EMUL 0xF3 +#define MSG2SSP_AP_SENSOR_SCANNING 0xF4 + +#define MSG2SSP_AP_FUSEROM 0X01 + +/* AP -> SSP Data Protocol Frame Field */ +#define MSG2SSP_SSP_SLEEP 0xC1 +#define MSG2SSP_STS 0xC2 /* Start to Send */ +#define MSG2SSP_RTS 0xC4 /* Ready to Send */ +#define MSG2SSP_STT 0xC8 +#define MSG2SSP_SRM 0xCA /* Start to Read MSG */ +#define MSG2SSP_SSM 0xCB /* Start to Send MSG */ +#define MSG2SSP_SSD 0xCE /* Start to Send Data Type & Length */ +#define MSG2SSP_NO_DATA 0xCF /* There is no data to get from MCU */ + +/* SSP -> AP ACK about write CMD */ +#define MSG_ACK 0x80 /* ACK from SSP to AP */ +#define MSG_NAK 0x70 /* NAK from SSP to AP */ + +#define SSP_INVALID_REVISION 99999 + +/* SSP_INSTRUCTION_CMD */ +enum { + REMOVE_SENSOR = 0, + ADD_SENSOR, + CHANGE_DELAY, + GO_SLEEP, + FACTORY_MODE, + REMOVE_LIBRARY, + ADD_LIBRARY, +}; + +/* SENSOR_TYPE */ +enum { + ACCELEROMETER_SENSOR = 0, + GYROSCOPE_SENSOR, + GEOMAGNETIC_SENSOR, + PRESSURE_SENSOR, + GESTURE_SENSOR, + PROXIMITY_SENSOR, + LIGHT_SENSOR, + PROXIMITY_RAW, + ORIENTATION_SENSOR, + SENSOR_MAX, +}; + +/* SENSOR_FACTORY_MODE_TYPE */ +enum { + ACCELEROMETER_FACTORY = 0, + GYROSCOPE_FACTORY, + GEOMAGNETIC_FACTORY, + PRESSURE_FACTORY, + MCU_FACTORY, + GYROSCOPE_TEMP_FACTORY, + GYROSCOPE_DPS_FACTORY, + MCU_SLEEP_FACTORY, + SENSOR_FACTORY_MAX, +}; + +/* Firmware download STATE */ +enum { + FW_DL_STATE_FAIL = -1, + FW_DL_STATE_NONE = 0, + FW_DL_STATE_NEED_TO_SCHEDULE, + FW_DL_STATE_SCHEDULED, + FW_DL_STATE_DOWNLOADING, + FW_DL_STATE_SYNC, + FW_DL_STATE_DONE, +}; + +struct sensor_value { + union { + struct { + s16 x; + s16 y; + s16 z; + }; + struct { + u16 r; + u16 g; + u16 b; + u16 w; + }; + u8 prox[4]; + s16 data[4]; + s32 pressure[3]; + }; +}; + +struct calibraion_data { + int x; + int y; + int z; +}; + +struct ssp_data { + struct input_dev *acc_input_dev; + struct input_dev *gyro_input_dev; + struct input_dev *pressure_input_dev; + struct input_dev *light_input_dev; + struct input_dev *prox_input_dev; + + struct device *sen_dev; + struct device *mcu_device; + struct device *acc_device; + struct device *gyro_device; + struct device *mag_device; + struct device *prs_device; + struct device *prox_device; + struct device *light_device; + + struct i2c_client *client; + struct wake_lock ssp_wake_lock; + struct miscdevice akmd_device; + struct timer_list debug_timer; + struct workqueue_struct *debug_wq; + struct delayed_work work_firmware; + struct work_struct work_debug; + struct calibraion_data accelcal; + struct calibraion_data gyrocal; + struct sensor_value buf[SENSOR_MAX]; + + bool bSspShutdown; + bool bCheckSuspend; + bool bDebugEnabled; + bool bMcuIRQTestSuccessed; + bool bAccelAlert; + bool bProximityRawEnabled; + bool bBarcodeEnabled; + + unsigned char uProxCanc; + unsigned char uProxHiThresh; + unsigned char uProxLoThresh; + unsigned char uFuseRomData[3]; + unsigned char uFactorydata[FACTORY_DATA_MAX]; + char *pchLibraryBuf; + char chLcdLdi[2]; + int iIrq; + int iLibraryLength; + int aiCheckStatus[SENSOR_MAX]; + int fw_dl_state; + + unsigned int uIrqFailCnt; + unsigned int uSsdFailCnt; + unsigned int uResetCnt; + unsigned int uInstFailCnt; + unsigned int uTimeOutCnt; + unsigned int uIrqCnt; + unsigned int uBusyCnt; + unsigned int uMissSensorCnt; + + unsigned int uGyroDps; + unsigned int uSensorState; + unsigned int uCurFirmRev; + unsigned int uFactoryProxAvg[4]; + unsigned int uFactorydataReady; + s32 iPressureCal; + + atomic_t aSensorEnable; + int64_t adDelayBuf[SENSOR_MAX]; + + int (*wakeup_mcu)(void); + int (*check_mcu_ready)(void); + int (*check_mcu_busy)(void); + int (*set_mcu_reset)(int); + int (*check_ap_rev)(void); + void (*get_sensor_data[SENSOR_MAX])(char *, int *, + struct sensor_value *); + void (*report_sensor_data[SENSOR_MAX])(struct ssp_data *, + struct sensor_value *); + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + struct ssp_sensorhub_data *hub_data; +#endif +}; + +int waiting_wakeup_mcu(struct ssp_data *); +int ssp_i2c_read(struct ssp_data *, char *, u16, char *, u16, int); +void toggle_mcu_reset(struct ssp_data *); +int initialize_mcu(struct ssp_data *); +int initialize_input_dev(struct ssp_data *); +int initialize_sysfs(struct ssp_data *); +void initialize_accel_factorytest(struct ssp_data *); +void initialize_prox_factorytest(struct ssp_data *); +void initialize_light_factorytest(struct ssp_data *); +void initialize_gyro_factorytest(struct ssp_data *); +void initialize_pressure_factorytest(struct ssp_data *); +void initialize_magnetic_factorytest(struct ssp_data *); +void initialize_function_pointer(struct ssp_data *); +void initialize_magnetic(struct ssp_data *); +void remove_accel_factorytest(struct ssp_data *); +void remove_gyro_factorytest(struct ssp_data *); +void remove_prox_factorytest(struct ssp_data *); +void remove_light_factorytest(struct ssp_data *); +void remove_pressure_factorytest(struct ssp_data *); +void remove_magnetic_factorytest(struct ssp_data *); +void destroy_sensor_class(void); +int initialize_event_symlink(struct ssp_data *); +int accel_open_calibration(struct ssp_data *); +int gyro_open_calibration(struct ssp_data *); +int pressure_open_calibration(struct ssp_data *); +int proximity_open_calibration(struct ssp_data *); +int check_fwbl(struct ssp_data *); +void remove_input_dev(struct ssp_data *); +void remove_sysfs(struct ssp_data *); +void remove_event_symlink(struct ssp_data *); +int ssp_send_status_cmd(struct ssp_data *, char); +int send_instruction(struct ssp_data *, u8, u8, u8 *, u8); +int select_irq_msg(struct ssp_data *); +int get_chipid(struct ssp_data *); +int get_fuserom_data(struct ssp_data *); +int set_sensor_position(struct ssp_data *); +void sync_sensor_state(struct ssp_data *); +void set_proximity_threshold(struct ssp_data *, unsigned char, unsigned char); +void set_proximity_barcode_enable(struct ssp_data *, bool); +unsigned int get_delay_cmd(u8); +unsigned int get_msdelay(int64_t); +unsigned int get_sensor_scanning_info(struct ssp_data *); +unsigned int get_firmware_rev(struct ssp_data *); +int forced_to_download_binary(struct ssp_data *, int); +int parse_dataframe(struct ssp_data *, char *, int); +void enable_debug_timer(struct ssp_data *); +void disable_debug_timer(struct ssp_data *); +int initialize_debug_timer(struct ssp_data *); +int proximity_open_lcd_ldi(struct ssp_data *); +void report_acc_data(struct ssp_data *, struct sensor_value *); +void report_gyro_data(struct ssp_data *, struct sensor_value *); +void report_mag_data(struct ssp_data *, struct sensor_value *); +void report_gesture_data(struct ssp_data *, struct sensor_value *); +void report_pressure_data(struct ssp_data *, struct sensor_value *); +void report_light_data(struct ssp_data *, struct sensor_value *); +void report_prox_data(struct ssp_data *, struct sensor_value *); +void report_prox_raw_data(struct ssp_data *, struct sensor_value *); +int print_mcu_debug(char *, int *, int); +unsigned int get_module_rev(void); +void reset_mcu(struct ssp_data *); +void convert_acc_data(s16 *); +int sensors_register(struct device *, void *, + struct device_attribute*[], char *); +void sensors_unregister(struct device *, struct device_attribute*[]); +ssize_t mcu_reset_show(struct device *, struct device_attribute *, char *); +ssize_t mcu_revision_show(struct device *, struct device_attribute *, char *); +ssize_t mcu_update_ums_bin_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_update_kernel_bin_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_update_kernel_crashed_bin_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_factorytest_store(struct device *, struct device_attribute *, + const char *, size_t); +ssize_t mcu_factorytest_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_model_name_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_sleep_factorytest_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_sleep_factorytest_store(struct device *, + struct device_attribute *, const char *, size_t); + +#endif diff --git a/drivers/sensorhub/atmel/ssp_ak8963c.c b/drivers/sensorhub/atmel/ssp_ak8963c.c new file mode 100755 index 00000000000..00a4f7dffca --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_ak8963c.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* AKM Daemon Library ioctl */ +/*************************************************************************/ + +static int akmd_copy_in(unsigned int cmd, void __user *argp, + void *buf, size_t buf_size) +{ + if (!(cmd & IOC_IN)) + return 0; + if (_IOC_SIZE(cmd) > buf_size) + return -EINVAL; + if (copy_from_user(buf, argp, _IOC_SIZE(cmd))) + return -EFAULT; + return 0; +} + +static int akmd_copy_out(unsigned int cmd, void __user *argp, + void *buf, size_t buf_size) +{ + if (!(cmd & IOC_OUT)) + return 0; + if (_IOC_SIZE(cmd) > buf_size) + return -EINVAL; + if (copy_to_user(argp, buf, _IOC_SIZE(cmd))) + return -EFAULT; + return 0; +} + +static long akmd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int iRet; + void __user *argp = (void __user *)arg; + struct ssp_data *data = container_of(file->private_data, + struct ssp_data, akmd_device); + + union { + u8 uData[8]; + u8 uMagData[8]; + u8 uFuseData[3]; + int iAccData[3]; + } akmdbuf; + + iRet = akmd_copy_in(cmd, argp, akmdbuf.uData, sizeof(akmdbuf)); + if (iRet) + return iRet; + + switch (cmd) { + case ECS_IOCTL_GET_MAGDATA: + if ((data->buf[GEOMAGNETIC_SENSOR].x == 0) + && (data->buf[GEOMAGNETIC_SENSOR].y == 0) + && (data->buf[GEOMAGNETIC_SENSOR].z == 0)) + akmdbuf.uMagData[0] = 0; + else + akmdbuf.uMagData[0] = 1; + + akmdbuf.uMagData[1] = data->buf[GEOMAGNETIC_SENSOR].x & 0xff; + akmdbuf.uMagData[2] = data->buf[GEOMAGNETIC_SENSOR].x >> 8; + akmdbuf.uMagData[3] = data->buf[GEOMAGNETIC_SENSOR].y & 0xff; + akmdbuf.uMagData[4] = data->buf[GEOMAGNETIC_SENSOR].y >> 8; + akmdbuf.uMagData[5] = data->buf[GEOMAGNETIC_SENSOR].z & 0xff; + akmdbuf.uMagData[6] = data->buf[GEOMAGNETIC_SENSOR].z >> 8; + akmdbuf.uMagData[7] = 0x10; + break; + case ECS_IOCTL_GET_ACCDATA: + akmdbuf.iAccData[0] = data->buf[ACCELEROMETER_SENSOR].x; + akmdbuf.iAccData[1] = data->buf[ACCELEROMETER_SENSOR].y; + akmdbuf.iAccData[2] = data->buf[ACCELEROMETER_SENSOR].z; + break; + case ECS_IOCTL_GET_FUSEROMDATA: + akmdbuf.uFuseData[0] = data->uFuseRomData[0]; + akmdbuf.uFuseData[1] = data->uFuseRomData[1]; + akmdbuf.uFuseData[2] = data->uFuseRomData[2]; + break; + default: + return -ENOTTY; + } + + if (iRet < 0) + return iRet; + + return akmd_copy_out(cmd, argp, akmdbuf.uData, sizeof(akmdbuf)); +} + +static const struct file_operations akmd_fops = { + .owner = THIS_MODULE, + .open = nonseekable_open, + .unlocked_ioctl = akmd_ioctl, +}; + +void initialize_magnetic(struct ssp_data *data) +{ + data->akmd_device.minor = MISC_DYNAMIC_MINOR; + data->akmd_device.name = "akm8963"; + data->akmd_device.fops = &akmd_fops; +} diff --git a/drivers/sensorhub/atmel/ssp_data.c b/drivers/sensorhub/atmel/ssp_data.c new file mode 100755 index 00000000000..09d5c099ac6 --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_data.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/* SSP -> AP Instruction */ +#define MSG2AP_INST_BYPASS_DATA 0x00 +#define MSG2AP_INST_LIBRARY_DATA 0x01 +#define MSG2AP_INST_SELFTEST_DATA 0x02 +#define MSG2AP_INST_DEBUG_DATA 0x03 + +/* Factory data length */ +#define ACCEL_FACTORY_DATA_LENGTH 1 +#define GYRO_FACTORY_DATA_LENGTH 27 +#define MAGNETIC_FACTORY_DATA_LENGTH 6 +#define PRESSURE_FACTORY_DATA_LENGTH 1 +#define MCU_FACTORY_DATA_LENGTH 5 +#define GYRO_TEMP_FACTORY_DATA_LENGTH 1 +#define GYRO_DPS_FACTORY_DATA_LENGTH 1 +#define MCU_SLEEP_FACTORY_DATA_LENGTH 39 + +/*************************************************************************/ +/* SSP parsing the dataframe */ +/*************************************************************************/ + +static void get_3axis_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + int iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->x = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->y = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->z = iTemp; +} + +static void get_light_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + int iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->r = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->g = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->b = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->w = iTemp; +} + +static void get_pressure_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + int iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 16; + sensorsdata->pressure[0] = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + sensorsdata->pressure[0] += iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->pressure[0] += iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += (int)pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->pressure[1] = (s16)iTemp; +} + +static void get_gesture_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + int iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->data[0] = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->data[1] = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->data[2] = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->data[3] = iTemp; +} + +static void get_proximity_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + sensorsdata->prox[0] = (u8)pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->prox[1] = (u8)pchRcvDataFrame[(*iDataIdx)++]; +} + +static void get_proximity_rawdata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + sensorsdata->prox[0] = (u8)pchRcvDataFrame[(*iDataIdx)++]; +} + +static void get_factoty_data(struct ssp_data *data, int iSensorData, + char *pchRcvDataFrame, int *iDataIdx) +{ + int iIdx, iTotalLenth = 0; + unsigned int uTemp = 0; + + switch (iSensorData) { + case ACCELEROMETER_FACTORY: + uTemp = (1 << ACCELEROMETER_FACTORY); + iTotalLenth = ACCEL_FACTORY_DATA_LENGTH; + break; + case GYROSCOPE_FACTORY: + uTemp = (1 << GYROSCOPE_FACTORY); + iTotalLenth = GYRO_FACTORY_DATA_LENGTH; + break; + case GEOMAGNETIC_FACTORY: + uTemp = (1 << GEOMAGNETIC_FACTORY); + iTotalLenth = MAGNETIC_FACTORY_DATA_LENGTH; + break; + case PRESSURE_FACTORY: + uTemp = (1 << PRESSURE_FACTORY); + iTotalLenth = PRESSURE_FACTORY_DATA_LENGTH; + break; + case MCU_FACTORY: + uTemp = (1 << MCU_FACTORY); + iTotalLenth = MCU_FACTORY_DATA_LENGTH; + break; + case GYROSCOPE_TEMP_FACTORY: + uTemp = (1 << GYROSCOPE_TEMP_FACTORY); + iTotalLenth = GYRO_TEMP_FACTORY_DATA_LENGTH; + break; + case GYROSCOPE_DPS_FACTORY: + uTemp = (1 << GYROSCOPE_DPS_FACTORY); + iTotalLenth = GYRO_DPS_FACTORY_DATA_LENGTH; + break; + case MCU_SLEEP_FACTORY: + uTemp = (1 << MCU_SLEEP_FACTORY); + iTotalLenth = MCU_SLEEP_FACTORY_DATA_LENGTH; + break; + } + + ssp_dbg("[SSP]: %s - Factory test data %d\n", __func__, iSensorData); + for (iIdx = 0; iIdx < iTotalLenth; iIdx++) + data->uFactorydata[iIdx] = (u8)pchRcvDataFrame[(*iDataIdx)++]; + + data->uFactorydataReady = uTemp; +} + +int parse_dataframe(struct ssp_data *data, char *pchRcvDataFrame, int iLength) +{ + int iDataIdx, iSensorData; + struct sensor_value *sensorsdata; + + sensorsdata = kzalloc(sizeof(*sensorsdata), GFP_KERNEL); + if (sensorsdata == NULL) + return ERROR; + + for (iDataIdx = 0; iDataIdx < iLength;) { + if (pchRcvDataFrame[iDataIdx] == MSG2AP_INST_BYPASS_DATA) { + iDataIdx++; + iSensorData = pchRcvDataFrame[iDataIdx++]; + if ((iSensorData < 0) || + (iSensorData >= (SENSOR_MAX - 1))) { + pr_err("[SSP]: %s - Mcu data frame1 error %d\n", + __func__, iSensorData); + kfree(sensorsdata); + return ERROR; + } + + data->get_sensor_data[iSensorData](pchRcvDataFrame, + &iDataIdx, sensorsdata); + data->report_sensor_data[iSensorData](data, + sensorsdata); + } else if (pchRcvDataFrame[iDataIdx] == + MSG2AP_INST_SELFTEST_DATA) { + iDataIdx++; + iSensorData = pchRcvDataFrame[iDataIdx++]; + if ((iSensorData < 0) || + (iSensorData >= SENSOR_FACTORY_MAX)) { + pr_err("[SSP]: %s - Mcu data frame2 error %d\n", + __func__, iSensorData); + kfree(sensorsdata); + return ERROR; + } + get_factoty_data(data, iSensorData, pchRcvDataFrame, + &iDataIdx); + } else if (pchRcvDataFrame[iDataIdx] == + MSG2AP_INST_DEBUG_DATA) { + iSensorData + = print_mcu_debug(pchRcvDataFrame + iDataIdx+1, + &iDataIdx, iLength); + if (iSensorData) { + pr_err("[SSP]: %s - Mcu data frame3 error %d\n", + __func__, iSensorData); + kfree(sensorsdata); + return ERROR; + } +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + } else if (pchRcvDataFrame[iDataIdx] == + MSG2AP_INST_LIBRARY_DATA) { + ssp_sensorhub_handle_data(data, + pchRcvDataFrame, iDataIdx, iLength); + break; +#endif + } else + iDataIdx++; + } + kfree(sensorsdata); + return SUCCESS; +} + +void initialize_function_pointer(struct ssp_data *data) +{ + data->get_sensor_data[ACCELEROMETER_SENSOR] = get_3axis_sensordata; + data->get_sensor_data[GYROSCOPE_SENSOR] = get_3axis_sensordata; + data->get_sensor_data[GEOMAGNETIC_SENSOR] = get_3axis_sensordata; + data->get_sensor_data[PRESSURE_SENSOR] = get_pressure_sensordata; + data->get_sensor_data[GESTURE_SENSOR] = get_gesture_sensordata; + data->get_sensor_data[PROXIMITY_SENSOR] = get_proximity_sensordata; + data->get_sensor_data[PROXIMITY_RAW] = get_proximity_rawdata; + data->get_sensor_data[LIGHT_SENSOR] = get_light_sensordata; + + data->report_sensor_data[ACCELEROMETER_SENSOR] = report_acc_data; + data->report_sensor_data[GYROSCOPE_SENSOR] = report_gyro_data; + data->report_sensor_data[GEOMAGNETIC_SENSOR] = report_mag_data; + data->report_sensor_data[PRESSURE_SENSOR] = report_pressure_data; + data->report_sensor_data[GESTURE_SENSOR] = report_gesture_data; + data->report_sensor_data[PROXIMITY_SENSOR] = report_prox_data; + data->report_sensor_data[PROXIMITY_RAW] = report_prox_raw_data; + data->report_sensor_data[LIGHT_SENSOR] = report_light_data; +} diff --git a/drivers/sensorhub/atmel/ssp_debug.c b/drivers/sensorhub/atmel/ssp_debug.c new file mode 100755 index 00000000000..1e127675b7b --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_debug.c @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +#define SSP_DEBUG_TIMER_SEC (10 * HZ) + +#define LIMIT_RESET_CNT 20 +#define LIMIT_SSD_FAIL_CNT 3 +#define LIMIT_INSTRUCTION_FAIL_CNT 1 +#define LIMIT_IRQ_FAIL_CNT 2 +#define LIMIT_TIMEOUT_CNT 5 + +/*************************************************************************/ +/* SSP Debug timer function */ +/*************************************************************************/ + +int print_mcu_debug(char *pchRcvDataFrame, int *pDataIdx, + int iRcvDataFrameLength) +{ + int iLength = pchRcvDataFrame[0]; + + if (iLength >= iRcvDataFrameLength - *pDataIdx - 1 || iLength <= 0) { + ssp_dbg("[SSP]: MSG From MCU - invalid debug length(%d/%d)\n", + iLength, iRcvDataFrameLength); + return iLength ? iLength : ERROR; + } + + pchRcvDataFrame[iLength] = 0; + *pDataIdx += iLength + 2; + ssp_dbg("[SSP]: MSG From MCU - %s\n", pchRcvDataFrame + 1); + + return 0; +} + +void reset_mcu(struct ssp_data *data) +{ + if (data->bSspShutdown == false) { + data->bSspShutdown = true; + disable_irq_wake(data->iIrq); + disable_irq(data->iIrq); + } + + toggle_mcu_reset(data); + msleep(SSP_SW_RESET_TIME); + data->bSspShutdown = false; + + if (initialize_mcu(data) < 0) + return; + + if (data->bSspShutdown == true) { + data->bSspShutdown = false; + enable_irq(data->iIrq); + enable_irq_wake(data->iIrq); + } + + sync_sensor_state(data); + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_RESET); +#endif +} + +void sync_sensor_state(struct ssp_data *data) +{ + unsigned char uBuf[2] = {0,}; + unsigned int uSensorCnt; + + proximity_open_calibration(data); + + udelay(10); + + for (uSensorCnt = 0; uSensorCnt < (SENSOR_MAX - 1); uSensorCnt++) { + if (atomic_read(&data->aSensorEnable) & (1 << uSensorCnt)) { + uBuf[1] = (u8)get_msdelay(data->adDelayBuf[uSensorCnt]); + uBuf[0] = (u8)get_delay_cmd(uBuf[1]); + send_instruction(data, ADD_SENSOR, uSensorCnt, uBuf, 2); + udelay(10); + } + } + + if (data->bProximityRawEnabled == true) { + uBuf[0] = 1; + uBuf[1] = 20; + send_instruction(data, ADD_SENSOR, PROXIMITY_RAW, uBuf, 2); + } +} + +static void print_sensordata(struct ssp_data *data, unsigned int uSensor) +{ + switch (uSensor) { + case ACCELEROMETER_SENSOR: + case GYROSCOPE_SENSOR: + case GEOMAGNETIC_SENSOR: + ssp_dbg(" %u : %d, %d, %d (%ums)\n", uSensor, + data->buf[uSensor].x, data->buf[uSensor].y, + data->buf[uSensor].z, + get_msdelay(data->adDelayBuf[uSensor])); + break; + case LIGHT_SENSOR: + ssp_dbg(" %u : %u, %u, %u, %u (%ums)\n", uSensor, + data->buf[uSensor].r, data->buf[uSensor].g, + data->buf[uSensor].b, data->buf[uSensor].w, + get_msdelay(data->adDelayBuf[uSensor])); + break; + case PRESSURE_SENSOR: + ssp_dbg(" %u : %d, %d (%ums)\n", uSensor, + data->buf[uSensor].pressure[0], + data->buf[uSensor].pressure[1], + get_msdelay(data->adDelayBuf[uSensor])); + break; + case GESTURE_SENSOR: + ssp_dbg(" %u : %d %d %d %d (%ums)\n", uSensor, + data->buf[uSensor].data[0], data->buf[uSensor].data[1], + data->buf[uSensor].data[2], data->buf[uSensor].data[3], + get_msdelay(data->adDelayBuf[uSensor])); + break; + case PROXIMITY_SENSOR: + ssp_dbg(" %u : %d %d(%ums)\n", uSensor, + data->buf[uSensor].prox[0], data->buf[uSensor].prox[1], + get_msdelay(data->adDelayBuf[uSensor])); + } +} + +static void debug_work_func(struct work_struct *work) +{ + unsigned int uSensorCnt; + struct ssp_data *data = container_of(work, struct ssp_data, work_debug); + + ssp_dbg("[SSP]: %s(%u) - Sensor state: 0x%x, RC: %u, MS: %u\n", + __func__, data->uIrqCnt, data->uSensorState, data->uResetCnt, + data->uMissSensorCnt); + + for (uSensorCnt = 0; uSensorCnt < (SENSOR_MAX - 1); uSensorCnt++) + if (atomic_read(&data->aSensorEnable) & (1 << uSensorCnt)) + print_sensordata(data, uSensorCnt); + + if (data->fw_dl_state >= FW_DL_STATE_DOWNLOADING && + data->fw_dl_state < FW_DL_STATE_DONE) { + pr_info("[SSP] : %s firmware downloading state = %d\n", + __func__, data->fw_dl_state); + return; + } else if (data->fw_dl_state == FW_DL_STATE_FAIL) { + pr_err("[SSP] : %s firmware download failed = %d\n", + __func__, data->fw_dl_state); + return; + } + + if ((atomic_read(&data->aSensorEnable) & 0x4f) && (data->uIrqCnt == 0)) + data->uIrqFailCnt++; + else + data->uIrqFailCnt = 0; + + if (((data->uSsdFailCnt >= LIMIT_SSD_FAIL_CNT) + || (data->uInstFailCnt >= LIMIT_INSTRUCTION_FAIL_CNT) + || (data->uIrqFailCnt >= LIMIT_IRQ_FAIL_CNT) + || ((data->uTimeOutCnt + data->uBusyCnt) > LIMIT_TIMEOUT_CNT)) + && (data->bSspShutdown == false)) { + + if (data->uResetCnt < LIMIT_RESET_CNT) { + reset_mcu(data); + data->uResetCnt++; + } else { + if (data->bSspShutdown == false) { + data->bSspShutdown = true; + disable_irq_wake(data->iIrq); + disable_irq(data->iIrq); + } + } + + data->uSsdFailCnt = 0; + data->uInstFailCnt = 0; + data->uTimeOutCnt = 0; + data->uBusyCnt = 0; + data->uIrqFailCnt = 0; + } + + data->uIrqCnt = 0; +} + +static void debug_timer_func(unsigned long ptr) +{ + struct ssp_data *data = (struct ssp_data *)ptr; + + queue_work(data->debug_wq, &data->work_debug); + mod_timer(&data->debug_timer, + round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC)); +} + +void enable_debug_timer(struct ssp_data *data) +{ + mod_timer(&data->debug_timer, + round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC)); +} + +void disable_debug_timer(struct ssp_data *data) +{ + del_timer_sync(&data->debug_timer); + cancel_work_sync(&data->work_debug); +} + +int initialize_debug_timer(struct ssp_data *data) +{ + setup_timer(&data->debug_timer, debug_timer_func, (unsigned long)data); + + data->debug_wq = create_singlethread_workqueue("ssp_debug_wq"); + if (!data->debug_wq) + return ERROR; + + INIT_WORK(&data->work_debug, debug_work_func); + return SUCCESS; +} diff --git a/drivers/sensorhub/atmel/ssp_dev.c b/drivers/sensorhub/atmel/ssp_dev.c new file mode 100755 index 00000000000..852358b6f61 --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_dev.c @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/* ssp mcu device ID */ +#define DEVICE_ID 0x55 + +static void ssp_early_suspend(struct early_suspend *handler); +static void ssp_late_resume(struct early_suspend *handler); + +/************************************************************************/ +/* interrupt happened due to transition/change of SSP MCU */ +/************************************************************************/ + +static irqreturn_t sensordata_irq_thread_fn(int iIrq, void *dev_id) +{ + struct ssp_data *data = dev_id; + + select_irq_msg(data); + data->uIrqCnt++; + + return IRQ_HANDLED; +} + +/*************************************************************************/ +/* initialize sensor hub */ +/*************************************************************************/ + +static void initialize_variable(struct ssp_data *data) +{ + int iSensorIndex; + + for (iSensorIndex = 0; iSensorIndex < SENSOR_MAX; iSensorIndex++) { + data->adDelayBuf[iSensorIndex] = DEFUALT_POLLING_DELAY; + data->aiCheckStatus[iSensorIndex] = INITIALIZATION_STATE; + } + + /* AKM Daemon Library */ + data->aiCheckStatus[GEOMAGNETIC_SENSOR] = NO_SENSOR_STATE; + data->aiCheckStatus[ORIENTATION_SENSOR] = NO_SENSOR_STATE; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + atomic_set(&data->aSensorEnable, 0); + data->iLibraryLength = 0; + data->uSensorState = 0; + data->uFactorydataReady = 0; + data->uFactoryProxAvg[0] = 0; + + data->uResetCnt = 0; + data->uInstFailCnt = 0; + data->uTimeOutCnt = 0; + data->uSsdFailCnt = 0; + data->uBusyCnt = 0; + data->uIrqCnt = 0; + data->uIrqFailCnt = 0; + data->uMissSensorCnt = 0; + + data->bCheckSuspend = false; + data->bSspShutdown = false; + data->bDebugEnabled = false; + data->bProximityRawEnabled = false; + data->bMcuIRQTestSuccessed = false; + data->bBarcodeEnabled = false; + data->bAccelAlert = false; + + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + + data->gyrocal.x = 0; + data->gyrocal.y = 0; + data->gyrocal.z = 0; + + data->iPressureCal = 0; + data->uProxCanc = 0; + data->uProxHiThresh = 0; + data->uProxLoThresh = 0; + data->uGyroDps = GYROSCOPE_DPS500; + + data->mcu_device = NULL; + data->acc_device = NULL; + data->gyro_device = NULL; + data->mag_device = NULL; + data->prs_device = NULL; + data->prox_device = NULL; + data->light_device = NULL; + + initialize_function_pointer(data); +} + +int initialize_mcu(struct ssp_data *data) +{ + int iRet = 0; + + data->bSspShutdown = false; + iRet = get_chipid(data); + pr_info("[SSP] MCU device ID = %d, reading ID = %d\n", DEVICE_ID, iRet); + if (iRet != DEVICE_ID) { + if (iRet < 0) { + pr_err("[SSP]: %s - MCU is not working : 0x%x\n", + __func__, iRet); + } else { + pr_err("[SSP]: %s - MCU identification failed\n", + __func__); + iRet = -ENODEV; + } + goto out; + } + + iRet = set_sensor_position(data); + if (iRet < 0) { + pr_err("[SSP]: %s - set_sensor_position failed\n", __func__); + goto out; + } + + data->uSensorState = get_sensor_scanning_info(data); + if (data->uSensorState == 0) { + pr_err("[SSP]: %s - get_sensor_scanning_info failed\n", + __func__); + iRet = ERROR; + goto out; + } + + iRet = get_fuserom_data(data); + if (iRet < 0) + pr_err("[SSP]: %s - get_fuserom_data failed\n", __func__); + + iRet = SUCCESS; +out: + data->bSspShutdown = true; + return iRet; +} + +static int initialize_irq(struct ssp_data *data) +{ + int iRet, iIrq; + + iRet = gpio_request(data->client->irq, "mpu_ap_int1"); + if (iRet < 0) { + pr_err("[SSP]: %s - gpio %d request failed (%d)\n", + __func__, data->client->irq, iRet); + return iRet; + } + + iRet = gpio_direction_input(data->client->irq); + if (iRet < 0) { + pr_err("[SSP]: %s - failed to set gpio %d as input (%d)\n", + __func__, data->client->irq, iRet); + goto err_irq_direction_input; + } + + iIrq = gpio_to_irq(data->client->irq); + + pr_info("[SSP]: requesting IRQ %d\n", iIrq); + iRet = request_threaded_irq(iIrq, NULL, sensordata_irq_thread_fn, + IRQF_TRIGGER_FALLING, "SSP_Int", data); + if (iRet < 0) { + pr_err("[SSP]: %s - request_irq(%d) failed for gpio %d (%d)\n", + __func__, iIrq, iIrq, iRet); + goto err_request_irq; + } + + /* start with interrupts disabled */ + data->iIrq = iIrq; + disable_irq(data->iIrq); + return 0; + +err_request_irq: +err_irq_direction_input: + gpio_free(data->client->irq); + return iRet; +} + +static void work_function_firmware_update(struct work_struct *work) +{ + struct ssp_data *data = container_of((struct delayed_work *)work, + struct ssp_data, work_firmware); + int iRet = 0; + + pr_info("[SSP] : %s\n", __func__); + + iRet = forced_to_download_binary(data, KERNEL_BINARY); + if (iRet < 0) { + ssp_dbg("[SSP]: %s - forced_to_download_binary failed!\n", + __func__); + return; + } + + data->uCurFirmRev = get_firmware_rev(data); + pr_info("[SSP] MCU Firm Rev : New = %8u\n", data->uCurFirmRev); +} + +static int ssp_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + int iRet = 0; + struct ssp_data *data; + struct ssp_platform_data *pdata = client->dev.platform_data; + + if (pdata == NULL) { + pr_err("[SSP]: %s - platform_data is null..\n", __func__); + iRet = -ENOMEM; + goto exit; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL) { + pr_err("[SSP]: %s - failed to allocate memory for data\n", + __func__); + iRet = -ENOMEM; + goto exit; + } + + data->fw_dl_state = FW_DL_STATE_NONE; + data->client = client; + i2c_set_clientdata(client, data); + + data->wakeup_mcu = pdata->wakeup_mcu; + data->check_mcu_ready = pdata->check_mcu_ready; + data->check_mcu_busy = pdata->check_mcu_busy; + data->set_mcu_reset = pdata->set_mcu_reset; + data->check_ap_rev = pdata->check_ap_rev; + + if ((data->wakeup_mcu == NULL) + || (data->check_mcu_ready == NULL) + || (data->check_mcu_busy == NULL) + || (data->set_mcu_reset == NULL) + || (data->check_ap_rev == NULL)) { + pr_err("[SSP]: %s - function callback is null\n", __func__); + iRet = -EIO; + goto err_reset_null; + } + + pr_info("\n#####################################################\n"); + INIT_DELAYED_WORK(&data->work_firmware, work_function_firmware_update); + + /* check boot loader binary */ + data->fw_dl_state = check_fwbl(data); + + initialize_variable(data); + + if (data->fw_dl_state == FW_DL_STATE_NONE) { + iRet = initialize_mcu(data); + if (iRet == ERROR) { + data->uResetCnt++; + toggle_mcu_reset(data); + msleep(SSP_SW_RESET_TIME); + initialize_mcu(data); + } else if (iRet < ERROR) { + pr_err("[SSP]: %s - initialize_mcu failed\n", __func__); + goto err_read_reg; + } + } + + wake_lock_init(&data->ssp_wake_lock, + WAKE_LOCK_SUSPEND, "ssp_wake_lock"); + + iRet = initialize_input_dev(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create input device\n", __func__); + goto err_input_register_device; + } + + initialize_magnetic(data); + + iRet = misc_register(&data->akmd_device); + if (iRet) + goto err_akmd_device_register; + + iRet = initialize_debug_timer(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create workqueue\n", __func__); + goto err_create_workqueue; + } + + iRet = initialize_irq(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create irq\n", __func__); + goto err_setup_irq; + } + + iRet = initialize_sysfs(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create sysfs\n", __func__); + goto err_sysfs_create; + } + + iRet = initialize_event_symlink(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create symlink\n", __func__); + goto err_symlink_create; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.suspend = ssp_early_suspend; + data->early_suspend.resume = ssp_late_resume; + register_early_suspend(&data->early_suspend); +#endif + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + /* init sensorhub device */ + iRet = ssp_sensorhub_initialize(data); + if (iRet < 0) { + pr_err("%s: ssp_sensorhub_initialize err(%d)", __func__, iRet); + ssp_sensorhub_remove(data); + } +#endif + + data->bSspShutdown = false; + enable_irq(data->iIrq); + enable_irq_wake(data->iIrq); + pr_info("[SSP]: %s - probe success!\n", __func__); + + enable_debug_timer(data); + + iRet = 0; + + if (data->fw_dl_state == FW_DL_STATE_NEED_TO_SCHEDULE) { + pr_info("[SSP]: Firmware update is scheduled\n"); + schedule_delayed_work(&data->work_firmware, + msecs_to_jiffies(3000)); + data->fw_dl_state = FW_DL_STATE_SCHEDULED; + } else if (data->fw_dl_state == FW_DL_STATE_FAIL) + data->bSspShutdown = true; + + goto exit; + +err_symlink_create: + remove_sysfs(data); +err_sysfs_create: + free_irq(data->iIrq, data); + gpio_free(data->client->irq); +err_setup_irq: + destroy_workqueue(data->debug_wq); +err_create_workqueue: + misc_deregister(&data->akmd_device); +err_akmd_device_register: + remove_input_dev(data); +err_input_register_device: + wake_lock_destroy(&data->ssp_wake_lock); +err_read_reg: +err_reset_null: + kfree(data); + pr_err("[SSP]: %s - probe failed!\n", __func__); +exit: + pr_info("#####################################################\n\n"); + return iRet; +} + +static void ssp_shutdown(struct i2c_client *client) +{ + struct ssp_data *data = i2c_get_clientdata(client); + + func_dbg(); + + if (data->fw_dl_state >= FW_DL_STATE_SCHEDULED && + data->fw_dl_state < FW_DL_STATE_DONE) { + pr_err("%s, cancel_delayed_work_sync state = %d\n", + __func__, data->fw_dl_state); + cancel_delayed_work_sync(&data->work_firmware); + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&data->early_suspend); +#endif + + disable_debug_timer(data); + if (data->bSspShutdown == false) { + data->bSspShutdown = true; + disable_irq_wake(data->iIrq); + disable_irq(data->iIrq); + } + + free_irq(data->iIrq, data); + gpio_free(data->client->irq); + + remove_sysfs(data); + remove_event_symlink(data); + remove_input_dev(data); + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + ssp_sensorhub_remove(data); +#endif + + misc_deregister(&data->akmd_device); + + del_timer_sync(&data->debug_timer); + cancel_work_sync(&data->work_debug); + destroy_workqueue(data->debug_wq); + wake_lock_destroy(&data->ssp_wake_lock); + + toggle_mcu_reset(data); + + kfree(data); +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ssp_early_suspend(struct early_suspend *handler) +{ + struct ssp_data *data; + data = container_of(handler, struct ssp_data, early_suspend); + + func_dbg(); + disable_debug_timer(data); + + /* give notice to user that AP goes to sleep */ + ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_SLEEP); + ssp_send_status_cmd(data, MSG2SSP_AP_STATUS_SLEEP); + + data->bCheckSuspend = true; +} + +static void ssp_late_resume(struct early_suspend *handler) +{ + struct ssp_data *data; + data = container_of(handler, struct ssp_data, early_suspend); + + func_dbg(); + enable_debug_timer(data); + + data->bCheckSuspend = false; + + /* give notice to user that AP goes to sleep */ + ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_WAKEUP); + ssp_send_status_cmd(data, MSG2SSP_AP_STATUS_WAKEUP); +} + +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +static int ssp_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ssp_data *data = i2c_get_clientdata(client); + + func_dbg(); + + ssp_send_status_cmd(data, MSG2SSP_AP_STATUS_SUSPEND); + + return 0; +} + +static int ssp_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ssp_data *data = i2c_get_clientdata(client); + + func_dbg(); + + ssp_send_status_cmd(data, MSG2SSP_AP_STATUS_RESUME); + + return 0; +} + +static const struct dev_pm_ops ssp_pm_ops = { + .suspend = ssp_suspend, + .resume = ssp_resume +}; + +static const struct i2c_device_id ssp_id[] = { + {"ssp", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ssp_id); + +static struct i2c_driver ssp_driver = { + .probe = ssp_probe, + .shutdown = ssp_shutdown, + .id_table = ssp_id, + .driver = { + .pm = &ssp_pm_ops, + .owner = THIS_MODULE, + .name = "ssp" + }, +}; + +static int __init ssp_init(void) +{ + return i2c_add_driver(&ssp_driver); +} + +static void __exit ssp_exit(void) +{ + i2c_del_driver(&ssp_driver); +} + +module_init(ssp_init); +module_exit(ssp_exit); + +MODULE_DESCRIPTION("ssp driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/atmel/ssp_firmware.c b/drivers/sensorhub/atmel/ssp_firmware.c new file mode 100755 index 00000000000..6d554fffde4 --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_firmware.c @@ -0,0 +1,495 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +#define SSP_FIRMWARE_REVISION 123109 + +/* Bootload mode cmd */ +#define BL_FW_NAME "ssp.fw" +#define BL_UMS_FW_NAME "ssp_.bin" +#define BL_CRASHED_FW_NAME "ssp_crashed.fw" + +#define BL_UMS_FW_PATH 255 + +#define APP_SLAVE_ADDR 0x18 +#define BOOTLOADER_SLAVE_ADDR 0x26 + +/* Bootloader mode status */ +#define BL_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ +#define BL_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ +#define BL_FRAME_CRC_CHECK 0x02 +#define BL_FRAME_CRC_FAIL 0x03 +#define BL_FRAME_CRC_PASS 0x04 +#define BL_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ +#define BL_BOOT_STATUS_MASK 0x3f + +/* Command to unlock bootloader */ +#define BL_UNLOCK_CMD_MSB 0xaa +#define BL_UNLOCK_CMD_LSB 0xdc + +unsigned int get_module_rev(void) +{ + return SSP_FIRMWARE_REVISION; +} + +static void change_to_bootmode(struct ssp_data *data) +{ + int iCnt = 0; + + for (iCnt = 0; iCnt < 10; iCnt++) { + data->set_mcu_reset(0); + udelay(10); + + data->set_mcu_reset(1); + msleep(100); + } + + msleep(50); +} + +void toggle_mcu_reset(struct ssp_data *data) +{ + u8 uBuf[2]; + + uBuf[0] = 0x00; + uBuf[1] = 0x00; + + data->set_mcu_reset(0); + udelay(10); + data->set_mcu_reset(1); + mdelay(50); + + data->client->addr = BOOTLOADER_SLAVE_ADDR; + + if (i2c_master_send(data->client, uBuf, 2) != 2) + pr_err("[SSP]: %s - ssp_Normal Mode\n", __func__); + else + pr_err("[SSP]: %s - ssp_load_fw_bootmode\n", __func__); + + data->client->addr = APP_SLAVE_ADDR; +} + +static int check_bootloader(struct i2c_client *client, unsigned int uState) +{ + u8 uVal; + u8 uTemp; + +recheck: + if (i2c_master_recv(client, &uVal, 1) != 1) + return -EIO; + + if (uVal & 0x20) { + if (i2c_master_recv(client, &uTemp, 1) != 1) { + pr_err("[SSP]: %s - i2c recv fail\n", __func__); + return -EIO; + } + + if (i2c_master_recv(client, &uTemp, 1) != 1) { + pr_err("[SSP]: %s - i2c recv fail\n", __func__); + return -EIO; + } + + uVal &= ~0x20; + } + + if ((uVal & 0xF0) == BL_APP_CRC_FAIL) { + pr_info("[SSP] SSP_APP_CRC_FAIL - There is no bootloader.\n"); + if (i2c_master_recv(client, &uVal, 1) != 1) { + pr_err("[SSP]: %s - i2c recv fail\n", __func__); + return -EIO; + } + + if (uVal & 0x20) { + if (i2c_master_recv(client, &uTemp, 1) != 1) { + pr_err("[SSP]: %s - i2c recv fail\n", __func__); + return -EIO; + } + + if (i2c_master_recv(client, &uTemp, 1) != 1) { + pr_err("[SSP]: %s - i2c recv fail\n", __func__); + return -EIO; + } + + uVal &= ~0x20; + } + } + + switch (uState) { + case BL_WAITING_BOOTLOAD_CMD: + case BL_WAITING_FRAME_DATA: + uVal &= ~BL_BOOT_STATUS_MASK; + break; + case BL_FRAME_CRC_PASS: + if (uVal == BL_FRAME_CRC_CHECK) + goto recheck; + break; + default: + return -EINVAL; + } + + if (uVal != uState) { + pr_err("[SSP]: %s - Invalid bootloader mode state\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int unlock_bootloader(struct i2c_client *client) +{ + u8 uBuf[2]; + + uBuf[0] = BL_UNLOCK_CMD_LSB; + uBuf[1] = BL_UNLOCK_CMD_MSB; + + if (i2c_master_send(client, uBuf, 2) != 2) { + pr_err("[SSP]: %s - i2c send failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int fw_write(struct i2c_client *client, + const u8 *pData, unsigned int uFrameSize) +{ + if (i2c_master_send(client, pData, uFrameSize) != uFrameSize) { + pr_err("[SSP]: %s - i2c send failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int load_ums_fw_bootmode(struct i2c_client *client, const char *pFn) +{ + const u8 *buff = NULL; + char fw_path[BL_UMS_FW_PATH+1]; + unsigned int uFrameSize; + unsigned int uFSize = 0, uNRead = 0; + unsigned int uPos = 0; + int iRet = SUCCESS; + int iCheckFrameCrcError = 0; + int iCheckWatingFrameDataError = 0; + int count = 0; + struct file *fp = NULL; + mm_segment_t old_fs = get_fs(); + + pr_info("[SSP] ssp_load_ums_fw start!!!\n"); + + old_fs = get_fs(); + set_fs(get_ds()); + + snprintf(fw_path, BL_UMS_FW_PATH, "/sdcard/ssp/%s", pFn); + + fp = filp_open(fw_path, O_RDONLY, 0); + if (IS_ERR(fp)) { + iRet = ERROR; + pr_err("file %s open error:%d\n", fw_path, (s32)fp); + goto err_open; + } + + uFSize = (unsigned int)fp->f_path.dentry->d_inode->i_size; + pr_info("ssp_load_ums firmware size: %u\n", uFSize); + + buff = kzalloc((size_t)uFSize, GFP_KERNEL); + if (!buff) { + iRet = ERROR; + pr_err("fail to alloc buffer for fw\n"); + goto err_alloc; + } + + uNRead = (unsigned int)vfs_read(fp, (char __user *)buff, + (unsigned int)uFSize, &fp->f_pos); + if (uNRead != uFSize) { + iRet = ERROR; + pr_err("fail to read file %s (nread = %u)\n", fw_path, uNRead); + goto err_fw_size; + } + + /* Unlock bootloader */ + iRet = unlock_bootloader(client); + if (iRet < 0) { + pr_err("[SSP] %s - unlock_bootloader failed! %d\n", + __func__, iRet); + goto out; + } + + while (uPos < uFSize) { + if (check_bootloader(client, BL_WAITING_FRAME_DATA)) { + iCheckWatingFrameDataError++; + if (iCheckWatingFrameDataError > 10) { + iRet = ERROR; + pr_err("[SSP]: %s - F/W update fail\n", + __func__); + goto out; + } else { + pr_err("[SSP]: %s - F/W data_error %d, retry\n", + __func__, iCheckWatingFrameDataError); + continue; + } + } + + uFrameSize = (unsigned int)((*(buff + uPos) << 8) | + *(buff + uPos + 1)); + + /* We should add 2 at frame size as the the firmware data is not + * included the CRC bytes. + */ + uFrameSize += 2; + + /* Write one frame to device */ + fw_write(client, buff + uPos, uFrameSize); + if (check_bootloader(client, BL_FRAME_CRC_PASS)) { + iCheckFrameCrcError++; + if (iCheckFrameCrcError > 10) { + iRet = ERROR; + pr_err("[SSP]: %s - F/W Update Fail. crc err\n", + __func__); + goto out; + } else { + pr_err("[SSP]: %s - F/W crc_error %d, retry\n", + __func__, iCheckFrameCrcError); + continue; + } + } + + uPos += uFrameSize; + if (count++ == 100) { + pr_info("[SSP] Updated %u bytes / %u bytes\n", uPos, + uFSize); + count = 0; + } + + mdelay(1); + } + +out: +err_fw_size: + kfree(buff); +err_alloc: + filp_close(fp, NULL); +err_open: + set_fs(old_fs); + + return iRet; +} + +static int load_kernel_fw_bootmode(struct i2c_client *client, const char *pFn) +{ + unsigned int uFrameSize; + unsigned int uPos = 0; + int iRet = SUCCESS; + int iCheckFrameCrcError = 0; + int iCheckWatingFrameDataError = 0; + int count = 0; + const struct firmware *fw = NULL; + + pr_info("[SSP] ssp_load_fw start!!!\n"); + + if (request_firmware(&fw, pFn, &client->dev)) { + iRet = ERROR; + pr_err("[SSP]: %s - Unable to open firmware %s\n", + __func__, pFn); + return iRet; + } + + /* Unlock bootloader */ + unlock_bootloader(client); + + while (uPos < fw->size) { + if (check_bootloader(client, BL_WAITING_FRAME_DATA)) { + iCheckWatingFrameDataError++; + if (iCheckWatingFrameDataError > 10) { + iRet = ERROR; + pr_err("[SSP]: %s - F/W update fail\n", + __func__); + goto out; + } else { + pr_err("[SSP]: %s - F/W data_error %d, retry\n", + __func__, iCheckWatingFrameDataError); + continue; + } + } + + uFrameSize = ((*(fw->data + uPos) << 8) | + *(fw->data + uPos + 1)); + + /* We should add 2 at frame size as the the firmware data is not + * included the CRC bytes. + */ + uFrameSize += 2; + + /* Write one frame to device */ + fw_write(client, fw->data + uPos, uFrameSize); + if (check_bootloader(client, BL_FRAME_CRC_PASS)) { + iCheckFrameCrcError++; + if (iCheckFrameCrcError > 10) { + iRet = ERROR; + pr_err("[SSP]: %s - F/W Update Fail. crc err\n", + __func__); + goto out; + } else { + pr_err("[SSP]: %s - F/W crc_error %d, retry\n", + __func__, iCheckFrameCrcError); + continue; + } + } + + uPos += uFrameSize; + if (count++ == 100) { + pr_info("[SSP] Updated %u bytes / %u bytes\n", uPos, + fw->size); + count = 0; + } + mdelay(1); + } + pr_info("[SSP] Firmware download is success.(%u bytes)\n", uPos); +out: + release_firmware(fw); + return iRet; +} + +static int update_mcu_bin(struct ssp_data *data, int iBinType) +{ + int iRet = SUCCESS; + + pr_info("[SSP] ssp_change_to_bootmode\n"); + change_to_bootmode(data); + data->client->addr = BOOTLOADER_SLAVE_ADDR; + + switch (iBinType) { + case KERNEL_BINARY: + iRet = load_kernel_fw_bootmode(data->client, BL_FW_NAME); + break; + case KERNEL_CRASHED_BINARY: + iRet = load_kernel_fw_bootmode(data->client, + BL_CRASHED_FW_NAME); + break; + case UMS_BINARY: + iRet = load_ums_fw_bootmode(data->client, BL_UMS_FW_NAME); + break; + default: + pr_err("[SSP] binary type error!!\n"); + } + + msleep(SSP_SW_RESET_TIME); + + data->client->addr = APP_SLAVE_ADDR; + + return iRet; +} + +int forced_to_download_binary(struct ssp_data *data, int iBinType) +{ + int iRet = 0; + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + if (data->bSspShutdown == false) { + data->bSspShutdown = true; + disable_irq_wake(data->iIrq); + disable_irq(data->iIrq); + } + + data->fw_dl_state = FW_DL_STATE_DOWNLOADING; + pr_info("[SSP] %s, DL state = %d\n", __func__, data->fw_dl_state); + + iRet = update_mcu_bin(data, iBinType); + if (iRet < 0) { + iRet = ERROR; + ssp_dbg("[SSP]: %s - update_mcu_bin failed!\n", __func__); + goto out; + } + + data->fw_dl_state = FW_DL_STATE_SYNC; + pr_info("[SSP] %s, DL state = %d\n", __func__, data->fw_dl_state); + + iRet = initialize_mcu(data); + if (iRet < 0) { + iRet = ERROR; + ssp_dbg("[SSP]: %s - initialize_mcu failed!\n", __func__); + goto out; + } + + if (data->bSspShutdown == true) { + data->bSspShutdown = false; + enable_irq(data->iIrq); + enable_irq_wake(data->iIrq); + } + + sync_sensor_state(data); + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_RESET); +#endif + + data->fw_dl_state = FW_DL_STATE_DONE; + pr_info("[SSP] %s, DL state = %d\n", __func__, data->fw_dl_state); + + iRet = SUCCESS; +out: + return iRet; +} + +int check_fwbl(struct ssp_data *data) +{ + int iRet; + + data->client->addr = APP_SLAVE_ADDR; + data->uCurFirmRev = get_firmware_rev(data); + + if (data->uCurFirmRev == SSP_INVALID_REVISION) { + toggle_mcu_reset(data); + msleep(SSP_SW_RESET_TIME); + + data->client->addr = BOOTLOADER_SLAVE_ADDR; + iRet = check_bootloader(data->client, BL_WAITING_BOOTLOAD_CMD); + + if (iRet >= 0) { + pr_info("[SSP] ssp_load_fw_bootmode\n"); + + return FW_DL_STATE_NEED_TO_SCHEDULE; + } else { + pr_warn("[SSP] Firm Rev is invalid. Retry.\n"); + data->client->addr = APP_SLAVE_ADDR; + data->uCurFirmRev = get_firmware_rev(data); + + if (data->uCurFirmRev == SSP_INVALID_REVISION ||\ + data->uCurFirmRev == ERROR) { + pr_err("[SSP] MCU is not working\n"); + return FW_DL_STATE_FAIL; + } else if (data->uCurFirmRev != SSP_FIRMWARE_REVISION) { + pr_info("[SSP] MCU Firm Rev : Old = %8u, New = " + "%8u\n", data->uCurFirmRev, + SSP_FIRMWARE_REVISION); + return FW_DL_STATE_NEED_TO_SCHEDULE; + } + pr_info("[SSP] MCU Firm Rev : Old = %8u, New = %8u\n", + data->uCurFirmRev, SSP_FIRMWARE_REVISION); + } + } else { + if (data->uCurFirmRev != SSP_FIRMWARE_REVISION) { + pr_info("[SSP] MCU Firm Rev : Old = %8u, New = %8u\n", + data->uCurFirmRev, SSP_FIRMWARE_REVISION); + + return FW_DL_STATE_NEED_TO_SCHEDULE; + } + pr_info("[SSP] MCU Firm Rev : Old = %8u, New = %8u\n", + data->uCurFirmRev, SSP_FIRMWARE_REVISION); + } + + return FW_DL_STATE_NONE; +} diff --git a/drivers/sensorhub/atmel/ssp_i2c.c b/drivers/sensorhub/atmel/ssp_i2c.c new file mode 100755 index 00000000000..e78b24f0833 --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_i2c.c @@ -0,0 +1,560 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +#define LIMIT_DELAY_CNT 200 + +int waiting_wakeup_mcu(struct ssp_data *data) +{ + int iDelaycnt = 0; + + while (!data->check_mcu_busy() && (iDelaycnt++ < LIMIT_DELAY_CNT) + && (data->bSspShutdown == false)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Irq Timeout!!\n", __func__); + data->uBusyCnt++; + } else { + data->uBusyCnt = 0; + } + + iDelaycnt = 0; + data->wakeup_mcu(); + while (!data->check_mcu_ready() && (iDelaycnt++ < LIMIT_DELAY_CNT) + && (data->bSspShutdown == false)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Wakeup Timeout!!\n", __func__); + data->uTimeOutCnt++; + } else { + data->uTimeOutCnt = 0; + } + + if (data->bSspShutdown == true) + return ERROR; + + return SUCCESS; +} + +int waiting_init_mcu(struct ssp_data *data) +{ + int iDelaycnt = 0; + + while (!data->check_mcu_busy() && (iDelaycnt++ < LIMIT_DELAY_CNT)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Irq Timeout!!\n", __func__); + data->uBusyCnt++; + } else { + data->uBusyCnt = 0; + } + + iDelaycnt = 0; + data->wakeup_mcu(); + while (!data->check_mcu_ready() && (iDelaycnt++ < LIMIT_DELAY_CNT)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Wakeup Timeout!!\n", __func__); + data->uTimeOutCnt++; + } else { + data->uTimeOutCnt = 0; + } + + return SUCCESS; +} + +int ssp_i2c_read(struct ssp_data *data, char *pTxData, u16 uTxLength, + char *pRxData, u16 uRxLength, int iRetries) +{ + int iRet = 0, iDiffTime = 0, iTimeTemp; + struct timeval cur_time; + struct i2c_client *client = data->client; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = uTxLength, + .buf = pTxData, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = uRxLength, + .buf = pRxData, + }, + }; + + do_gettimeofday(&cur_time); + iTimeTemp = (int)cur_time.tv_sec; + do { + iRet = i2c_transfer(client->adapter, msgs, 2); + if (iRet < 0) { + do_gettimeofday(&cur_time); + iDiffTime = (int)cur_time.tv_sec - iTimeTemp; + iTimeTemp = (int)cur_time.tv_sec; + if (iDiffTime >= 4) { + pr_err("[SSP]: %s - i2c time out %d!\n", + __func__, iDiffTime); + break; + } + pr_err("[SSP]: %s - i2c transfer error %d! retry...\n", + __func__, iRet); + mdelay(10); + } else { + return SUCCESS; + } + } while (--iRetries > 0); + + return ERROR; +} + +int ssp_send_status_cmd(struct ssp_data *data, char chTxBuf) +{ + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + /* send to AP_STATUS_CMD */ + iRet = ssp_i2c_read(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_CMD(0x%x) fail %d\n", + __func__, chTxBuf, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (--iRetries > 0) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_CMD(0x%x) " + "retry...\n", __func__, chTxBuf); + iRet = ssp_i2c_read(data, &chTxBuf, 1, + &chRxBuf, 1, DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_CMD(0x%x)\n", __func__, chTxBuf); + + return SUCCESS; +} + +int send_instruction(struct ssp_data *data, u8 uInst, + u8 uSensorType, u8 *uSendBuf, u8 uLength) +{ + char chTxbuf[uLength + 4]; + char chRxbuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (data->fw_dl_state == FW_DL_STATE_DOWNLOADING) { + pr_err("[SSP] %s - Skip Inst! DL state = %d\n", + __func__, data->fw_dl_state); + return SUCCESS; + } else if ((!(data->uSensorState & (1 << uSensorType))) + && (uInst <= CHANGE_DELAY)) { + pr_err("[SSP]: %s - Bypass Inst Skip! - %u\n", + __func__, uSensorType); + return FAIL; + } else if ((!((data->uSensorState | 0xf0) & (1 << uSensorType))) + && (uInst == FACTORY_MODE)) { + pr_err("[SSP]: %s - Factory Inst Skip! - %u\n", + __func__, uSensorType); + return FAIL; + } + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + chTxbuf[0] = MSG2SSP_SSM; + chTxbuf[1] = (char)(uLength + 4); + + switch (uInst) { + case REMOVE_SENSOR: + chTxbuf[2] = MSG2SSP_INST_BYPASS_SENSOR_REMOVE; + break; + case ADD_SENSOR: + chTxbuf[2] = MSG2SSP_INST_BYPASS_SENSOR_ADD; + break; + case CHANGE_DELAY: + chTxbuf[2] = MSG2SSP_INST_CHANGE_DELAY; + break; + case GO_SLEEP: + chTxbuf[2] = MSG2SSP_AP_STATUS_SLEEP; + break; + case FACTORY_MODE: + chTxbuf[2] = MSG2SSP_INST_SENSOR_SELFTEST; + break; + case REMOVE_LIBRARY: + chTxbuf[2] = MSG2SSP_INST_LIBRARY_REMOVE; + break; + case ADD_LIBRARY: + chTxbuf[2] = MSG2SSP_INST_LIBRARY_ADD; + break; + default: + chTxbuf[2] = uInst; + break; + } + + chTxbuf[3] = uSensorType; + memcpy(&chTxbuf[4], uSendBuf, uLength); + + iRet = ssp_i2c_read(data, &(chTxbuf[0]), uLength + 4, &chRxbuf, 1, + DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Instruction CMD Fail %d\n", __func__, iRet); + return ERROR; + } else if (chRxbuf != MSG_ACK) { + while (--iRetries > 0) { + mdelay(10); + pr_err("[SSP]: %s - Instruction CMD retry...\n", + __func__); + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + iRet = ssp_i2c_read(data, &(chTxbuf[0]), + uLength + 4, &chRxbuf, 1, DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxbuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - Inst = 0x%x, Sensor Type = 0x%x, " "data = %u\n", + __func__, chTxbuf[2], chTxbuf[3], chTxbuf[4]); + return SUCCESS; +} + +int get_chipid(struct ssp_data *data) +{ + int iRet; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + /* read chip id */ + iRet = i2c_smbus_read_byte_data(data->client, MSG2SSP_AP_WHOAMI); + + return iRet; +} + +int set_sensor_position(struct ssp_data *data) +{ + char chTxBuf[5] = { 0, }; + char chRxData = 0; + int iRet = 0; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + chTxBuf[0] = MSG2SSP_AP_SENSOR_FORMATION; + + chTxBuf[1] = CONFIG_SENSORS_SSP_ACCELEROMETER_POSITION; + chTxBuf[2] = CONFIG_SENSORS_SSP_GYROSCOPE_POSITION; + chTxBuf[3] = CONFIG_SENSORS_SSP_MAGNETOMETER_POSITION; + chTxBuf[4] = 0; + + pr_info("[SSP] Sensor Posision A : %u, G : %u, M: %u, P: %u\n", + chTxBuf[1], chTxBuf[2], chTxBuf[3], chTxBuf[4]); + + iRet = ssp_i2c_read(data, chTxBuf, 5, &chRxData, 1, DEFAULT_RETRIES); + if ((chRxData != MSG_ACK) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); + iRet = ERROR; + } + + return iRet; +} + +void set_proximity_threshold(struct ssp_data *data, + unsigned char uData1, unsigned char uData2) +{ + char chTxBuf[3] = { 0, }; + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0 || + data->fw_dl_state == FW_DL_STATE_DOWNLOADING) { + pr_info("[SSP] : %s, skip DL state = %d\n", __func__, + data->fw_dl_state); + return; + } else if (!(data->uSensorState & (1 << PROXIMITY_SENSOR))) { + pr_info("[SSP] : %s, skip uSensorState = 0x%x\n", __func__, + data->uSensorState); + return; + } + + chTxBuf[0] = MSG2SSP_AP_SENSOR_PROXTHRESHOLD; + chTxBuf[1] = uData1; + chTxBuf[2] = uData2; + + iRet = ssp_i2c_read(data, chTxBuf, 3, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - SENSOR_PROXTHRESHOLD CMD fail %d\n", + __func__, iRet); + return; + } else if (chRxBuf != MSG_ACK) { + while (--iRetries > 0) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_PROXTHRESHOLD CMD" + " retry...\n", __func__); + iRet = ssp_i2c_read(data, chTxBuf, 3, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return; + } + } + + data->uInstFailCnt = 0; + pr_info("[SSP]: Proximity Threshold - %u, %u\n", uData1, uData2); +} + +void set_proximity_barcode_enable(struct ssp_data *data, bool bEnable) +{ + char chTxBuf[2] = { 0, }; + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return; + + chTxBuf[0] = MSG2SSP_AP_SENSOR_BARCODE_EMUL; + chTxBuf[1] = bEnable; + + data->bBarcodeEnabled = bEnable; + + iRet = ssp_i2c_read(data, chTxBuf, 2, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - SENSOR_BARCODE_EMUL CMD fail %d\n", + __func__, iRet); + return; + } else if (chRxBuf != MSG_ACK) { + while (--iRetries > 0) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_BARCODE_EMUL CMD " + "retry...\n", __func__); + iRet = ssp_i2c_read(data, chTxBuf, 2, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return; + } + } + + data->uInstFailCnt = 0; + pr_info("[SSP] Proximity Barcode En : %u\n", bEnable); +} + +unsigned int get_sensor_scanning_info(struct ssp_data *data) +{ + char chTxBuf = MSG2SSP_AP_SENSOR_SCANNING; + char chRxData[2] = {0,}; + int iRet = 0; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + iRet = ssp_i2c_read(data, &chTxBuf, 1, chRxData, 2, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - i2c failed %d\n", __func__, iRet); + return 0; + } + return ((unsigned int)chRxData[0] << 8) | chRxData[1]; +} + +unsigned int get_firmware_rev(struct ssp_data *data) +{ + char chTxData = MSG2SSP_AP_FIRMWARE_REV; + char chRxBuf[3] = { 0, }; + unsigned int uRev = SSP_INVALID_REVISION; + int iRet; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + iRet = ssp_i2c_read(data, &chTxData, 1, chRxBuf, 3, DEFAULT_RETRIES); + if (iRet != SUCCESS) + pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); + else + uRev = ((unsigned int)chRxBuf[0] << 16) + | ((unsigned int)chRxBuf[1] << 8) | chRxBuf[2]; + return uRev; +} + +int get_fuserom_data(struct ssp_data *data) +{ + char chTxBuf[2] = { 0, }; + char chRxBuf[2] = { 0, }; + int iRet = 0; + unsigned int uLength = 0; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + chTxBuf[0] = MSG2SSP_AP_STT; + chTxBuf[1] = MSG2SSP_AP_FUSEROM; + + /* chRxBuf is Two Byte because msg is large */ + iRet = ssp_i2c_read(data, chTxBuf, 2, chRxBuf, 2, DEFAULT_RETRIES); + uLength = ((unsigned int)chRxBuf[0] << 8) + (unsigned int)chRxBuf[1]; + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STT - i2c fail %d\n", + __func__, iRet); + goto err_read_fuserom; + } else if (uLength == 0) { + pr_err("[SSP]: %s - No ready data. length = %u\n", + __func__, uLength); + goto err_read_fuserom; + } else { + if (data->iLibraryLength != 0) + kfree(data->pchLibraryBuf); + + data->iLibraryLength = (int)uLength; + data->pchLibraryBuf = + kzalloc((data->iLibraryLength * sizeof(char)), GFP_KERNEL); + + chTxBuf[0] = MSG2SSP_SRM; + iRet = ssp_i2c_read(data, chTxBuf, 1, data->pchLibraryBuf, + (u16)data->iLibraryLength, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Fail to receive SSP data %d\n", + __func__, iRet); + kfree(data->pchLibraryBuf); + data->iLibraryLength = 0; + goto err_read_fuserom; + } + } + + data->uFuseRomData[0] = data->pchLibraryBuf[0]; + data->uFuseRomData[1] = data->pchLibraryBuf[1]; + data->uFuseRomData[2] = data->pchLibraryBuf[2]; + + pr_info("[SSP] FUSE ROM Data %d , %d, %d\n", data->uFuseRomData[0], + data->uFuseRomData[1], data->uFuseRomData[2]); + + data->iLibraryLength = 0; + kfree(data->pchLibraryBuf); + return SUCCESS; + +err_read_fuserom: + data->uFuseRomData[0] = 0; + data->uFuseRomData[1] = 0; + data->uFuseRomData[2] = 0; + + return FAIL; +} + +static int ssp_receive_msg(struct ssp_data *data, u8 uLength) +{ + char chTxBuf = 0; + char *pchRcvDataFrame; /* SSP-AP Massage data buffer */ + int iRet = 0; + + if (uLength > 0) { + pchRcvDataFrame = kzalloc((uLength * sizeof(char)), GFP_KERNEL); + if (pchRcvDataFrame == NULL) { + pr_err("[SSP]: %s - failed to allocate memory for data\n", + __func__); + iRet = -ENOMEM; + return iRet; + } + chTxBuf = MSG2SSP_SRM; + iRet = ssp_i2c_read(data, &chTxBuf, 1, pchRcvDataFrame, + (u16)uLength, 0); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Fail to receive data %d\n", + __func__, iRet); + kfree(pchRcvDataFrame); + return ERROR; + } + } else { + pr_err("[SSP]: %s - No ready data. length = %d\n", + __func__, uLength); + return FAIL; + } + + parse_dataframe(data, pchRcvDataFrame, uLength); + + kfree(pchRcvDataFrame); + return uLength; +} + +int select_irq_msg(struct ssp_data *data) +{ + u8 chLength = 0; + char chTxBuf = 0; + char chRxBuf[2] = { 0, }; + int iRet = 0; + + chTxBuf = MSG2SSP_SSD; + iRet = ssp_i2c_read(data, &chTxBuf, 1, chRxBuf, 2, 0); + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_SSD error %d\n", __func__, iRet); + return ERROR; + } else { + if (chRxBuf[0] == MSG2SSP_RTS) { + chLength = (u8)chRxBuf[1]; + ssp_receive_msg(data, chLength); + data->uSsdFailCnt = 0; + } +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + else if (chRxBuf[0] == MSG2SSP_STT) { + pr_info("%s: MSG2SSP_STT irq", __func__); + iRet = ssp_sensorhub_handle_large_data(data, + (u8)chRxBuf[1]); + if (iRet < 0) { + pr_err("%s: ssp sensorhub large data err(%d)", + __func__, iRet); + } + data->uSsdFailCnt = 0; + } +#endif + else if (chRxBuf[0] == MSG2SSP_NO_DATA) { + pr_info("%s: MSG2SSP_NO_DATA irq [0]: 0x%x, [1]: 0x%x\n", + __func__, chRxBuf[0], chRxBuf[1]); + } else { + pr_err("[SSP]: %s - MSG2SSP_SSD Data fail " + "[0]: 0x%x, [1]: 0x%x\n", __func__, + chRxBuf[0], chRxBuf[1]); + if ((chRxBuf[0] == 0) && (chRxBuf[1] == 0)) + data->uSsdFailCnt++; + } + } + return SUCCESS; +} diff --git a/drivers/sensorhub/atmel/ssp_input.c b/drivers/sensorhub/atmel/ssp_input.c new file mode 100755 index 00000000000..a7de8c60836 --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_input.c @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* SSP Kernel -> HAL input evnet function */ +/*************************************************************************/ +void convert_acc_data(s16 *iValue) +{ + if (*iValue > 2048) + *iValue = ((4096 - *iValue)) * (-1); +} + +void report_acc_data(struct ssp_data *data, struct sensor_value *accdata) +{ + convert_acc_data(&accdata->x); + convert_acc_data(&accdata->y); + convert_acc_data(&accdata->z); + + data->buf[ACCELEROMETER_SENSOR].x = accdata->x - data->accelcal.x; + data->buf[ACCELEROMETER_SENSOR].y = accdata->y - data->accelcal.y; + data->buf[ACCELEROMETER_SENSOR].z = accdata->z - data->accelcal.z; + + input_report_rel(data->acc_input_dev, REL_X, + data->buf[ACCELEROMETER_SENSOR].x); + input_report_rel(data->acc_input_dev, REL_Y, + data->buf[ACCELEROMETER_SENSOR].y); + input_report_rel(data->acc_input_dev, REL_Z, + data->buf[ACCELEROMETER_SENSOR].z); + input_sync(data->acc_input_dev); +} + +void report_gyro_data(struct ssp_data *data, struct sensor_value *gyrodata) +{ + long lTemp[3] = {0,}; + data->buf[GYROSCOPE_SENSOR].x = gyrodata->x - data->gyrocal.x; + data->buf[GYROSCOPE_SENSOR].y = gyrodata->y - data->gyrocal.y; + data->buf[GYROSCOPE_SENSOR].z = gyrodata->z - data->gyrocal.z; + + if (data->uGyroDps == GYROSCOPE_DPS250) { + lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x >> 1; + lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y >> 1; + lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z >> 1; + } else if (data->uGyroDps == GYROSCOPE_DPS2000) { + lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x << 2; + lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y << 2; + lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z << 2; + } else { + lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x; + lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y; + lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z; + } + + input_report_rel(data->gyro_input_dev, REL_RX, lTemp[0]); + input_report_rel(data->gyro_input_dev, REL_RY, lTemp[1]); + input_report_rel(data->gyro_input_dev, REL_RZ, lTemp[2]); + input_sync(data->gyro_input_dev); +} + +void report_mag_data(struct ssp_data *data, struct sensor_value *magdata) +{ + data->buf[GEOMAGNETIC_SENSOR].x = magdata->x; + data->buf[GEOMAGNETIC_SENSOR].y = magdata->y; + data->buf[GEOMAGNETIC_SENSOR].z = magdata->z; +} + +void report_gesture_data(struct ssp_data *data, struct sensor_value *gesdata) +{ + /* todo: remove func*/ +} + +void report_pressure_data(struct ssp_data *data, struct sensor_value *predata) +{ + data->buf[PRESSURE_SENSOR].pressure[0] = + predata->pressure[0] - data->iPressureCal; + data->buf[PRESSURE_SENSOR].pressure[1] = predata->pressure[1]; + + /* pressure */ + input_report_rel(data->pressure_input_dev, REL_HWHEEL, + data->buf[PRESSURE_SENSOR].pressure[0]); + /* temperature */ + input_report_rel(data->pressure_input_dev, REL_WHEEL, + data->buf[PRESSURE_SENSOR].pressure[1]); + input_sync(data->pressure_input_dev); +} + +void report_light_data(struct ssp_data *data, struct sensor_value *lightdata) +{ + data->buf[LIGHT_SENSOR].r = lightdata->r; + data->buf[LIGHT_SENSOR].g = lightdata->g; + data->buf[LIGHT_SENSOR].b = lightdata->b; + data->buf[LIGHT_SENSOR].w = lightdata->w; + + input_report_rel(data->light_input_dev, REL_HWHEEL, + data->buf[LIGHT_SENSOR].r + 1); + input_report_rel(data->light_input_dev, REL_DIAL, + data->buf[LIGHT_SENSOR].g + 1); + input_report_rel(data->light_input_dev, REL_WHEEL, + data->buf[LIGHT_SENSOR].b + 1); + input_report_rel(data->light_input_dev, REL_MISC, + data->buf[LIGHT_SENSOR].w + 1); + input_sync(data->light_input_dev); +} + +void report_prox_data(struct ssp_data *data, struct sensor_value *proxdata) +{ + ssp_dbg("[SSP] Proximity Sensor Detect : %u, raw : %u\n", + proxdata->prox[0], proxdata->prox[1]); + + data->buf[PROXIMITY_SENSOR].prox[0] = proxdata->prox[0]; + data->buf[PROXIMITY_SENSOR].prox[1] = proxdata->prox[1]; + + input_report_abs(data->prox_input_dev, ABS_DISTANCE, + (!proxdata->prox[0])); + input_sync(data->prox_input_dev); + + wake_lock_timeout(&data->ssp_wake_lock, 3 * HZ); +} + +void report_prox_raw_data(struct ssp_data *data, + struct sensor_value *proxrawdata) +{ + if (data->uFactoryProxAvg[0]++ >= PROX_AVG_READ_NUM) { + data->uFactoryProxAvg[2] /= PROX_AVG_READ_NUM; + data->buf[PROXIMITY_RAW].prox[1] = (u8)data->uFactoryProxAvg[1]; + data->buf[PROXIMITY_RAW].prox[2] = (u8)data->uFactoryProxAvg[2]; + data->buf[PROXIMITY_RAW].prox[3] = (u8)data->uFactoryProxAvg[3]; + + data->uFactoryProxAvg[0] = 0; + data->uFactoryProxAvg[1] = 0; + data->uFactoryProxAvg[2] = 0; + data->uFactoryProxAvg[3] = 0; + } else { + data->uFactoryProxAvg[2] += proxrawdata->prox[0]; + + if (data->uFactoryProxAvg[0] == 1) + data->uFactoryProxAvg[1] = proxrawdata->prox[0]; + else if (proxrawdata->prox[0] < data->uFactoryProxAvg[1]) + data->uFactoryProxAvg[1] = proxrawdata->prox[0]; + + if (proxrawdata->prox[0] > data->uFactoryProxAvg[3]) + data->uFactoryProxAvg[3] = proxrawdata->prox[0]; + } + + data->buf[PROXIMITY_RAW].prox[0] = proxrawdata->prox[0]; +} + +int initialize_event_symlink(struct ssp_data *data) +{ + int iRet = 0; + struct class *event_class = NULL; + + event_class = class_create(THIS_MODULE, "sensor_event"); + data->sen_dev = device_create(event_class, NULL, 0, NULL, + "%s", "symlink"); + + iRet = sysfs_create_link(&data->sen_dev->kobj, + &data->acc_input_dev->dev.kobj, + data->acc_input_dev->name); + if (iRet < 0) + goto iRet_acc_sysfs_create_link; + + iRet = sysfs_create_link(&data->sen_dev->kobj, + &data->gyro_input_dev->dev.kobj, + data->gyro_input_dev->name); + if (iRet < 0) + goto iRet_gyro_sysfs_create_link; + + iRet = sysfs_create_link(&data->sen_dev->kobj, + &data->pressure_input_dev->dev.kobj, + data->pressure_input_dev->name); + if (iRet < 0) + goto iRet_prs_sysfs_create_link; + + iRet = sysfs_create_link(&data->sen_dev->kobj, + &data->light_input_dev->dev.kobj, + data->light_input_dev->name); + if (iRet < 0) + goto iRet_light_sysfs_create_link; + + iRet = sysfs_create_link(&data->sen_dev->kobj, + &data->prox_input_dev->dev.kobj, + data->prox_input_dev->name); + if (iRet < 0) + goto iRet_prox_sysfs_create_link; + + return SUCCESS; + +iRet_prox_sysfs_create_link: + sysfs_delete_link(&data->sen_dev->kobj, + &data->light_input_dev->dev.kobj, + data->light_input_dev->name); +iRet_light_sysfs_create_link: + sysfs_delete_link(&data->sen_dev->kobj, + &data->pressure_input_dev->dev.kobj, + data->pressure_input_dev->name); +iRet_prs_sysfs_create_link: + sysfs_delete_link(&data->sen_dev->kobj, + &data->gyro_input_dev->dev.kobj, + data->gyro_input_dev->name); +iRet_gyro_sysfs_create_link: + sysfs_delete_link(&data->sen_dev->kobj, + &data->acc_input_dev->dev.kobj, + data->acc_input_dev->name); +iRet_acc_sysfs_create_link: + pr_err("[SSP]: %s - could not create event symlink\n", __func__); + + return FAIL; +} + +void remove_event_symlink(struct ssp_data *data) +{ + sysfs_delete_link(&data->sen_dev->kobj, + &data->acc_input_dev->dev.kobj, + data->acc_input_dev->name); + sysfs_delete_link(&data->sen_dev->kobj, + &data->gyro_input_dev->dev.kobj, + data->gyro_input_dev->name); + sysfs_delete_link(&data->sen_dev->kobj, + &data->pressure_input_dev->dev.kobj, + data->pressure_input_dev->name); + sysfs_delete_link(&data->sen_dev->kobj, + &data->light_input_dev->dev.kobj, + data->light_input_dev->name); + sysfs_delete_link(&data->sen_dev->kobj, + &data->prox_input_dev->dev.kobj, + data->prox_input_dev->name); +} + +int initialize_input_dev(struct ssp_data *data) +{ + int iRet = 0; + struct input_dev *acc_input_dev, *gyro_input_dev, *pressure_input_dev, + *light_input_dev, *prox_input_dev; + + /* allocate input_device */ + acc_input_dev = input_allocate_device(); + if (acc_input_dev == NULL) + goto iRet_acc_input_free_device; + + gyro_input_dev = input_allocate_device(); + if (gyro_input_dev == NULL) + goto iRet_gyro_input_free_device; + + pressure_input_dev = input_allocate_device(); + if (pressure_input_dev == NULL) + goto iRet_pressure_input_free_device; + + light_input_dev = input_allocate_device(); + if (light_input_dev == NULL) + goto iRet_light_input_free_device; + + prox_input_dev = input_allocate_device(); + if (prox_input_dev == NULL) + goto iRet_proximity_input_free_device; + + input_set_drvdata(acc_input_dev, data); + input_set_drvdata(gyro_input_dev, data); + input_set_drvdata(pressure_input_dev, data); + input_set_drvdata(light_input_dev, data); + input_set_drvdata(prox_input_dev, data); + + acc_input_dev->name = "accelerometer_sensor"; + gyro_input_dev->name = "gyro_sensor"; + pressure_input_dev->name = "pressure_sensor"; + light_input_dev->name = "light_sensor"; + prox_input_dev->name = "proximity_sensor"; + + input_set_capability(acc_input_dev, EV_REL, REL_X); + input_set_capability(acc_input_dev, EV_REL, REL_Y); + input_set_capability(acc_input_dev, EV_REL, REL_Z); + + input_set_capability(gyro_input_dev, EV_REL, REL_RX); + input_set_capability(gyro_input_dev, EV_REL, REL_RY); + input_set_capability(gyro_input_dev, EV_REL, REL_RZ); + + input_set_capability(pressure_input_dev, EV_REL, REL_HWHEEL); + input_set_capability(pressure_input_dev, EV_REL, REL_DIAL); + input_set_capability(pressure_input_dev, EV_REL, REL_WHEEL); + + input_set_capability(light_input_dev, EV_REL, REL_HWHEEL); + input_set_capability(light_input_dev, EV_REL, REL_DIAL); + input_set_capability(light_input_dev, EV_REL, REL_WHEEL); + input_set_capability(light_input_dev, EV_REL, REL_MISC); + + input_set_capability(prox_input_dev, EV_ABS, ABS_DISTANCE); + input_set_abs_params(prox_input_dev, ABS_DISTANCE, 0, 1, 0, 0); + + /* register input_device */ + iRet = input_register_device(acc_input_dev); + if (iRet < 0) + goto iRet_acc_input_unreg_device; + + iRet = input_register_device(gyro_input_dev); + if (iRet < 0) { + input_free_device(gyro_input_dev); + goto iRet_gyro_input_unreg_device; + } + + iRet = input_register_device(pressure_input_dev); + if (iRet < 0) { + input_free_device(pressure_input_dev); + goto iRet_pressure_input_unreg_device; + } + + iRet = input_register_device(light_input_dev); + if (iRet < 0) { + input_free_device(light_input_dev); + goto iRet_light_input_unreg_device; + } + + iRet = input_register_device(prox_input_dev); + if (iRet < 0) { + input_free_device(prox_input_dev); + goto iRet_proximity_input_unreg_device; + } + + data->acc_input_dev = acc_input_dev; + data->gyro_input_dev = gyro_input_dev; + data->pressure_input_dev = pressure_input_dev; + data->light_input_dev = light_input_dev; + data->prox_input_dev = prox_input_dev; + + return SUCCESS; + +iRet_proximity_input_unreg_device: + input_unregister_device(light_input_dev); +iRet_light_input_unreg_device: + input_unregister_device(pressure_input_dev); +iRet_pressure_input_unreg_device: + input_unregister_device(gyro_input_dev); +iRet_gyro_input_unreg_device: + input_unregister_device(acc_input_dev); + return ERROR; + +iRet_acc_input_unreg_device: + pr_err("[SSP]: %s - could not register input device\n", __func__); + input_free_device(prox_input_dev); +iRet_proximity_input_free_device: + input_free_device(light_input_dev); +iRet_light_input_free_device: + input_free_device(pressure_input_dev); +iRet_pressure_input_free_device: + input_free_device(gyro_input_dev); +iRet_gyro_input_free_device: + input_free_device(acc_input_dev); +iRet_acc_input_free_device: + pr_err("[SSP]: %s - could not allocate input device\n", __func__); + return ERROR; +} + +void remove_input_dev(struct ssp_data *data) +{ + input_unregister_device(data->acc_input_dev); + input_unregister_device(data->gyro_input_dev); + input_unregister_device(data->pressure_input_dev); + input_unregister_device(data->light_input_dev); + input_unregister_device(data->prox_input_dev); +} diff --git a/drivers/sensorhub/atmel/ssp_sensorhub.c b/drivers/sensorhub/atmel/ssp_sensorhub.c new file mode 100755 index 00000000000..b526e261add --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_sensorhub.c @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2013, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ssp.h" + +static int ssp_sensorhub_print_data(const char *func_name, + const char *data, int length) +{ + char buf[6]; + char *log_str; + int log_size = strlen(func_name) + 2 + sizeof(buf) * length + 1; + int i; + + log_str = kzalloc(log_size, GFP_ATOMIC); + if (unlikely(!log_str)) { + sensorhub_err("allocate memory for data log err"); + return -ENOMEM; + } + + for (i = 0; i < length; i++) { + if (i == 0) { + strlcat(log_str, func_name, log_size); + strlcat(log_str, ": ", log_size); + } else { + strlcat(log_str, ", ", log_size); + } + snprintf(buf, sizeof(buf), "%d", (signed char)data[i]); + strlcat(log_str, buf, log_size); + } + + pr_info("%s", log_str); + kfree(log_str); + return log_size; +} + +static ssize_t ssp_sensorhub_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + struct ssp_sensorhub_data *hub_data + = container_of(file->private_data, + struct ssp_sensorhub_data, sensorhub_device); + unsigned char instruction; + int ret = 0; + + if (unlikely(count < 2)) { + sensorhub_err("library data length err(%d)", count); + return -EINVAL; + } + + ssp_sensorhub_print_data(__func__, buf, count); + + if (unlikely(hub_data->ssp_data->bSspShutdown)) { + sensorhub_err("stop sending library data(shutdown)"); + return -EBUSY; + } + + if (buf[0] == MSG2SSP_INST_LIBRARY_REMOVE) + instruction = REMOVE_LIBRARY; + else if (buf[0] == MSG2SSP_INST_LIBRARY_ADD) + instruction = ADD_LIBRARY; + else + instruction = buf[0]; + + ret = send_instruction(hub_data->ssp_data, instruction, + (unsigned char)buf[1], (unsigned char *)(buf+2), count-2); + if (unlikely(ret <= 0)) { + sensorhub_err("send library data err(%d)", ret); + /* i2c transfer fail */ + if (ret == ERROR) + return -EIO; + /* i2c transfer done but no ack from MCU */ + else if (ret == FAIL) + return -EAGAIN; + } + + return count; +} + +static ssize_t ssp_sensorhub_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct ssp_sensorhub_data *hub_data + = container_of(file->private_data, + struct ssp_sensorhub_data, sensorhub_device); + int retries = MAX_DATA_COPY_TRY; + int length = 0; + int ret = 0; + + spin_lock_bh(&hub_data->sensorhub_lock); + if (unlikely(list_empty(&hub_data->events_head.list))) { + sensorhub_info("no library data"); + goto exit; + } + + /* first in first out */ + hub_data->first_event + = list_first_entry(&hub_data->events_head.list, + struct sensorhub_event, list); + length = hub_data->first_event->library_length; + + /* remove first event from the list */ + list_del(&hub_data->first_event->list); + + while (retries--) { + ret = copy_to_user(buf, + hub_data->first_event->library_data, + hub_data->first_event->library_length); + if (likely(!ret)) + break; + } + if (unlikely(ret)) { + sensorhub_err("read library data err(%d)", ret); + goto exit; + } + + ssp_sensorhub_print_data(__func__, + hub_data->first_event->library_data, + hub_data->first_event->library_length); + + complete(&hub_data->sensorhub_completion); + +exit: + spin_unlock_bh(&hub_data->sensorhub_lock); + return ret ? -ret : length; +} + +static long ssp_sensorhub_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ssp_sensorhub_data *hub_data + = container_of(file->private_data, + struct ssp_sensorhub_data, sensorhub_device); + void __user *argp = (void __user *)arg; + int retries = MAX_DATA_COPY_TRY; + int length = hub_data->large_library_length; + int ret = 0; + + switch (cmd) { + case IOCTL_READ_LARGE_CONTEXT_DATA: + if (unlikely(!hub_data->large_library_data + || !hub_data->large_library_length)) { + sensorhub_info("no large library data"); + return 0; + } + + while (retries--) { + ret = copy_to_user(argp, + hub_data->large_library_data, + hub_data->large_library_length); + if (likely(!ret)) + break; + } + if (unlikely(ret)) { + sensorhub_err("read large library data err(%d)", ret); + return -ret; + } + + ssp_sensorhub_print_data(__func__, + hub_data->large_library_data, + hub_data->large_library_length); + + kfree(hub_data->large_library_data); + hub_data->large_library_length = 0; + break; + + default: + sensorhub_err("ioctl cmd err(%d)", cmd); + return -EINVAL; + } + + return length; +} + +static struct file_operations ssp_sensorhub_fops = { + .owner = THIS_MODULE, + .open = nonseekable_open, + .write = ssp_sensorhub_write, + .read = ssp_sensorhub_read, + .unlocked_ioctl = ssp_sensorhub_ioctl, +}; + +void ssp_sensorhub_report_notice(struct ssp_data *ssp_data, char notice) +{ + struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; + + input_report_rel(hub_data->sensorhub_input_dev, NOTICE, notice); + input_sync(hub_data->sensorhub_input_dev); + + if (notice == MSG2SSP_AP_STATUS_WAKEUP) + sensorhub_info("wake up"); + else if (notice == MSG2SSP_AP_STATUS_SLEEP) + sensorhub_info("sleep"); + else if (notice == MSG2SSP_AP_STATUS_RESET) + sensorhub_info("reset"); + else + sensorhub_err("invalid notice(0x%x)", notice); +} + +static void ssp_sensorhub_report_library(struct ssp_sensorhub_data *hub_data) +{ + input_report_rel(hub_data->sensorhub_input_dev, DATA, DATA); + input_sync(hub_data->sensorhub_input_dev); + wake_lock_timeout(&hub_data->sensorhub_wake_lock, WAKE_LOCK_TIMEOUT); +} + +static void ssp_sensorhub_report_large_library( + struct ssp_sensorhub_data *hub_data) +{ + input_report_rel(hub_data->sensorhub_input_dev, LARGE_DATA, LARGE_DATA); + input_sync(hub_data->sensorhub_input_dev); + wake_lock_timeout(&hub_data->sensorhub_wake_lock, WAKE_LOCK_TIMEOUT); +} + +static int ssp_sensorhub_list(struct ssp_sensorhub_data *hub_data, + char *dataframe, int start, int end) +{ + struct list_head *list; + int length = end - start; + int events = 0; + + if (unlikely(length <= 0)) { + sensorhub_err("library length err(%d)", length); + return -EINVAL; + } + + ssp_sensorhub_print_data(__func__, dataframe+start, length); + + spin_lock_bh(&hub_data->sensorhub_lock); + /* how many events in the list? */ + list_for_each(list, &hub_data->events_head.list) + events++; + + /* overwrite new event if list is full */ + if (unlikely(events >= LIST_SIZE)) { + struct sensorhub_event *oldest_event + = list_first_entry(&hub_data->events_head.list, + struct sensorhub_event, list); + list_del(&oldest_event->list); + sensorhub_info("overwrite event"); + } + + /* allocate memory for new event */ + kfree(hub_data->events[hub_data->event_number].library_data); + hub_data->events[hub_data->event_number].library_data + = kzalloc(length * sizeof(char), GFP_ATOMIC); + if (unlikely(!hub_data->events[hub_data->event_number].library_data)) { + sensorhub_err("allocate memory for library err"); + spin_unlock_bh(&hub_data->sensorhub_lock); + return -ENOMEM; + } + + /* copy new event into memory */ + memcpy(hub_data->events[hub_data->event_number].library_data, + dataframe+start, length); + hub_data->events[hub_data->event_number].library_length = length; + + /* add new event into the end of list */ + list_add_tail(&hub_data->events[hub_data->event_number].list, + &hub_data->events_head.list); + spin_unlock_bh(&hub_data->sensorhub_lock); + + /* not to overflow max list capacity */ + if (hub_data->event_number++ >= LIST_SIZE - 1) + hub_data->event_number = 0; + + return events + (events >= LIST_SIZE ? 0 : 1); +} + +static int ssp_sensorhub_thread(void *arg) +{ + struct ssp_sensorhub_data *hub_data = (struct ssp_sensorhub_data *)arg; + int ret = 0; + + while (likely(!kthread_should_stop())) { + /* run thread if list is not empty */ + wait_event_interruptible(hub_data->sensorhub_wq, + kthread_should_stop() || + !list_empty(&hub_data->events_head.list)); + + /* exit thread if kthread should stop */ + if (unlikely(kthread_should_stop())) { + sensorhub_info("kthread_stop()"); + break; + } + + /* report sensorhub event to user */ + ssp_sensorhub_report_library(hub_data); + + /* wait until transfer finished */ + ret = wait_for_completion_timeout( + &hub_data->sensorhub_completion, COMPLETION_TIMEOUT); + if (unlikely(!ret)) + sensorhub_err("wait timed out"); + else if (unlikely(ret < 0)) + sensorhub_err("wait for completion err(%d)", ret); + } + + return 0; +} + +int ssp_sensorhub_handle_data(struct ssp_data *ssp_data, char *dataframe, + int start, int end) +{ + struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; + + /* add new sensorhub event into list */ + int ret = ssp_sensorhub_list(hub_data, dataframe, start, end); + wake_up(&hub_data->sensorhub_wq); + + return ret; +} + +static int ssp_sensorhub_receive_large_data(struct ssp_sensorhub_data *hub_data, + unsigned char sub_cmd) +{ + static int pos; /* large_library_data current position */ + char send_data[2] = { 0, }; /* send data */ + char receive_data[5] = { 0, }; /* receive data */ + char *msg_data; /* Nth msg data */ + int total_length = 0; /* total length */ + int msg_length = 0; /* Nth msg length */ + int total_msg_number; /* total msg number */ + int msg_number; /* current msg number */ + int ret = 0; + + sensorhub_info("sub_cmd = 0x%x", sub_cmd); + + send_data[0] = MSG2SSP_STT; + send_data[1] = sub_cmd; + + /* receive_data[0-1] : total length + * receive_data[2] >> 4 : total msg number + * receive_data[2] & 0x0F : current msg number */ + ret = ssp_i2c_read(hub_data->ssp_data, send_data, sizeof(send_data), + receive_data, sizeof(receive_data), DEFAULT_RETRIES); + if (unlikely(ret < 0)) { + sensorhub_err("MSG2SSP_STT i2c err(%d)", ret); + return ret; + } + + /* get total length */ + total_length = ((unsigned int)receive_data[0] << 8) + + (unsigned int)receive_data[1]; + sensorhub_info("total length = %d", total_length); + + total_msg_number = (int)(receive_data[2] >> 4); + msg_number = (int)(receive_data[2] & 0x0F); + + /* if this is the first msg */ + if (msg_number <= 1) { + /* empty previous large_library_data */ + if (hub_data->large_library_length != 0) + kfree(hub_data->large_library_data); + + /* allocate new memory for large_library_data */ + hub_data->large_library_data + = kzalloc((total_length * sizeof(char)), GFP_KERNEL); + if (unlikely(!hub_data->large_library_data)) { + sensorhub_err("allocate memory for large library err"); + return -ENOMEM; + } + hub_data->large_library_length = total_length; + } + + /* get the Nth msg length */ + msg_length = ((unsigned int)receive_data[3] << 8) + + (unsigned int)receive_data[4]; + sensorhub_info("%dth msg length = %d", msg_number, msg_length); + + /* receive the Nth msg data */ + send_data[0] = MSG2SSP_SRM; + msg_data = kzalloc((msg_length * sizeof(char)), GFP_KERNEL); + if (unlikely(!msg_data)) { + sensorhub_err("allocate memory for msg data err"); + return -ENOMEM; + } + + ret = ssp_i2c_read(hub_data->ssp_data, send_data, 1, + msg_data, msg_length, 0); + if (unlikely(ret < 0)) { + sensorhub_err("receive %dth msg err(%d)", msg_number, ret); + kfree(msg_data); + return ret; + } + + /* copy the Nth msg data into large_library_data */ + memcpy(&hub_data->large_library_data[pos], + &msg_data[0], msg_length * sizeof(char)); + kfree(msg_data); + pos += msg_length; + + if (msg_number < total_msg_number) { + /* still receiving msg data */ + sensorhub_info("current msg length = %d(%d/%d)", + msg_length, msg_number, total_msg_number); + } else { + /* finish receiving msg data */ + sensorhub_info("total msg length = %d(%d/%d)", + pos, msg_number, total_msg_number); + pos = 0; + } + + return msg_number; +} + +int ssp_sensorhub_handle_large_data(struct ssp_data *ssp_data, + unsigned char sub_cmd) +{ + struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; + static bool err; + static int current_msg_number = 1; + int total_msg_number = (int)(sub_cmd >> 4); + int msg_number = (int)(sub_cmd & 0x0F); + int ret; + + /* skip the rest transfer if error occurs */ + if (unlikely(err)) { + if (msg_number <= 1) { + current_msg_number = 1; + err = false; + } else { + return -EIO; + } + } + + /* next msg is the right one? */ + if (current_msg_number++ != msg_number) { + sensorhub_err("next msg should be %dth but %dth", + current_msg_number - 1, msg_number); + sensorhub_err("skip the rest %d msg transfer", + total_msg_number - msg_number); + err = true; + return -EINVAL; + } + + /* receive large library data */ + ret = ssp_sensorhub_receive_large_data(hub_data, sub_cmd); + if (unlikely(ret < 0)) { + sensorhub_err("receive large msg err(%d/%d)(%d)", + msg_number, total_msg_number, ret); + sensorhub_err("skip the rest %d msg transfer", + total_msg_number - msg_number); + err = true; + return ret; + } + + /* finally ready to go to user */ + if (msg_number >= total_msg_number) { + ssp_sensorhub_report_large_library(hub_data); + current_msg_number = 1; + } + + return ret; +} + +int ssp_sensorhub_initialize(struct ssp_data *ssp_data) +{ + struct ssp_sensorhub_data *hub_data; + int ret; + + /* allocate memory for sensorhub data */ + hub_data = kzalloc(sizeof(*hub_data), GFP_KERNEL); + if (!hub_data) { + sensorhub_err("allocate memory for sensorhub data err"); + ret = -ENOMEM; + goto exit; + } + hub_data->ssp_data = ssp_data; + ssp_data->hub_data = hub_data; + + /* init wakelock, list, waitqueue, completion and spinlock */ + wake_lock_init(&hub_data->sensorhub_wake_lock, WAKE_LOCK_SUSPEND, + "ssp_sensorhub_wake_lock"); + INIT_LIST_HEAD(&hub_data->events_head.list); + init_waitqueue_head(&hub_data->sensorhub_wq); + init_completion(&hub_data->sensorhub_completion); + spin_lock_init(&hub_data->sensorhub_lock); + + /* allocate sensorhub input device */ + hub_data->sensorhub_input_dev = input_allocate_device(); + if (!hub_data->sensorhub_input_dev) { + sensorhub_err("allocate sensorhub input device err"); + ret = -ENOMEM; + goto err_input_allocate_device_sensorhub; + } + + /* set sensorhub input device */ + input_set_drvdata(hub_data->sensorhub_input_dev, hub_data); + hub_data->sensorhub_input_dev->name = "ssp_context"; + input_set_capability(hub_data->sensorhub_input_dev, EV_REL, DATA); + input_set_capability(hub_data->sensorhub_input_dev, EV_REL, LARGE_DATA); + input_set_capability(hub_data->sensorhub_input_dev, EV_REL, NOTICE); + + /* register sensorhub input device */ + ret = input_register_device(hub_data->sensorhub_input_dev); + if (ret < 0) { + sensorhub_err("register sensorhub input device err(%d)", ret); + input_free_device(hub_data->sensorhub_input_dev); + goto err_input_register_device_sensorhub; + } + + /* register sensorhub misc device */ + hub_data->sensorhub_device.minor = MISC_DYNAMIC_MINOR; + hub_data->sensorhub_device.name = "ssp_sensorhub"; + hub_data->sensorhub_device.fops = &ssp_sensorhub_fops; + + ret = misc_register(&hub_data->sensorhub_device); + if (ret < 0) { + sensorhub_err("register sensorhub misc device err(%d)", ret); + goto err_misc_register; + } + + /* create and run sensorhub thread */ + hub_data->sensorhub_task = kthread_run(ssp_sensorhub_thread, + (void *)hub_data, "ssp_sensorhub_thread"); + if (IS_ERR(hub_data->sensorhub_task)) { + ret = PTR_ERR(hub_data->sensorhub_task); + goto err_kthread_create; + } + + return 0; + +err_kthread_create: + misc_deregister(&hub_data->sensorhub_device); +err_misc_register: + input_unregister_device(hub_data->sensorhub_input_dev); +err_input_register_device_sensorhub: +err_input_allocate_device_sensorhub: + complete_all(&hub_data->sensorhub_completion); + wake_lock_destroy(&hub_data->sensorhub_wake_lock); + kfree(hub_data); +exit: + return ret; +} + +void ssp_sensorhub_remove(struct ssp_data *ssp_data) +{ + struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; + + ssp_sensorhub_fops.write = NULL; + ssp_sensorhub_fops.read = NULL; + ssp_sensorhub_fops.unlocked_ioctl = NULL; + + kthread_stop(hub_data->sensorhub_task); + misc_deregister(&hub_data->sensorhub_device); + input_unregister_device(hub_data->sensorhub_input_dev); + complete_all(&hub_data->sensorhub_completion); + wake_lock_destroy(&hub_data->sensorhub_wake_lock); + kfree(hub_data); +} + +MODULE_DESCRIPTION("Seamless Sensor Platform(SSP) sensorhub driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/atmel/ssp_sensorhub.h b/drivers/sensorhub/atmel/ssp_sensorhub.h new file mode 100755 index 00000000000..a0dedd2be08 --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_sensorhub.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2013, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SSP_SENSORHUB__ +#define __SSP_SENSORHUB__ + +#include +#include +#include +#include +#include "ssp.h" + +#define LIST_SIZE 5 +#define MAX_DATA_COPY_TRY 2 +#define WAKE_LOCK_TIMEOUT (3*HZ) +#define COMPLETION_TIMEOUT (2*HZ) +#define DATA REL_RX +#define LARGE_DATA REL_RY +#define NOTICE REL_RZ + +#define SENSORHUB_IOCTL_MAGIC 'S' +#define IOCTL_READ_LARGE_CONTEXT_DATA _IOR(SENSORHUB_IOCTL_MAGIC, 3, char *) + +#define sensorhub_info(str, args...) pr_info("%s: " str, __func__, ##args) +#define sensorhub_debug(str, args...) pr_debug("%s: " str, __func__, ##args) +#define sensorhub_err(str, args...) pr_err("%s: " str, __func__, ##args) + + +struct sensorhub_event { + char *library_data; + int library_length; + struct list_head list; +}; + +struct ssp_sensorhub_data { + struct ssp_data *ssp_data; + struct input_dev *sensorhub_input_dev; + struct miscdevice sensorhub_device; + struct wake_lock sensorhub_wake_lock; + struct completion sensorhub_completion; + struct task_struct *sensorhub_task; + struct sensorhub_event events_head; + struct sensorhub_event events[LIST_SIZE]; + struct sensorhub_event *first_event; + char *large_library_data; + int large_library_length; + int event_number; + wait_queue_head_t sensorhub_wq; + spinlock_t sensorhub_lock; +}; + +void ssp_sensorhub_report_notice(struct ssp_data *ssp_data, char notice); +int ssp_sensorhub_handle_data(struct ssp_data *ssp_data, char *dataframe, + int start, int end); +int ssp_sensorhub_handle_large_data(struct ssp_data *ssp_data, u8 sub_cmd); +int ssp_sensorhub_initialize(struct ssp_data *ssp_data); +void ssp_sensorhub_remove(struct ssp_data *ssp_data); + +#endif diff --git a/drivers/sensorhub/atmel/ssp_sysfs.c b/drivers/sensorhub/atmel/ssp_sysfs.c new file mode 100755 index 00000000000..ad2074148f4 --- /dev/null +++ b/drivers/sensorhub/atmel/ssp_sysfs.c @@ -0,0 +1,524 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* SSP data delay function */ +/*************************************************************************/ + +unsigned int get_msdelay(int64_t dDelayRate) +{ + if (dDelayRate <= SENSOR_NS_DELAY_FASTEST) + return SENSOR_MS_DELAY_FASTEST; + else if (dDelayRate <= SENSOR_NS_DELAY_GAME) + return SENSOR_MS_DELAY_GAME; + else if (dDelayRate <= SENSOR_NS_DELAY_UI) + return SENSOR_MS_DELAY_UI; + else + return SENSOR_MS_DELAY_NORMAL; +} + +unsigned int get_delay_cmd(u8 uDelayRate) +{ + if (uDelayRate <= SENSOR_MS_DELAY_FASTEST) + return SENSOR_CMD_DELAY_FASTEST; + else if (uDelayRate <= SENSOR_MS_DELAY_GAME) + return SENSOR_CMD_DELAY_GAME; + else if (uDelayRate <= SENSOR_MS_DELAY_UI) + return SENSOR_CMD_DELAY_UI; + else + return SENSOR_CMD_DELAY_NORMAL; +} + +static void change_sensor_delay(struct ssp_data *data, + int iSensorType, int64_t dNewDelay) +{ + u8 uBuf[2]; + unsigned int uNewEnable = 0; + int64_t dTempDelay = data->adDelayBuf[iSensorType]; + + if (!(atomic_read(&data->aSensorEnable) & (1 << iSensorType))) { + data->aiCheckStatus[iSensorType] = NO_SENSOR_STATE; + return; + } + + data->adDelayBuf[iSensorType] = dNewDelay; + + if (iSensorType == ORIENTATION_SENSOR) + iSensorType = ACCELEROMETER_SENSOR; + + switch (data->aiCheckStatus[iSensorType]) { + case ADD_SENSOR_STATE: + ssp_dbg("[SSP]: %s - add %u, New = %lldns\n", + __func__, 1 << iSensorType, dNewDelay); + + uBuf[1] = (u8)get_msdelay(dNewDelay); + uBuf[0] = (u8)get_delay_cmd(uBuf[1]); + + if (send_instruction(data, ADD_SENSOR, iSensorType, uBuf, 2) + != SUCCESS) { + uNewEnable = + (unsigned int)atomic_read(&data->aSensorEnable) + & (~(unsigned int)(1 << iSensorType)); + atomic_set(&data->aSensorEnable, uNewEnable); + + data->aiCheckStatus[iSensorType] = NO_SENSOR_STATE; + data->uMissSensorCnt++; + break; + } + + data->aiCheckStatus[iSensorType] = RUNNING_SENSOR_STATE; + + if (iSensorType == PROXIMITY_SENSOR) { + proximity_open_lcd_ldi(data); + proximity_open_calibration(data); + + input_report_abs(data->prox_input_dev, ABS_DISTANCE, 1); + input_sync(data->prox_input_dev); + } + break; + case RUNNING_SENSOR_STATE: + if (get_msdelay(dTempDelay) + == get_msdelay(data->adDelayBuf[iSensorType])) + break; + + ssp_dbg("[SSP]: %s - Change %u, New = %lldns\n", + __func__, 1 << iSensorType, dNewDelay); + + uBuf[1] = (u8)get_msdelay(dNewDelay); + uBuf[0] = (u8)get_delay_cmd(uBuf[1]); + send_instruction(data, CHANGE_DELAY, iSensorType, uBuf, 2); + + break; + default: + break; + } +} + +/*************************************************************************/ +/* SSP data enable function */ +/*************************************************************************/ + +static int ssp_add_sensor(struct ssp_data *data, unsigned int uChangedSensor) +{ + if ((data->aiCheckStatus[uChangedSensor] != INITIALIZATION_STATE) + && (!atomic_read(&data->aSensorEnable))) { + if (data->bCheckSuspend == false) + data->bDebugEnabled = true; + } + + return 0; +} + +static int ssp_remove_sensor(struct ssp_data *data, + unsigned int uChangedSensor, unsigned int uNewEnable) +{ + u8 uBuf[2]; + int64_t dSensorDelay = data->adDelayBuf[uChangedSensor]; + + ssp_dbg("[SSP]: %s - remove sensor = %d, current state = %d\n", + __func__, (1 << uChangedSensor), uNewEnable); + + data->adDelayBuf[uChangedSensor] = DEFUALT_POLLING_DELAY; + + if (uChangedSensor == ORIENTATION_SENSOR) { + if (!(atomic_read(&data->aSensorEnable) + & (1 << ACCELEROMETER_SENSOR))) { + uChangedSensor = ACCELEROMETER_SENSOR; + } else { + change_sensor_delay(data, ACCELEROMETER_SENSOR, + data->adDelayBuf[ACCELEROMETER_SENSOR]); + return 0; + } + } else if (uChangedSensor == ACCELEROMETER_SENSOR) { + if (atomic_read(&data->aSensorEnable) + & (1 << ORIENTATION_SENSOR)) { + change_sensor_delay(data, ORIENTATION_SENSOR, + data->adDelayBuf[ORIENTATION_SENSOR]); + return 0; + } + } + + if (!uNewEnable) { + if (data->bCheckSuspend == false) + data->bDebugEnabled = false; + } + + if (atomic_read(&data->aSensorEnable) & (1 << uChangedSensor)) { + uBuf[1] = (u8)get_msdelay(dSensorDelay); + uBuf[0] = (u8)get_delay_cmd(uBuf[1]); + + send_instruction(data, REMOVE_SENSOR, uChangedSensor, uBuf, 2); + } + data->aiCheckStatus[uChangedSensor] = NO_SENSOR_STATE; + return 0; +} + +/*************************************************************************/ +/* ssp Sysfs */ +/*************************************************************************/ + +static ssize_t show_sensors_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - cur_enable = %d\n", __func__, + atomic_read(&data->aSensorEnable)); + + return sprintf(buf, "%9u\n", atomic_read(&data->aSensorEnable)); +} + +static ssize_t set_sensors_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dTemp; + unsigned int uNewEnable = 0, uChangedSensor = 0; + struct ssp_data *data = dev_get_drvdata(dev); + int iRet; + + if (kstrtoll(buf, 10, &dTemp) < 0) + return -1; + + uNewEnable = (unsigned int)dTemp; + ssp_dbg("[SSP]: %s - new_enable = %u, old_enable = %u\n", __func__, + uNewEnable, atomic_read(&data->aSensorEnable)); + + if (uNewEnable == atomic_read(&data->aSensorEnable)) + return size; + + for (uChangedSensor = 0; uChangedSensor < SENSOR_MAX; uChangedSensor++) { + if ((atomic_read(&data->aSensorEnable) & (1 << uChangedSensor)) + != (uNewEnable & (1 << uChangedSensor))) { + + if (!(uNewEnable & (1 << uChangedSensor))) + ssp_remove_sensor(data, uChangedSensor, + uNewEnable); /* disable */ + else { /* Change to ADD_SENSOR_STATE from KitKat */ + if (data->aiCheckStatus[uChangedSensor] == INITIALIZATION_STATE) { + if (uChangedSensor == ACCELEROMETER_SENSOR) + accel_open_calibration(data); + else if (uChangedSensor == GYROSCOPE_SENSOR) + gyro_open_calibration(data); + else if (uChangedSensor == PRESSURE_SENSOR) + pressure_open_calibration(data); + else if (uChangedSensor == PROXIMITY_SENSOR) { + proximity_open_lcd_ldi(data); + proximity_open_calibration(data); + } + } + data->aiCheckStatus[uChangedSensor] = ADD_SENSOR_STATE; + } + break; + } + } + + atomic_set(&data->aSensorEnable, uNewEnable); + + return size; +} + +static ssize_t show_acc_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[ACCELEROMETER_SENSOR]); +} + +static ssize_t set_acc_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -1; + + if ((atomic_read(&data->aSensorEnable) & (1 << ORIENTATION_SENSOR)) && + (data->adDelayBuf[ORIENTATION_SENSOR] < dNewDelay)) + data->adDelayBuf[ACCELEROMETER_SENSOR] = dNewDelay; + else + change_sensor_delay(data, ACCELEROMETER_SENSOR, dNewDelay); + + return size; +} + +static ssize_t show_ori_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[ORIENTATION_SENSOR]); +} + +static ssize_t set_ori_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -1; + + if (data->aiCheckStatus[ACCELEROMETER_SENSOR] == NO_SENSOR_STATE) { + data->aiCheckStatus[ACCELEROMETER_SENSOR] = ADD_SENSOR_STATE; + change_sensor_delay(data, ORIENTATION_SENSOR, dNewDelay); + } else if (data->aiCheckStatus[ACCELEROMETER_SENSOR] == + RUNNING_SENSOR_STATE) { + if (dNewDelay < data->adDelayBuf[ACCELEROMETER_SENSOR]) + change_sensor_delay(data, + ORIENTATION_SENSOR, dNewDelay); + else + data->adDelayBuf[ORIENTATION_SENSOR] = dNewDelay; + } + return size; +} + +static ssize_t show_gyro_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[GYROSCOPE_SENSOR]); +} + +static ssize_t set_gyro_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -1; + + change_sensor_delay(data, GYROSCOPE_SENSOR, dNewDelay); + return size; +} + +static ssize_t show_mag_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[GEOMAGNETIC_SENSOR]); +} + +static ssize_t set_mag_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -1; + + change_sensor_delay(data, GEOMAGNETIC_SENSOR, dNewDelay); + + return size; +} + +static ssize_t show_pressure_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[PRESSURE_SENSOR]); +} + +static ssize_t set_pressure_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -1; + + change_sensor_delay(data, PRESSURE_SENSOR, dNewDelay); + return size; +} + +static ssize_t show_light_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[LIGHT_SENSOR]); +} + +static ssize_t set_light_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -1; + + change_sensor_delay(data, LIGHT_SENSOR, dNewDelay); + return size; +} + +static ssize_t show_prox_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[PROXIMITY_SENSOR]); +} + +static ssize_t set_prox_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -1; + + change_sensor_delay(data, PROXIMITY_SENSOR, dNewDelay); + return size; +} + +static DEVICE_ATTR(mcu_rev, S_IRUGO, mcu_revision_show, NULL); +static DEVICE_ATTR(mcu_name, S_IRUGO, mcu_model_name_show, NULL); +static DEVICE_ATTR(mcu_update, S_IRUGO, mcu_update_kernel_bin_show, NULL); +static DEVICE_ATTR(mcu_update2, S_IRUGO, + mcu_update_kernel_crashed_bin_show, NULL); +static DEVICE_ATTR(mcu_update_ums, S_IRUGO, mcu_update_ums_bin_show, NULL); +static DEVICE_ATTR(mcu_reset, S_IRUGO, mcu_reset_show, NULL); +static DEVICE_ATTR(mcu_test, S_IRUGO | S_IWUSR | S_IWGRP, + mcu_factorytest_show, mcu_factorytest_store); +static DEVICE_ATTR(mcu_sleep_test, S_IRUGO | S_IWUSR | S_IWGRP, + mcu_sleep_factorytest_show, mcu_sleep_factorytest_store); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, + show_sensors_enable, set_sensors_enable); +static DEVICE_ATTR(mag_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_mag_delay, set_mag_delay); +static DEVICE_ATTR(ori_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_ori_delay, set_ori_delay); + +static struct device_attribute dev_attr_acc_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_acc_delay, set_acc_delay); +static struct device_attribute dev_attr_gyro_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_gyro_delay, set_gyro_delay); +static struct device_attribute dev_attr_pressure_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_pressure_delay, set_pressure_delay); +static struct device_attribute dev_attr_light_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_light_delay, set_light_delay); +static struct device_attribute dev_attr_prox_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_prox_delay, set_prox_delay); + +static struct device_attribute *mcu_attrs[] = { + &dev_attr_enable, + &dev_attr_mcu_rev, + &dev_attr_mcu_name, + &dev_attr_mcu_test, + &dev_attr_mcu_reset, + &dev_attr_mcu_update, + &dev_attr_mcu_update2, + &dev_attr_mcu_update_ums, + &dev_attr_mcu_sleep_test, + &dev_attr_mag_poll_delay, + &dev_attr_ori_poll_delay, + NULL, +}; + +static void initialize_mcu_factorytest(struct ssp_data *data) +{ + sensors_register(data->mcu_device, data, mcu_attrs, "ssp_sensor"); +} + +static void remove_mcu_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->mcu_device, mcu_attrs); +} + +int initialize_sysfs(struct ssp_data *data) +{ + if (device_create_file(&data->acc_input_dev->dev, + &dev_attr_acc_poll_delay)) + goto err_acc_input_dev; + + if (device_create_file(&data->gyro_input_dev->dev, + &dev_attr_gyro_poll_delay)) + goto err_gyro_input_dev; + + if (device_create_file(&data->pressure_input_dev->dev, + &dev_attr_pressure_poll_delay)) + goto err_pressure_input_dev; + + if (device_create_file(&data->light_input_dev->dev, + &dev_attr_light_poll_delay)) + goto err_light_input_dev; + + if (device_create_file(&data->prox_input_dev->dev, + &dev_attr_prox_poll_delay)) + goto err_prox_input_dev; + + initialize_accel_factorytest(data); + initialize_gyro_factorytest(data); + initialize_prox_factorytest(data); + initialize_light_factorytest(data); + initialize_pressure_factorytest(data); + initialize_magnetic_factorytest(data); + initialize_mcu_factorytest(data); + + return SUCCESS; + +err_prox_input_dev: + device_remove_file(&data->light_input_dev->dev, + &dev_attr_light_poll_delay); +err_light_input_dev: + device_remove_file(&data->pressure_input_dev->dev, + &dev_attr_pressure_poll_delay); +err_pressure_input_dev: + device_remove_file(&data->gyro_input_dev->dev, + &dev_attr_gyro_poll_delay); +err_gyro_input_dev: + device_remove_file(&data->acc_input_dev->dev, + &dev_attr_acc_poll_delay); +err_acc_input_dev: + return ERROR; +} + +void remove_sysfs(struct ssp_data *data) +{ + device_remove_file(&data->acc_input_dev->dev, + &dev_attr_acc_poll_delay); + device_remove_file(&data->gyro_input_dev->dev, + &dev_attr_gyro_poll_delay); + device_remove_file(&data->pressure_input_dev->dev, + &dev_attr_pressure_poll_delay); + device_remove_file(&data->light_input_dev->dev, + &dev_attr_light_poll_delay); + device_remove_file(&data->prox_input_dev->dev, + &dev_attr_prox_poll_delay); + + remove_accel_factorytest(data); + remove_gyro_factorytest(data); + remove_prox_factorytest(data); + remove_light_factorytest(data); + remove_pressure_factorytest(data); + remove_magnetic_factorytest(data); + remove_mcu_factorytest(data); + destroy_sensor_class(); +} diff --git a/drivers/sensorhub/gyro_lsm330.c b/drivers/sensorhub/gyro_lsm330.c deleted file mode 100644 index 0a3a473f107..00000000000 --- a/drivers/sensorhub/gyro_lsm330.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -/*************************************************************************/ -/* factory Sysfs */ -/*************************************************************************/ - -#define VENDOR "STM" -#define CHIP_ID "LSM330" - -#define CALIBRATION_FILE_PATH "/efs/gyro_cal_data" -#define CALIBRATION_DATA_AMOUNT 20 - -static ssize_t gyro_vendor_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", VENDOR); -} - -static ssize_t gyro_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", CHIP_ID); -} - -int gyro_open_calibration(struct ssp_data *data) -{ - int iRet = 0; - mm_segment_t old_fs; - struct file *cal_filp = NULL; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); - if (IS_ERR(cal_filp)) { - set_fs(old_fs); - iRet = PTR_ERR(cal_filp); - - data->gyrocal.x = 0; - data->gyrocal.y = 0; - data->gyrocal.z = 0; - - return iRet; - } - - iRet = cal_filp->f_op->read(cal_filp, (char *)&data->gyrocal, - 3 * sizeof(int), &cal_filp->f_pos); - if (iRet != 3 * sizeof(int)) - iRet = -EIO; - - filp_close(cal_filp, current->files); - set_fs(old_fs); - - ssp_dbg("[SSP]: open gyro calibration %d, %d, %d\n", - data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); - return iRet; -} - -static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) -{ - int iRet = 0; - struct file *cal_filp = NULL; - mm_segment_t old_fs; - - data->gyrocal.x = iCalData[0]; - data->gyrocal.y = iCalData[1]; - data->gyrocal.z = iCalData[2]; - - ssp_dbg("[SSP]: do gyro calibrate %d, %d, %d\n", - data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); - if (IS_ERR(cal_filp)) { - pr_err("[SSP]: %s - Can't open calibration file\n", __func__); - set_fs(old_fs); - iRet = PTR_ERR(cal_filp); - return -EIO; - } - - iRet = cal_filp->f_op->write(cal_filp, (char *)&data->gyrocal, - 3 * sizeof(int), &cal_filp->f_pos); - if (iRet != 3 * sizeof(int)) { - pr_err("[SSP]: %s - Can't write gyro cal to file\n", __func__); - iRet = -EIO; - } - - filp_close(cal_filp, current->files); - set_fs(old_fs); - - return iRet; -} - -static ssize_t gyro_power_off(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssp_dbg("[SSP]: %s\n", __func__); - - return sprintf(buf, "%d\n", 1); -} - -static ssize_t gyro_power_on(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssp_dbg("[SSP]: %s\n", __func__); - - return sprintf(buf, "%d\n", 1); -} - -static ssize_t gyro_get_temp(struct device *dev, - struct device_attribute *attr, char *buf) -{ - char chTempBuf[2] = { 0, 10}, chTemp = 0; - int iDelayCnt = 0, iRet = 0; - struct ssp_data *data = dev_get_drvdata(dev); - - if (!(data->uSensorState & (1 << GYROSCOPE_SENSOR))) - goto exit; - - data->uFactorydataReady = 0; - memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); - - iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_TEMP_FACTORY, - chTempBuf, 2); - - while (!(data->uFactorydataReady & (1 << GYROSCOPE_TEMP_FACTORY)) - && (iDelayCnt++ < 150) - && (iRet == SUCCESS)) - msleep(20); - - if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { - pr_err("[SSP]: %s - Gyro Temp Timeout!!\n", __func__); - goto exit; - } - - mdelay(5); - - chTemp = (char)data->uFactorydata[0]; - ssp_dbg("[SSP]: %s - %d\n", __func__, chTemp); -exit: - return sprintf(buf, "%d\n", chTemp); -} - -static ssize_t gyro_selftest_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - char chTempBuf[2] = { 3, 200}; - u8 uFifoPass = 2; - u8 uBypassPass = 2; - u8 uCalPass = 0; - s16 iNOST[3] = {0,}, iST[3] = {0,}, iCalData[3] = {0,}; - int iZeroRateData[3] = {0,}; - int iDelayCnt = 0, iRet = 0; - struct ssp_data *data = dev_get_drvdata(dev); - - data->uFactorydataReady = 0; - memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); - - iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_FACTORY, - chTempBuf, 2); - - while (!(data->uFactorydataReady & (1 << GYROSCOPE_FACTORY)) - && (iDelayCnt++ < 250) - && (iRet == SUCCESS)) - msleep(20); - - if ((iDelayCnt >= 250) || (iRet != SUCCESS)) { - pr_err("[SSP]: %s - Gyro Selftest Timeout!!\n", __func__); - goto exit; - } - mdelay(5); - - iNOST[0] = (s16)((data->uFactorydata[0] << 8) + data->uFactorydata[1]); - iNOST[1] = (s16)((data->uFactorydata[2] << 8) + data->uFactorydata[3]); - iNOST[2] = (s16)((data->uFactorydata[4] << 8) + data->uFactorydata[5]); - - iST[0] = (s16)((data->uFactorydata[6] << 8) + data->uFactorydata[7]); - iST[1] = (s16)((data->uFactorydata[8] << 8) + data->uFactorydata[9]); - iST[2] = (s16)((data->uFactorydata[10] << 8) + data->uFactorydata[11]); - - iCalData[0] = - (s16)((data->uFactorydata[12] << 8) + data->uFactorydata[13]); - iCalData[1] = - (s16)((data->uFactorydata[14] << 8) + data->uFactorydata[15]); - iCalData[2] = - (s16)((data->uFactorydata[16] << 8) + data->uFactorydata[17]); - - iZeroRateData[0] = - (s16)((data->uFactorydata[18] << 8) + data->uFactorydata[19]); - iZeroRateData[1] = - (s16)((data->uFactorydata[20] << 8) + data->uFactorydata[21]); - iZeroRateData[2] = - (s16)((data->uFactorydata[22] << 8) + data->uFactorydata[23]); - - uCalPass = data->uFactorydata[24]; - uFifoPass = data->uFactorydata[25]; - uBypassPass = data->uFactorydata[26]; - - if (uFifoPass && uBypassPass && uCalPass) - save_gyro_caldata(data, iCalData); - -exit: - ssp_dbg("[SSP]: Gyro Selftest - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", - iNOST[0], iNOST[1], iNOST[2], iST[0], iST[1], iST[2], - iZeroRateData[0], iZeroRateData[1], iZeroRateData[2], - uFifoPass & uBypassPass & uCalPass, uFifoPass, uCalPass); - - return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", - iNOST[0], iNOST[1], iNOST[2], iST[0], iST[1], iST[2], - iZeroRateData[0], iZeroRateData[1], iZeroRateData[2], - uFifoPass & uBypassPass & uCalPass, uFifoPass, uCalPass); -} - -static ssize_t gyro_selftest_dps_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - int iNewDps = 0; - int iDelayCnt = 0, iRet = 0; - char chTempBuf[2] = { 0, 10 }; - - struct ssp_data *data = dev_get_drvdata(dev); - - if (!(data->uSensorState & (1 << GYROSCOPE_SENSOR))) - goto exit; - - sscanf(buf, "%d", &iNewDps); - - if (iNewDps == GYROSCOPE_DPS250) - chTempBuf[0] = 0; - else if (iNewDps == GYROSCOPE_DPS500) - chTempBuf[0] = 1; - else if (iNewDps == GYROSCOPE_DPS2000) - chTempBuf[0] = 2; - else { - chTempBuf[0] = 1; - iNewDps = GYROSCOPE_DPS500; - } - - data->uFactorydataReady = 0; - memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); - - iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_DPS_FACTORY, - chTempBuf, 2); - - while (!(data->uFactorydataReady & (1 << GYROSCOPE_DPS_FACTORY)) - && (iDelayCnt++ < 150) - && (iRet == SUCCESS)) - msleep(20); - - if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { - pr_err("[SSP]: %s - Gyro Selftest DPS Timeout!!\n", __func__); - goto exit; - } - - mdelay(5); - - if (data->uFactorydata[0] != SUCCESS) { - pr_err("[SSP]: %s - Gyro Selftest DPS Error!!\n", __func__); - goto exit; - } - - data->uGyroDps = (unsigned int)iNewDps; - pr_err("[SSP]: %s - %u dps stored\n", __func__, data->uGyroDps); -exit: - return count; -} - -static ssize_t gyro_selftest_dps_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%u\n", data->uGyroDps); -} - -static DEVICE_ATTR(name, S_IRUGO, gyro_name_show, NULL); -static DEVICE_ATTR(vendor, S_IRUGO, gyro_vendor_show, NULL); -static DEVICE_ATTR(power_off, S_IRUGO, gyro_power_off, NULL); -static DEVICE_ATTR(power_on, S_IRUGO, gyro_power_on, NULL); -static DEVICE_ATTR(temperature, S_IRUGO, gyro_get_temp, NULL); -static DEVICE_ATTR(selftest, S_IRUGO, gyro_selftest_show, NULL); -static DEVICE_ATTR(selftest_dps, S_IRUGO | S_IWUSR | S_IWGRP, - gyro_selftest_dps_show, gyro_selftest_dps_store); - -static struct device_attribute *gyro_attrs[] = { - &dev_attr_name, - &dev_attr_vendor, - &dev_attr_selftest, - &dev_attr_power_on, - &dev_attr_power_off, - &dev_attr_temperature, - &dev_attr_selftest_dps, - NULL, -}; - -void initialize_gyro_factorytest(struct ssp_data *data) -{ - sensors_register(data->gyro_device, data, gyro_attrs, "gyro_sensor"); -} - -void remove_gyro_factorytest(struct ssp_data *data) -{ - sensors_unregister(data->gyro_device, gyro_attrs); -} diff --git a/drivers/sensorhub/light_cm36651.c b/drivers/sensorhub/light_cm36651.c deleted file mode 100644 index 68081e44deb..00000000000 --- a/drivers/sensorhub/light_cm36651.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -#define VENDOR "CAPELLA" -#define CHIP_ID "CM36651" - -/*************************************************************************/ -/* factory Sysfs */ -/*************************************************************************/ - -static ssize_t light_vendor_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", VENDOR); -} - -static ssize_t light_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", CHIP_ID); -} - -static ssize_t light_lux_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%u,%u,%u,%u\n", - data->buf[LIGHT_SENSOR].r, data->buf[LIGHT_SENSOR].g, - data->buf[LIGHT_SENSOR].b, data->buf[LIGHT_SENSOR].w); -} - -static ssize_t light_data_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%u,%u,%u,%u\n", - data->buf[LIGHT_SENSOR].r, data->buf[LIGHT_SENSOR].g, - data->buf[LIGHT_SENSOR].b, data->buf[LIGHT_SENSOR].w); -} - -static DEVICE_ATTR(vendor, S_IRUGO, light_vendor_show, NULL); -static DEVICE_ATTR(name, S_IRUGO, light_name_show, NULL); -static DEVICE_ATTR(lux, S_IRUGO, light_lux_show, NULL); -static DEVICE_ATTR(raw_data, S_IRUGO, light_data_show, NULL); - -static struct device_attribute *light_attrs[] = { - &dev_attr_vendor, - &dev_attr_name, - &dev_attr_lux, - &dev_attr_raw_data, - NULL, -}; - -void initialize_light_factorytest(struct ssp_data *data) -{ - sensors_register(data->light_device, data, light_attrs, "light_sensor"); -} - -void remove_light_factorytest(struct ssp_data *data) -{ - sensors_unregister(data->light_device, light_attrs); -} diff --git a/drivers/sensorhub/magnetic_ak8963c.c b/drivers/sensorhub/magnetic_ak8963c.c deleted file mode 100644 index ccd1723bdae..00000000000 --- a/drivers/sensorhub/magnetic_ak8963c.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -/*************************************************************************/ -/* factory Sysfs */ -/*************************************************************************/ - -#define VENDOR "AKM" -#define CHIP_ID "AK8963C" - -#define GYROSCOPE_DATA_SPEC_MIN -6500 -#define GYROSCOPE_DATA_SPEC_MAX 6500 - -#define GYROSCOPE_SELFTEST_X_SPEC_MIN -200 -#define GYROSCOPE_SELFTEST_X_SPEC_MAX 200 - -#define GYROSCOPE_SELFTEST_Y_SPEC_MIN -200 -#define GYROSCOPE_SELFTEST_Y_SPEC_MAX 200 - -#define GYROSCOPE_SELFTEST_Z_SPEC_MIN -3200 -#define GYROSCOPE_SELFTEST_Z_SPEC_MAX -800 - -static ssize_t magnetic_vendor_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", VENDOR); -} - -static ssize_t magnetic_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", CHIP_ID); -} - -static ssize_t raw_data_read(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", - data->buf[GEOMAGNETIC_SENSOR].x, - data->buf[GEOMAGNETIC_SENSOR].y, - data->buf[GEOMAGNETIC_SENSOR].z); -} - -static int check_data_spec(struct ssp_data *data) -{ - if ((data->buf[GEOMAGNETIC_SENSOR].x == 0) && - (data->buf[GEOMAGNETIC_SENSOR].y == 0) && - (data->buf[GEOMAGNETIC_SENSOR].z == 0)) - return FAIL; - else if ((data->buf[GEOMAGNETIC_SENSOR].x > GYROSCOPE_DATA_SPEC_MAX) || - (data->buf[GEOMAGNETIC_SENSOR].x < GYROSCOPE_DATA_SPEC_MIN) || - (data->buf[GEOMAGNETIC_SENSOR].y > GYROSCOPE_DATA_SPEC_MAX) || - (data->buf[GEOMAGNETIC_SENSOR].y < GYROSCOPE_DATA_SPEC_MIN) || - (data->buf[GEOMAGNETIC_SENSOR].z > GYROSCOPE_DATA_SPEC_MAX) || - (data->buf[GEOMAGNETIC_SENSOR].z < GYROSCOPE_DATA_SPEC_MIN)) - return FAIL; - else - return SUCCESS; -} - -static ssize_t adc_data_read(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool bSuccess = false; - u8 chTempbuf[2] = {1, 20}; - s16 iSensorBuf[3] = {0, }; - int iRetries = 20; - struct ssp_data *data = dev_get_drvdata(dev); - - data->buf[GEOMAGNETIC_SENSOR].x = 0; - data->buf[GEOMAGNETIC_SENSOR].y = 0; - data->buf[GEOMAGNETIC_SENSOR].z = 0; - - if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_SENSOR))) - send_instruction(data, ADD_SENSOR, GEOMAGNETIC_SENSOR, - chTempbuf, 2); - - do { - msleep(50); - if (check_data_spec(data) == SUCCESS) - break; - } while (--iRetries); - - if (iRetries > 0) - bSuccess = true; - - iSensorBuf[0] = data->buf[GEOMAGNETIC_SENSOR].x; - iSensorBuf[1] = data->buf[GEOMAGNETIC_SENSOR].y; - iSensorBuf[2] = data->buf[GEOMAGNETIC_SENSOR].z; - - if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_SENSOR))) - send_instruction(data, REMOVE_SENSOR, GEOMAGNETIC_SENSOR, - chTempbuf, 2); - - pr_info("[SSP]: %s - x = %d, y = %d, z = %d\n", __func__, - iSensorBuf[0], iSensorBuf[1], iSensorBuf[2]); - - return sprintf(buf, "%s,%d,%d,%d\n", (bSuccess ? "OK" : "NG"), - iSensorBuf[0], iSensorBuf[1], iSensorBuf[2]); -} - -static ssize_t magnetic_get_asa(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%d,%d,%d\n", (s16)data->uFuseRomData[0], - (s16)data->uFuseRomData[1], (s16)data->uFuseRomData[2]); -} - -static ssize_t magnetic_get_status(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool bSuccess; - struct ssp_data *data = dev_get_drvdata(dev); - - if ((data->uFuseRomData[0] == 0) || - (data->uFuseRomData[0] == 0xff) || - (data->uFuseRomData[1] == 0) || - (data->uFuseRomData[1] == 0xff) || - (data->uFuseRomData[2] == 0) || - (data->uFuseRomData[2] == 0xff)) - bSuccess = false; - else - bSuccess = true; - - return sprintf(buf, "%s,%u\n", (bSuccess ? "OK" : "NG"), bSuccess); -} - -static ssize_t magnetic_get_selftest(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool bSelftestPassed = false; - char chTempBuf[2] = { 0, 10 }; - s16 iSF_X = 0, iSF_Y = 0, iSF_Z = 0; - int iDelayCnt = 0, iRet = 0, iTimeoutReties = 0, iSpecOutReties = 0; - struct ssp_data *data = dev_get_drvdata(dev); - -reties: - iDelayCnt = 0; - data->uFactorydataReady = 0; - memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); - - iRet = send_instruction(data, FACTORY_MODE, GEOMAGNETIC_FACTORY, - chTempBuf, 2); - - while (!(data->uFactorydataReady & (1 << GEOMAGNETIC_FACTORY)) - && (iDelayCnt++ < 50) - && (iRet == SUCCESS)) - msleep(20); - - if ((iDelayCnt >= 50) || (iRet != SUCCESS)) { - pr_err("[SSP]: %s - Magnetic Selftest Timeout!! %d\n", - __func__, iRet); - if (iTimeoutReties++ < 3) - goto reties; - else - goto exit; - } - - mdelay(5); - - iSF_X = (s16)((data->uFactorydata[0] << 8) + data->uFactorydata[1]); - iSF_Y = (s16)((data->uFactorydata[2] << 8) + data->uFactorydata[3]); - iSF_Z = (s16)((data->uFactorydata[4] << 8) + data->uFactorydata[5]); - - iSF_X = (s16)(((int)iSF_X * ((int)data->uFuseRomData[0] + 128)) >> 8); - iSF_Y = (s16)(((int)iSF_Y * ((int)data->uFuseRomData[1] + 128)) >> 8); - iSF_Z = (s16)(((int)iSF_Z * ((int)data->uFuseRomData[2] + 128)) >> 8); - - pr_info("[SSP] %s: self test x = %d, y = %d, z = %d\n", - __func__, iSF_X, iSF_Y, iSF_Z); - if ((iSF_X >= GYROSCOPE_SELFTEST_X_SPEC_MIN) - && (iSF_X <= GYROSCOPE_SELFTEST_X_SPEC_MAX)) - pr_info("[SSP] x passed self test, expect -200<=x<=200\n"); - else - pr_info("[SSP] x failed self test, expect -200<=x<=200\n"); - if ((iSF_Y >= GYROSCOPE_SELFTEST_Y_SPEC_MIN) - && (iSF_Y <= GYROSCOPE_SELFTEST_Y_SPEC_MAX)) - pr_info("[SSP] y passed self test, expect -200<=y<=200\n"); - else - pr_info("[SSP] y failed self test, expect -200<=y<=200\n"); - if ((iSF_Z >= GYROSCOPE_SELFTEST_Z_SPEC_MIN) - && (iSF_Z <= GYROSCOPE_SELFTEST_Z_SPEC_MAX)) - pr_info("[SSP] z passed self test, expect -3200<=z<=-800\n"); - else - pr_info("[SSP] z failed self test, expect -3200<=z<=-800\n"); - - if ((iSF_X >= GYROSCOPE_SELFTEST_X_SPEC_MIN) - && (iSF_X <= GYROSCOPE_SELFTEST_X_SPEC_MAX) - && (iSF_Y >= GYROSCOPE_SELFTEST_Y_SPEC_MIN) - && (iSF_Y <= GYROSCOPE_SELFTEST_Y_SPEC_MAX) - && (iSF_Z >= GYROSCOPE_SELFTEST_Z_SPEC_MIN) - && (iSF_Z <= GYROSCOPE_SELFTEST_Z_SPEC_MAX)) - bSelftestPassed = true; - - if ((bSelftestPassed == false) && (iSpecOutReties++ < 5)) - goto reties; -exit: - return sprintf(buf, "%u,%d,%d,%d\n", - bSelftestPassed, iSF_X, iSF_Y, iSF_Z); -} - -static ssize_t magnetic_check_registers(struct device *dev, - struct device_attribute *attr, char *buf) -{ - u8 uBuf[13] = {0,}; - - return sprintf(buf, "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n", - uBuf[0], uBuf[1], uBuf[2], uBuf[3], uBuf[4], uBuf[5], - uBuf[6], uBuf[7], uBuf[8], uBuf[9], uBuf[10], uBuf[11], - uBuf[12]); -} - -static ssize_t magnetic_check_cntl(struct device *dev, - struct device_attribute *attr, char *strbuf) -{ - bool bSuccess = false; - - return sprintf(strbuf, "%s,%d,%d,%d\n", - (!bSuccess ? "OK" : "NG"), 0, 0, 0); -} - -static DEVICE_ATTR(name, S_IRUGO, magnetic_name_show, NULL); -static DEVICE_ATTR(vendor, S_IRUGO, magnetic_vendor_show, NULL); -static DEVICE_ATTR(raw_data, S_IRUGO, raw_data_read, NULL); -static DEVICE_ATTR(status, S_IRUGO, magnetic_get_status, NULL); -static DEVICE_ATTR(adc, S_IRUGO, adc_data_read, NULL); -static DEVICE_ATTR(dac, S_IRUGO, magnetic_check_cntl, NULL); -static DEVICE_ATTR(selftest, S_IRUGO, magnetic_get_selftest, NULL); -static DEVICE_ATTR(ak8963_asa, S_IRUGO, magnetic_get_asa, NULL); -static DEVICE_ATTR(ak8963_chk_registers, S_IRUGO, - magnetic_check_registers, NULL); - -static struct device_attribute *mag_attrs[] = { - &dev_attr_name, - &dev_attr_vendor, - &dev_attr_adc, - &dev_attr_raw_data, - &dev_attr_status, - &dev_attr_selftest, - &dev_attr_ak8963_asa, - &dev_attr_ak8963_chk_registers, - &dev_attr_dac, - NULL, -}; - -void initialize_magnetic_factorytest(struct ssp_data *data) -{ - sensors_register(data->mag_device, data, mag_attrs, "magnetic_sensor"); -} - -void remove_magnetic_factorytest(struct ssp_data *data) -{ - sensors_unregister(data->mag_device, mag_attrs); -} diff --git a/drivers/sensorhub/mcu_at32uc3l0128.c b/drivers/sensorhub/mcu_at32uc3l0128.c deleted file mode 100644 index 0f63a8dd70d..00000000000 --- a/drivers/sensorhub/mcu_at32uc3l0128.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -/*************************************************************************/ -/* factory Sysfs */ -/*************************************************************************/ - -#define MODEL_NAME "AT32UC3L0128" - -ssize_t mcu_revision_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "AT01120%u,AT01120%u\n", get_module_rev(), - data->uCurFirmRev); -} - -ssize_t mcu_model_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", MODEL_NAME); -} - -ssize_t mcu_update_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool bSuccess = false; - int iRet = 0; - struct ssp_data *data = dev_get_drvdata(dev); - - ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); - - if (data->bSspShutdown == false) { - disable_irq(data->iIrq); - disable_irq_wake(data->iIrq); - data->bSspShutdown = true; - } - - iRet = update_mcu_bin(data); - if (iRet < 0) { - ssp_dbg("[SSP]: %s - update_mcu_bin failed!\n", __func__); - goto exit; - } - - iRet = initialize_mcu(data); - if (iRet < 0) { - ssp_dbg("[SSP]: %s - initialize_mcu failed!\n", __func__); - goto exit; - } - - sync_sensor_state(data); - - enable_irq(data->iIrq); - enable_irq_wake(data->iIrq); - -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - ssp_report_sensorhub_notice(data, MSG2SSP_AP_STATUS_RESET); -#endif - - bSuccess = true; -exit: - return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); -} - -ssize_t mcu_update2_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool bSuccess = false; - int iRet = 0; - struct ssp_data *data = dev_get_drvdata(dev); - - ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); - - if (data->bSspShutdown == false) { - disable_irq(data->iIrq); - disable_irq_wake(data->iIrq); - data->bSspShutdown = true; - } - - iRet = update_crashed_mcu_bin(data); - if (iRet < 0) { - ssp_dbg("[SSP]: %s - update_mcu_bin failed!\n", __func__); - goto exit; - } - - iRet = initialize_mcu(data); - if (iRet < 0) { - ssp_dbg("[SSP]: %s - initialize_mcu failed!\n", __func__); - goto exit; - } - - sync_sensor_state(data); - - enable_irq(data->iIrq); - enable_irq_wake(data->iIrq); - -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - ssp_report_sensorhub_notice(data, MSG2SSP_AP_STATUS_RESET); -#endif - - bSuccess = true; -exit: - return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); -} - -ssize_t mcu_reset_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - reset_mcu(data); - - return sprintf(buf, "OK\n"); -} - -ssize_t mcu_factorytest_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct ssp_data *data = dev_get_drvdata(dev); - char chTempBuf[2] = {0, 10}; - int iRet = 0; - - if (sysfs_streq(buf, "1")) { - data->uFactorydataReady = 0; - memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); - - data->bMcuIRQTestSuccessed = false; - data->uTimeOutCnt = 0; - - iRet = send_instruction(data, FACTORY_MODE, - MCU_FACTORY, chTempBuf, 2); - if (data->uTimeOutCnt == 0) - data->bMcuIRQTestSuccessed = true; - } else { - pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); - return -EINVAL; - } - - ssp_dbg("[SSP]: MCU Factory Test Start! - %d\n", iRet); - - return size; -} - -ssize_t mcu_factorytest_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool bMcuTestSuccessed = false; - struct ssp_data *data = dev_get_drvdata(dev); - - if (data->bSspShutdown == true) { - ssp_dbg("[SSP]: %s - MCU Bin is crashed\n", __func__); - return sprintf(buf, "NG,NG,NG\n"); - } - - if (data->uFactorydataReady & (1 << MCU_FACTORY)) { - ssp_dbg("[SSP] MCU Factory Test Data : %u, %u, %u, %u, %u\n", - data->uFactorydata[0], data->uFactorydata[1], - data->uFactorydata[2], data->uFactorydata[3], - data->uFactorydata[4]); - - /* system clock, RTC, I2C Master, I2C Slave, externel pin */ - if ((data->uFactorydata[0] == SUCCESS) - && (data->uFactorydata[1] == SUCCESS) - && (data->uFactorydata[2] == SUCCESS) - && (data->uFactorydata[3] == SUCCESS) - && (data->uFactorydata[4] == SUCCESS)) - bMcuTestSuccessed = true; - } else { - pr_err("[SSP]: %s - The Sensorhub is not ready %u\n", __func__, - data->uFactorydataReady); - } - - ssp_dbg("[SSP]: MCU Factory Test Result - %s, %s, %s\n", MODEL_NAME, - (data->bMcuIRQTestSuccessed ? "OK" : "NG"), - (bMcuTestSuccessed ? "OK" : "NG")); - - return sprintf(buf, "%s,%s,%s\n", MODEL_NAME, - (data->bMcuIRQTestSuccessed ? "OK" : "NG"), - (bMcuTestSuccessed ? "OK" : "NG")); -} - -ssize_t mcu_sleep_factorytest_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct ssp_data *data = dev_get_drvdata(dev); - char chTempBuf[2] = {0, 10}; - int iRet = 0; - - if (sysfs_streq(buf, "1")) { - data->uFactorydataReady = 0; - memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); - - iRet = send_instruction(data, FACTORY_MODE, - MCU_SLEEP_FACTORY, chTempBuf, 2); - } else { - pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); - return -EINVAL; - } - - ssp_dbg("[SSP]: MCU Sleep Factory Test Start! - %d\n", iRet); - - return size; -} - -ssize_t mcu_sleep_factorytest_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int iDataIdx, iSensorData = 0; - struct ssp_data *data = dev_get_drvdata(dev); - struct sensor_value fsb[SENSOR_MAX]; - - if (!(data->uFactorydataReady & (1 << MCU_SLEEP_FACTORY))) { - pr_err("[SSP]: %s - The Sensorhub is not ready\n", __func__); - goto exit; - } - - for (iDataIdx = 0; iDataIdx < FACTORY_DATA_MAX;) { - iSensorData = (int)data->uFactorydata[iDataIdx++]; - - if ((iSensorData < 0) || - (iSensorData >= (SENSOR_MAX - 1))) { - pr_err("[SSP]: %s - Mcu data frame error %d\n", - __func__, iSensorData); - goto exit; - } - - data->get_sensor_data[iSensorData]((char *)data->uFactorydata, - &iDataIdx, &(fsb[iSensorData])); - } - - convert_acc_data(&fsb[ACCELEROMETER_SENSOR].x); - convert_acc_data(&fsb[ACCELEROMETER_SENSOR].y); - convert_acc_data(&fsb[ACCELEROMETER_SENSOR].z); - -exit: - ssp_dbg("[SSP]: %s Result - " - "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%u,%u,%u,%u,%u\n", __func__, - fsb[ACCELEROMETER_SENSOR].x, fsb[ACCELEROMETER_SENSOR].y, - fsb[ACCELEROMETER_SENSOR].z, fsb[GYROSCOPE_SENSOR].x, - fsb[GYROSCOPE_SENSOR].y, fsb[GYROSCOPE_SENSOR].z, - fsb[GEOMAGNETIC_SENSOR].x, fsb[GEOMAGNETIC_SENSOR].y, - fsb[GEOMAGNETIC_SENSOR].z, fsb[PRESSURE_SENSOR].pressure[0], - fsb[PRESSURE_SENSOR].pressure[1], fsb[PROXIMITY_SENSOR].prox[1], - fsb[LIGHT_SENSOR].r, fsb[LIGHT_SENSOR].g, fsb[LIGHT_SENSOR].b, - fsb[LIGHT_SENSOR].w); - - return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%u,%u,%u,%u,%u\n", - fsb[ACCELEROMETER_SENSOR].x, fsb[ACCELEROMETER_SENSOR].y, - fsb[ACCELEROMETER_SENSOR].z, fsb[GYROSCOPE_SENSOR].x, - fsb[GYROSCOPE_SENSOR].y, fsb[GYROSCOPE_SENSOR].z, - fsb[GEOMAGNETIC_SENSOR].x, fsb[GEOMAGNETIC_SENSOR].y, - fsb[GEOMAGNETIC_SENSOR].z, fsb[PRESSURE_SENSOR].pressure[0], - fsb[PRESSURE_SENSOR].pressure[1], fsb[PROXIMITY_SENSOR].prox[1], - fsb[LIGHT_SENSOR].r, fsb[LIGHT_SENSOR].g, fsb[LIGHT_SENSOR].b, - fsb[LIGHT_SENSOR].w); -} diff --git a/drivers/sensorhub/pressure_bmp182.c b/drivers/sensorhub/pressure_bmp182.c deleted file mode 100644 index d5896f32bc2..00000000000 --- a/drivers/sensorhub/pressure_bmp182.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -#define VENDOR "BOSCH" -#define CHIP_ID "BMP180" - -#define CALIBRATION_FILE_PATH "/efs/FactoryApp/baro_delta" - -#define PR_ABS_MAX 8388607 /* 24 bit 2'compl */ -#define PR_ABS_MIN -8388608 - -/*************************************************************************/ -/* factory Sysfs */ -/*************************************************************************/ - -static ssize_t sea_level_pressure_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct ssp_data *data = dev_get_drvdata(dev); - int iNewSeaLevelPressure; - - sscanf(buf, "%d", &iNewSeaLevelPressure); - - if (iNewSeaLevelPressure == 0) { - pr_info("%s, our->temperature = 0\n", __func__); - iNewSeaLevelPressure = -1; - } - - input_report_rel(data->pressure_input_dev, REL_DIAL, - iNewSeaLevelPressure); - input_sync(data->pressure_input_dev); - - return size; -} - -int pressure_open_calibration(struct ssp_data *data) -{ - char chBuf[10] = {0,}; - int iErr = 0; - mm_segment_t old_fs; - struct file *cal_filp = NULL; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); - if (IS_ERR(cal_filp)) { - iErr = PTR_ERR(cal_filp); - if (iErr != -ENOENT) - pr_err("[SSP]: %s - Can't open calibration file(%d)\n", - __func__, iErr); - set_fs(old_fs); - return iErr; - } - iErr = cal_filp->f_op->read(cal_filp, - chBuf, 10 * sizeof(char), &cal_filp->f_pos); - if (iErr < 0) { - pr_err("[SSP]: %s - Can't read the cal data from file (%d)\n", - __func__, iErr); - return iErr; - } - filp_close(cal_filp, current->files); - set_fs(old_fs); - - iErr = kstrtoint(chBuf, 10, &data->iPressureCal); - if (iErr < 0) { - pr_err("[SSP]: %s - kstrtoint failed. %d", __func__, iErr); - return iErr; - } - - ssp_dbg("[SSP]: open barometer calibration %d\n", data->iPressureCal); - - if (data->iPressureCal < PR_ABS_MIN || data->iPressureCal > PR_ABS_MAX) - pr_err("[SSP]: %s - wrong offset value!!!\n", __func__); - - return iErr; -} - -static ssize_t pressure_cabratioin_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct ssp_data *data = dev_get_drvdata(dev); - int iPressureCal = 0, iErr = 0; - - iErr = kstrtoint(buf, 10, &iPressureCal); - if (iErr < 0) { - pr_err("[SSP]: %s - kstrtoint failed.(%d)", __func__, iErr); - return iErr; - } - - if (iPressureCal < PR_ABS_MIN || iPressureCal > PR_ABS_MAX) - return -EINVAL; - - data->iPressureCal = (s32)iPressureCal; - - return size; -} - -static ssize_t pressure_cabratioin_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - pressure_open_calibration(data); - - return sprintf(buf, "%d\n", data->iPressureCal); -} - -static ssize_t eeprom_check_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool bSuccess = false; - char chTempBuf[2] = {0, 10}; - int iRet, iDelayCnt = 0; - struct ssp_data *data = dev_get_drvdata(dev); - - data->uFactorydataReady = 0; - memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); - - iRet = send_instruction(data, FACTORY_MODE, PRESSURE_FACTORY, - chTempBuf, 2); - - while (!(data->uFactorydataReady & (1 << PRESSURE_FACTORY)) - && (iDelayCnt++ < 150) - && (iRet == SUCCESS)) - msleep(20); - - if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { - pr_err("[SSP]: %s - Pressure Selftest Timeout!!\n", - __func__); - goto exit; - } - - mdelay(5); - - bSuccess = (bool)(!!data->uFactorydata[0]); - ssp_dbg("[SSP]: %s - %u\n", __func__, bSuccess); - -exit: - return snprintf(buf, PAGE_SIZE, "%d", bSuccess); -} - -/* sysfs for vendor & name */ -static ssize_t pressure_vendor_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", VENDOR); -} - -static ssize_t pressure_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", CHIP_ID); -} - -static DEVICE_ATTR(vendor, S_IRUGO, pressure_vendor_show, NULL); -static DEVICE_ATTR(name, S_IRUGO, pressure_name_show, NULL); -static DEVICE_ATTR(eeprom_check, S_IRUGO, eeprom_check_show, NULL); -static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, - pressure_cabratioin_show, pressure_cabratioin_store); -static DEVICE_ATTR(sea_level_pressure, S_IRUGO | S_IWUSR | S_IWGRP, - NULL, sea_level_pressure_store); - -static struct device_attribute *pressure_attrs[] = { - &dev_attr_vendor, - &dev_attr_name, - &dev_attr_calibration, - &dev_attr_sea_level_pressure, - &dev_attr_eeprom_check, - NULL, -}; - -void initialize_pressure_factorytest(struct ssp_data *data) -{ - sensors_register(data->prs_device, data, pressure_attrs, - "barometer_sensor"); -} - -void remove_pressure_factorytest(struct ssp_data *data) -{ - sensors_unregister(data->prs_device, pressure_attrs); -} diff --git a/drivers/sensorhub/prox_cm36651.c b/drivers/sensorhub/prox_cm36651.c deleted file mode 100644 index a7f91a79f37..00000000000 --- a/drivers/sensorhub/prox_cm36651.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -#define VENDOR "CAPELLA" -#define CHIP_ID "CM36651" - -#define CANCELATION_FILE_PATH "/efs/prox_cal" -#define LCD_LDI_FILE_PATH "/sys/class/lcd/panel/window_type" - -#define LINE_1 '4' -#define LINE_2 '2' - -#define LDI_OTHERS '0' -#define LDI_GRAY '1' -#define LDI_WHITE '2' - -#define CANCELATION_THRESHOLD 9 -#define DEFAULT_THRESHOLD 13 -#define OTHERS_OCTA_DEFAULT_THRESHOLD 14 -#define WHITE_OCTA_DEFAULT_THRESHOLD 13 -#define GRAY_OCTA_DEFAULT_THRESHOLD 12 - -/*************************************************************************/ -/* factory Sysfs */ -/*************************************************************************/ - -static ssize_t prox_vendor_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", VENDOR); -} - -static ssize_t prox_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", CHIP_ID); -} - -static ssize_t proximity_avg_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", - data->buf[PROXIMITY_RAW].prox[1], - data->buf[PROXIMITY_RAW].prox[2], - data->buf[PROXIMITY_RAW].prox[3]); -} - -static ssize_t proximity_avg_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - char chTempbuf[2] = { 1, 20}; - int iRet; - int64_t dEnable; - struct ssp_data *data = dev_get_drvdata(dev); - - iRet = strict_strtoll(buf, 10, &dEnable); - if (iRet < 0) - return iRet; - - if (dEnable) { - send_instruction(data, ADD_SENSOR, PROXIMITY_RAW, chTempbuf, 2); - data->bProximityRawEnabled = true; - } else { - send_instruction(data, REMOVE_SENSOR, PROXIMITY_RAW, - chTempbuf, 2); - data->bProximityRawEnabled = false; - } - - return size; -} - -static unsigned char get_proximity_rawdata(struct ssp_data *data) -{ - unsigned char uRowdata = 0; - char chTempbuf[2] = { 1, 20}; - - if (data->bProximityRawEnabled == false) { - send_instruction(data, ADD_SENSOR, PROXIMITY_RAW, chTempbuf, 2); - msleep(200); - uRowdata = data->buf[PROXIMITY_RAW].prox[0]; - send_instruction(data, REMOVE_SENSOR, PROXIMITY_RAW, - chTempbuf, 2); - } else { - uRowdata = data->buf[PROXIMITY_RAW].prox[0]; - } - - return uRowdata; -} - -static ssize_t proximity_state_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%u\n", get_proximity_rawdata(data)); -} - -static void change_proximity_default_threshold(struct ssp_data *data) -{ - switch (data->chLcdLdi[1]) { - case LDI_GRAY: - data->uProxHiThresh = GRAY_OCTA_DEFAULT_THRESHOLD; - break; - case LDI_WHITE: - data->uProxHiThresh = WHITE_OCTA_DEFAULT_THRESHOLD; - break; - case LDI_OTHERS: - data->uProxHiThresh = OTHERS_OCTA_DEFAULT_THRESHOLD; - break; - default: - data->uProxHiThresh = DEFAULT_THRESHOLD; - break; - } -} - -int proximity_open_lcd_ldi(struct ssp_data *data) -{ - int iRet = 0; - mm_segment_t old_fs; - struct file *cancel_filp = NULL; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); - if (IS_ERR(cancel_filp)) { - iRet = PTR_ERR(cancel_filp); - if (iRet != -ENOENT) - pr_err("[SSP]: %s - Can't open lcd ldi file\n", - __func__); - set_fs(old_fs); - data->chLcdLdi[0] = 0; - data->chLcdLdi[1] = 0; - goto exit; - } - - iRet = cancel_filp->f_op->read(cancel_filp, - (u8 *)data->chLcdLdi, sizeof(u8) * 2, &cancel_filp->f_pos); - if (iRet != (sizeof(u8) * 2)) { - pr_err("[SSP]: %s - Can't read the lcd ldi data\n", __func__); - iRet = -EIO; - } - - ssp_dbg("[SSP]: %s - %c%c\n", __func__, - data->chLcdLdi[0], data->chLcdLdi[1]); - - filp_close(cancel_filp, current->files); - set_fs(old_fs); - -exit: - change_proximity_default_threshold(data); - return iRet; -} - -int proximity_open_calibration(struct ssp_data *data) -{ - int iRet = 0; - mm_segment_t old_fs; - struct file *cancel_filp = NULL; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); - if (IS_ERR(cancel_filp)) { - iRet = PTR_ERR(cancel_filp); - if (iRet != -ENOENT) - pr_err("[SSP]: %s - Can't open cancelation file\n", - __func__); - set_fs(old_fs); - goto exit; - } - - iRet = cancel_filp->f_op->read(cancel_filp, - (u8 *)&data->uProxCanc, sizeof(u8), &cancel_filp->f_pos); - if (iRet != sizeof(u8)) { - pr_err("[SSP]: %s - Can't read the cancel data\n", __func__); - iRet = -EIO; - } - - if (data->uProxCanc != 0) /* If there is an offset cal data. */ - data->uProxHiThresh = CANCELATION_THRESHOLD; - - pr_info("%s: proximity ps_canc = %d, ps_thresh = %d\n", - __func__, data->uProxCanc, data->uProxHiThresh); - - filp_close(cancel_filp, current->files); - set_fs(old_fs); - -exit: - set_proximity_threshold(data, data->uProxHiThresh, data->uProxCanc); - - return iRet; -} - -static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD) -{ - int iRet = 0; - mm_segment_t old_fs; - struct file *cancel_filp = NULL; - - if (iCalCMD) { - data->uProxHiThresh = CANCELATION_THRESHOLD; - data->uProxCanc = get_proximity_rawdata(data); - } else { - change_proximity_default_threshold(data); - data->uProxCanc = 0; - } - - set_proximity_threshold(data, data->uProxHiThresh, data->uProxCanc); - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cancel_filp = filp_open(CANCELATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); - if (IS_ERR(cancel_filp)) { - pr_err("%s: Can't open cancelation file\n", __func__); - set_fs(old_fs); - iRet = PTR_ERR(cancel_filp); - return iRet; - } - - iRet = cancel_filp->f_op->write(cancel_filp, (u8 *)&data->uProxCanc, - sizeof(u8), &cancel_filp->f_pos); - if (iRet != sizeof(u8)) { - pr_err("%s: Can't write the cancel data to file\n", __func__); - iRet = -EIO; - } - - filp_close(cancel_filp, current->files); - set_fs(old_fs); - - return iRet; -} - -static ssize_t proximity_cancel_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - ssp_dbg("[SSP]: uProxThresh = %u, uProxCanc = %u\n", - data->uProxHiThresh, data->uProxCanc); - - return sprintf(buf, "%u,%u\n", data->uProxCanc, data->uProxHiThresh); -} - -static ssize_t proximity_cancel_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int iCalCMD = 0, iRet = 0; - struct ssp_data *data = dev_get_drvdata(dev); - - if (sysfs_streq(buf, "1")) /* calibrate cancelation value */ - iCalCMD = 1; - else if (sysfs_streq(buf, "0")) /* reset cancelation value */ - iCalCMD = 0; - else { - pr_debug("%s: invalid value %d\n", __func__, *buf); - return -EINVAL; - } - - iRet = proximity_store_cancelation(data, iCalCMD); - if (iRet < 0) { - pr_err("[SSP]: - %s proximity_store_cancelation() failed\n", - __func__); - return iRet; - } - - ssp_dbg("[SSP]: %s - %u\n", __func__, iCalCMD); - return size; -} - -static ssize_t proximity_thresh_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - ssp_dbg("[SSP]: uProxThresh = %u\n", data->uProxHiThresh); - - return sprintf(buf, "%u\n", data->uProxHiThresh); -} - -static ssize_t proximity_thresh_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - u8 uNewThresh = 0x09; - int iRet = 0; - struct ssp_data *data = dev_get_drvdata(dev); - - iRet = kstrtou8(buf, 10, &uNewThresh); - if (iRet < 0) - pr_err("[SSP]: %s - kstrtoint failed.", __func__); - - data->uProxHiThresh = uNewThresh; - set_proximity_threshold(data, data->uProxHiThresh, data->uProxCanc); - - ssp_dbg("[SSP]: %s - new prox threshold = 0x%x\n", - __func__, data->uProxHiThresh); - - return size; -} - -static ssize_t barcode_emul_enable_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", data->bBarcodeEnabled); -} - -static ssize_t barcode_emul_enable_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int iRet; - int64_t dEnable; - struct ssp_data *data = dev_get_drvdata(dev); - - iRet = strict_strtoll(buf, 10, &dEnable); - if (iRet < 0) - return iRet; - - if (dEnable) - set_proximity_barcode_enable(data, true); - else - set_proximity_barcode_enable(data, false); - - return size; -} - -static DEVICE_ATTR(vendor, S_IRUGO, prox_vendor_show, NULL); -static DEVICE_ATTR(name, S_IRUGO, prox_name_show, NULL); -static DEVICE_ATTR(state, S_IRUGO, proximity_state_show, NULL); -static DEVICE_ATTR(barcode_emul_en, S_IRUGO | S_IWUSR | S_IWGRP, - barcode_emul_enable_show, barcode_emul_enable_store); -static DEVICE_ATTR(prox_avg, S_IRUGO | S_IWUSR | S_IWGRP, - proximity_avg_show, proximity_avg_store); -static DEVICE_ATTR(prox_cal, S_IRUGO | S_IWUSR | S_IWGRP, - proximity_cancel_show, proximity_cancel_store); -static DEVICE_ATTR(prox_thresh, S_IRUGO | S_IWUSR | S_IWGRP, - proximity_thresh_show, proximity_thresh_store); - -static struct device_attribute *prox_attrs[] = { - &dev_attr_vendor, - &dev_attr_name, - &dev_attr_state, - &dev_attr_prox_avg, - &dev_attr_prox_cal, - &dev_attr_prox_thresh, - &dev_attr_barcode_emul_en, - NULL, -}; - -void initialize_prox_factorytest(struct ssp_data *data) -{ - sensors_register(data->prox_device, data, - prox_attrs, "proximity_sensor"); -} - -void remove_prox_factorytest(struct ssp_data *data) -{ - sensors_unregister(data->prox_device, prox_attrs); -} diff --git a/drivers/sensorhub/sensors_core.c b/drivers/sensorhub/sensors_core.c deleted file mode 100644 index f968df82610..00000000000 --- a/drivers/sensorhub/sensors_core.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Universal sensors core class - * - * Author : Ryunkyun Park - */ - -#include -#include -#include -#include -#include -#include - -struct class *sensors_class; -static atomic_t sensor_count; - -/* - * Create sysfs interface - */ -static void set_sensor_attr(struct device *dev, - struct device_attribute *attributes[]) -{ - int i; - - for (i = 0; attributes[i] != NULL; i++) - if ((device_create_file(dev, attributes[i])) < 0) - printk(KERN_INFO "[SENSOR CORE] fail device_create_file" - "(dev, attributes[%d])\n", i); -} - -int sensors_register(struct device *dev, void * drvdata, - struct device_attribute *attributes[], char *name) -{ - int ret = 0; - - if (!sensors_class) { - sensors_class = class_create(THIS_MODULE, "sensors"); - if (IS_ERR(sensors_class)) - return PTR_ERR(sensors_class); - } - - dev = device_create(sensors_class, NULL, 0, drvdata, "%s", name); - - if (IS_ERR(dev)) { - ret = PTR_ERR(dev); - printk(KERN_ERR "[SENSORS CORE] device_create failed!" - "[%d]\n", ret); - return ret; - } - - set_sensor_attr(dev, attributes); - atomic_inc(&sensor_count); - - return 0; -} -EXPORT_SYMBOL_GPL(sensors_register); - -void sensors_unregister(struct device *dev, - struct device_attribute *attributes[]) -{ - int i; - - for (i = 0; attributes[i] != NULL; i++) - device_remove_file(dev, attributes[i]); -} -EXPORT_SYMBOL_GPL(sensors_unregister); - -void destroy_sensor_class(void) -{ - if (sensors_class) { - class_destroy(sensors_class); - sensors_class = NULL; - } -} -EXPORT_SYMBOL_GPL(destroy_sensor_class); - -static int __init sensors_class_init(void) -{ - printk(KERN_INFO "[SENSORS CORE] sensors_class_init\n"); - sensors_class = class_create(THIS_MODULE, "sensors"); - - if (IS_ERR(sensors_class)) - return PTR_ERR(sensors_class); - - atomic_set(&sensor_count, 0); - sensors_class->dev_uevent = NULL; - - return 0; -} - -static void __exit sensors_class_exit(void) -{ - if (sensors_class) { - class_destroy(sensors_class); - sensors_class = NULL; - } -} - -/* exported for the APM Power driver, APM emulation */ -EXPORT_SYMBOL_GPL(sensors_class); - -subsys_initcall(sensors_class_init); -module_exit(sensors_class_exit); - -MODULE_DESCRIPTION("Universal sensors core class"); -MODULE_AUTHOR("Ryunkyun Park "); -MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/ssp.h b/drivers/sensorhub/ssp.h deleted file mode 100644 index 33534f5300a..00000000000 --- a/drivers/sensorhub/ssp.h +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __SSP_PRJ_H__ -#define __SSP_PRJ_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SENSORS_SSP_SENSORHUB -#include "ssp_sensorhub.h" -#endif - -#define SUCCESS 1 -#define FAIL 0 -#define ERROR -1 - -#define FACTORY_DATA_MAX 39 - -#define SSP_DBG 1 - -#if SSP_DBG -#define SSP_FUNC_DBG 1 - -#define ssp_dbg(dev, format, ...) do { \ - printk(KERN_INFO dev, format, ##__VA_ARGS__); \ - } while (0) -#else -#define ssp_dbg(dev, format, ...) -#endif - -#if SSP_FUNC_DBG -#define func_dbg() do { \ - printk(KERN_INFO "[SSP]: %s\n", __func__); \ - } while (0) -#else -#define func_dbg() -#endif - -#define SSP_SW_RESET_TIME 3000 -#define DEFUALT_POLLING_DELAY (200 * NSEC_PER_MSEC) -#define PROX_AVG_READ_NUM 80 -#define DEFAULT_RETRIES 3 - -/* Sensor Sampling Time Define */ -enum { - SENSOR_NS_DELAY_FASTEST = 10000000, /* 10msec */ - SENSOR_NS_DELAY_GAME = 20000000, /* 20msec */ - SENSOR_NS_DELAY_UI = 66700000, /* 66.7msec */ - SENSOR_NS_DELAY_NORMAL = 200000000, /* 200msec */ -}; - -enum { - SENSOR_MS_DELAY_FASTEST = 10, /* 10msec */ - SENSOR_MS_DELAY_GAME = 20, /* 20msec */ - SENSOR_MS_DELAY_UI = 66, /* 66.7msec */ - SENSOR_MS_DELAY_NORMAL = 200, /* 200msec */ -}; - -enum { - SENSOR_CMD_DELAY_FASTEST = 0, /* 10msec */ - SENSOR_CMD_DELAY_GAME, /* 20msec */ - SENSOR_CMD_DELAY_UI, /* 66.7msec */ - SENSOR_CMD_DELAY_NORMAL, /* 200msec */ -}; - -/* - * SENSOR_DELAY_SET_STATE - * Check delay set to avoid sending ADD instruction twice - */ -enum { - INITIALIZATION_STATE = 0, - NO_SENSOR_STATE, - ADD_SENSOR_STATE, - RUNNING_SENSOR_STATE, -}; - -/* Gyroscope DPS */ -#define GYROSCOPE_DPS250 250 -#define GYROSCOPE_DPS500 500 -#define GYROSCOPE_DPS2000 2000 - -/* kernel -> ssp manager cmd*/ -#define SSP_LIBRARY_SLEEP_CMD (1 << 5) -#define SSP_LIBRARY_LARGE_DATA_CMD (1 << 6) -#define SSP_LIBRARY_WAKEUP_CMD (1 << 7) - -/* ioctl command */ -#define AKMIO 0xA1 -#define ECS_IOCTL_GET_FUSEROMDATA _IOR(AKMIO, 0x01, unsigned char[3]) -#define ECS_IOCTL_GET_MAGDATA _IOR(AKMIO, 0x02, unsigned char[8]) -#define ECS_IOCTL_GET_ACCDATA _IOR(AKMIO, 0x03, int[3]) - -/* AP -> SSP Instruction */ -#define MSG2SSP_INST_BYPASS_SENSOR_ADD 0xA1 -#define MSG2SSP_INST_BYPASS_SENSOR_REMOVE 0xA2 -#define MSG2SSP_INST_REMOVE_ALL 0xA3 -#define MSG2SSP_INST_CHANGE_DELAY 0xA4 -#define MSG2SSP_INST_SENSOR_SELFTEST 0xA8 -#define MSG2SSP_INST_LIBRARY_ADD 0xB1 -#define MSG2SSP_INST_LIBRARY_REMOVE 0xB2 - -#define MSG2SSP_AP_STT 0xC8 -#define MSG2SSP_AP_STATUS_WAKEUP 0xD1 -#define MSG2SSP_AP_STATUS_SLEEP 0xD2 -#define MSG2SSP_AP_STATUS_RESET 0xD3 -#define MSG2SSP_AP_WHOAMI 0x0F -#define MSG2SSP_AP_FIRMWARE_REV 0xF0 -#define MSG2SSP_AP_SENSOR_FORMATION 0xF1 -#define MSG2SSP_AP_SENSOR_PROXTHRESHOLD 0xF2 -#define MSG2SSP_AP_SENSOR_BARCODE_EMUL 0xF3 -#define MSG2SSP_AP_SENSOR_SCANNING 0xF4 - -#define MSG2SSP_AP_FUSEROM 0X01 - -/* AP -> SSP Data Protocol Frame Field */ -#define MSG2SSP_SSP_SLEEP 0xC1 -#define MSG2SSP_STS 0xC2 /* Start to Send */ -#define MSG2SSP_RTS 0xC4 /* Ready to Send */ -#define MSG2SSP_STT 0xC8 -#define MSG2SSP_SRM 0xCA /* Start to Read MSG */ -#define MSG2SSP_SSM 0xCB /* Start to Send MSG */ -#define MSG2SSP_SSD 0xCE /* Start to Send Data Type & Length */ - -/* SSP -> AP ACK about write CMD */ -#define MSG_ACK 0x80 /* ACK from SSP to AP */ -#define MSG_NAK 0x70 /* NAK from SSP to AP */ - - -/* SSP_INSTRUCTION_CMD */ -enum { - REMOVE_SENSOR = 0, - ADD_SENSOR, - CHANGE_DELAY, - GO_SLEEP, - FACTORY_MODE, - REMOVE_LIBRARY, - ADD_LIBRARY, -}; - -/* SENSOR_TYPE */ -enum { - ACCELEROMETER_SENSOR = 0, - GYROSCOPE_SENSOR, - GEOMAGNETIC_SENSOR, - PRESSURE_SENSOR, - GESTURE_SENSOR, - PROXIMITY_SENSOR, - LIGHT_SENSOR, - PROXIMITY_RAW, - ORIENTATION_SENSOR, - SENSOR_MAX, -}; - -/* SENSOR_FACTORY_MODE_TYPE */ -enum { - ACCELEROMETER_FACTORY = 0, - GYROSCOPE_FACTORY, - GEOMAGNETIC_FACTORY, - PRESSURE_FACTORY, - MCU_FACTORY, - GYROSCOPE_TEMP_FACTORY, - GYROSCOPE_DPS_FACTORY, - MCU_SLEEP_FACTORY, - SENSOR_FACTORY_MAX, -}; - -struct sensor_value { - union { - struct { - s16 x; - s16 y; - s16 z; - }; - struct { - u16 r; - u16 g; - u16 b; - u16 w; - }; - u8 prox[4]; - s16 data[4]; - s32 pressure[3]; - }; -}; - -struct calibraion_data { - int x; - int y; - int z; -}; - -struct ssp_data { - struct input_dev *acc_input_dev; - struct input_dev *gyro_input_dev; - struct input_dev *pressure_input_dev; - struct input_dev *light_input_dev; - struct input_dev *prox_input_dev; - - struct device *sen_dev; - struct device *mcu_device; - struct device *acc_device; - struct device *gyro_device; - struct device *mag_device; - struct device *prs_device; - struct device *prox_device; - struct device *light_device; - - struct i2c_client *client; - struct wake_lock ssp_wake_lock; - struct miscdevice akmd_device; - struct timer_list debug_timer; - struct workqueue_struct *debug_wq; - struct work_struct work_debug; - struct calibraion_data accelcal; - struct calibraion_data gyrocal; - struct sensor_value buf[SENSOR_MAX]; - - bool bSspShutdown; - bool bCheckSuspend; - bool bDebugEnabled; - bool bMcuIRQTestSuccessed; - bool bAccelAlert; - bool bProximityRawEnabled; - bool bBarcodeEnabled; - - unsigned char uProxCanc; - unsigned char uProxHiThresh; - unsigned char uProxLoThresh; - unsigned char uFuseRomData[3]; - unsigned char uFactorydata[FACTORY_DATA_MAX]; - char *pchLibraryBuf; - char chLcdLdi[2]; - int iIrq; - int iLibraryLength; - int aiCheckStatus[SENSOR_MAX]; - - unsigned int uIrqFailCnt; - unsigned int uSsdFailCnt; - unsigned int uResetCnt; - unsigned int uInstFailCnt; - unsigned int uTimeOutCnt; - unsigned int uIrqCnt; - unsigned int uBusyCnt; - unsigned int uMissSensorCnt; - - unsigned int uGyroDps; - unsigned int uSensorState; - unsigned int uCurFirmRev; - unsigned int uFactoryProxAvg[4]; - unsigned int uFactorydataReady; - s32 iPressureCal; - - atomic_t aSensorEnable; - int64_t adDelayBuf[SENSOR_MAX]; - - int (*wakeup_mcu)(void); - int (*check_mcu_ready)(void); - int (*check_mcu_busy)(void); - int (*set_mcu_reset)(int); - int (*check_ap_rev)(void); - void (*get_sensor_data[SENSOR_MAX])(char *, int *, - struct sensor_value *); - void (*report_sensor_data[SENSOR_MAX])(struct ssp_data *, - struct sensor_value *); - -#ifdef CONFIG_HAS_EARLYSUSPEND - struct early_suspend early_suspend; -#endif - -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - struct ssp_sensorhub_data *hub_data; -#endif -}; - -int waiting_wakeup_mcu(struct ssp_data *); -int ssp_i2c_read(struct ssp_data *, char *, u16, char *, u16, int); -void toggle_mcu_reset(struct ssp_data *); -int initialize_mcu(struct ssp_data *); -int initialize_input_dev(struct ssp_data *); -int initialize_sysfs(struct ssp_data *); -void initialize_accel_factorytest(struct ssp_data *); -void initialize_prox_factorytest(struct ssp_data *); -void initialize_light_factorytest(struct ssp_data *); -void initialize_gyro_factorytest(struct ssp_data *); -void initialize_pressure_factorytest(struct ssp_data *); -void initialize_magnetic_factorytest(struct ssp_data *); -void initialize_function_pointer(struct ssp_data *); -void initialize_magnetic(struct ssp_data *); -void remove_accel_factorytest(struct ssp_data *); -void remove_gyro_factorytest(struct ssp_data *); -void remove_prox_factorytest(struct ssp_data *); -void remove_light_factorytest(struct ssp_data *); -void remove_pressure_factorytest(struct ssp_data *); -void remove_magnetic_factorytest(struct ssp_data *); -void destroy_sensor_class(void); -int initialize_event_symlink(struct ssp_data *); -int accel_open_calibration(struct ssp_data *); -int gyro_open_calibration(struct ssp_data *); -int pressure_open_calibration(struct ssp_data *); -int proximity_open_calibration(struct ssp_data *); -void check_fwbl(struct ssp_data *); -int update_mcu_bin(struct ssp_data *); -int update_crashed_mcu_bin(struct ssp_data *); -void remove_input_dev(struct ssp_data *); -void remove_sysfs(struct ssp_data *); -void remove_event_symlink(struct ssp_data *); -int ssp_sleep_mode(struct ssp_data *); -int ssp_resume_mode(struct ssp_data *); -int send_instruction(struct ssp_data *, u8, u8, u8 *, u8); -int select_irq_msg(struct ssp_data *); -int get_chipid(struct ssp_data *); -int get_fuserom_data(struct ssp_data *); -int set_sensor_position(struct ssp_data *); -void sync_sensor_state(struct ssp_data *); -void set_proximity_threshold(struct ssp_data *, unsigned char, unsigned char); -void set_proximity_barcode_enable(struct ssp_data *, bool); -unsigned int get_delay_cmd(u8); -unsigned int get_msdelay(int64_t); -unsigned int get_sensor_scanning_info(struct ssp_data *); -unsigned int get_firmware_rev(struct ssp_data *); -int parse_dataframe(struct ssp_data *, char *, int); -void enable_debug_timer(struct ssp_data *); -void disable_debug_timer(struct ssp_data *); -int initialize_debug_timer(struct ssp_data *); -int proximity_open_lcd_ldi(struct ssp_data *); -void report_acc_data(struct ssp_data *, struct sensor_value *); -void report_gyro_data(struct ssp_data *, struct sensor_value *); -void report_mag_data(struct ssp_data *, struct sensor_value *); -void report_gesture_data(struct ssp_data *, struct sensor_value *); -void report_pressure_data(struct ssp_data *, struct sensor_value *); -void report_light_data(struct ssp_data *, struct sensor_value *); -void report_prox_data(struct ssp_data *, struct sensor_value *); -void report_prox_raw_data(struct ssp_data *, struct sensor_value *); -void print_mcu_debug(char *, int *); -unsigned int get_module_rev(void); -void reset_mcu(struct ssp_data *); -void convert_acc_data(s16 *); -int sensors_register(struct device *, void *, - struct device_attribute*[], char *); -void sensors_unregister(struct device *, struct device_attribute*[]); -ssize_t mcu_reset_show(struct device *, struct device_attribute *, char *); -ssize_t mcu_revision_show(struct device *, struct device_attribute *, char *); -ssize_t mcu_update_show(struct device *, struct device_attribute *, char *); -ssize_t mcu_update2_show(struct device *, struct device_attribute *, char *); -ssize_t mcu_factorytest_store(struct device *, struct device_attribute *, - const char *, size_t); -ssize_t mcu_factorytest_show(struct device *, - struct device_attribute *, char *); -ssize_t mcu_model_name_show(struct device *, - struct device_attribute *, char *); -ssize_t mcu_sleep_factorytest_show(struct device *, - struct device_attribute *, char *); -ssize_t mcu_sleep_factorytest_store(struct device *, - struct device_attribute *, const char *, size_t); - -#endif diff --git a/drivers/sensorhub/ssp_ak8963c.c b/drivers/sensorhub/ssp_ak8963c.c deleted file mode 100644 index 00a4f7dffca..00000000000 --- a/drivers/sensorhub/ssp_ak8963c.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -/*************************************************************************/ -/* AKM Daemon Library ioctl */ -/*************************************************************************/ - -static int akmd_copy_in(unsigned int cmd, void __user *argp, - void *buf, size_t buf_size) -{ - if (!(cmd & IOC_IN)) - return 0; - if (_IOC_SIZE(cmd) > buf_size) - return -EINVAL; - if (copy_from_user(buf, argp, _IOC_SIZE(cmd))) - return -EFAULT; - return 0; -} - -static int akmd_copy_out(unsigned int cmd, void __user *argp, - void *buf, size_t buf_size) -{ - if (!(cmd & IOC_OUT)) - return 0; - if (_IOC_SIZE(cmd) > buf_size) - return -EINVAL; - if (copy_to_user(argp, buf, _IOC_SIZE(cmd))) - return -EFAULT; - return 0; -} - -static long akmd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int iRet; - void __user *argp = (void __user *)arg; - struct ssp_data *data = container_of(file->private_data, - struct ssp_data, akmd_device); - - union { - u8 uData[8]; - u8 uMagData[8]; - u8 uFuseData[3]; - int iAccData[3]; - } akmdbuf; - - iRet = akmd_copy_in(cmd, argp, akmdbuf.uData, sizeof(akmdbuf)); - if (iRet) - return iRet; - - switch (cmd) { - case ECS_IOCTL_GET_MAGDATA: - if ((data->buf[GEOMAGNETIC_SENSOR].x == 0) - && (data->buf[GEOMAGNETIC_SENSOR].y == 0) - && (data->buf[GEOMAGNETIC_SENSOR].z == 0)) - akmdbuf.uMagData[0] = 0; - else - akmdbuf.uMagData[0] = 1; - - akmdbuf.uMagData[1] = data->buf[GEOMAGNETIC_SENSOR].x & 0xff; - akmdbuf.uMagData[2] = data->buf[GEOMAGNETIC_SENSOR].x >> 8; - akmdbuf.uMagData[3] = data->buf[GEOMAGNETIC_SENSOR].y & 0xff; - akmdbuf.uMagData[4] = data->buf[GEOMAGNETIC_SENSOR].y >> 8; - akmdbuf.uMagData[5] = data->buf[GEOMAGNETIC_SENSOR].z & 0xff; - akmdbuf.uMagData[6] = data->buf[GEOMAGNETIC_SENSOR].z >> 8; - akmdbuf.uMagData[7] = 0x10; - break; - case ECS_IOCTL_GET_ACCDATA: - akmdbuf.iAccData[0] = data->buf[ACCELEROMETER_SENSOR].x; - akmdbuf.iAccData[1] = data->buf[ACCELEROMETER_SENSOR].y; - akmdbuf.iAccData[2] = data->buf[ACCELEROMETER_SENSOR].z; - break; - case ECS_IOCTL_GET_FUSEROMDATA: - akmdbuf.uFuseData[0] = data->uFuseRomData[0]; - akmdbuf.uFuseData[1] = data->uFuseRomData[1]; - akmdbuf.uFuseData[2] = data->uFuseRomData[2]; - break; - default: - return -ENOTTY; - } - - if (iRet < 0) - return iRet; - - return akmd_copy_out(cmd, argp, akmdbuf.uData, sizeof(akmdbuf)); -} - -static const struct file_operations akmd_fops = { - .owner = THIS_MODULE, - .open = nonseekable_open, - .unlocked_ioctl = akmd_ioctl, -}; - -void initialize_magnetic(struct ssp_data *data) -{ - data->akmd_device.minor = MISC_DYNAMIC_MINOR; - data->akmd_device.name = "akm8963"; - data->akmd_device.fops = &akmd_fops; -} diff --git a/drivers/sensorhub/ssp_data.c b/drivers/sensorhub/ssp_data.c deleted file mode 100644 index 1be865c7d17..00000000000 --- a/drivers/sensorhub/ssp_data.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -/* SSP -> AP Instruction */ -#define MSG2AP_INST_BYPASS_DATA 0x00 -#define MSG2AP_INST_LIBRARY_DATA 0x01 -#define MSG2AP_INST_SELFTEST_DATA 0x02 -#define MSG2AP_INST_DEBUG_DATA 0x03 - -/* Factory data length */ -#define ACCEL_FACTORY_DATA_LENGTH 1 -#define GYRO_FACTORY_DATA_LENGTH 27 -#define MAGNETIC_FACTORY_DATA_LENGTH 6 -#define PRESSURE_FACTORY_DATA_LENGTH 1 -#define MCU_FACTORY_DATA_LENGTH 5 -#define GYRO_TEMP_FACTORY_DATA_LENGTH 1 -#define GYRO_DPS_FACTORY_DATA_LENGTH 1 -#define MCU_SLEEP_FACTORY_DATA_LENGTH 39 - -/*************************************************************************/ -/* SSP parsing the dataframe */ -/*************************************************************************/ - -static void get_3axis_sensordata(char *pchRcvDataFrame, int *iDataIdx, - struct sensor_value *sensorsdata) -{ - int iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->x = iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->y = iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->z = iTemp; -} - -static void get_light_sensordata(char *pchRcvDataFrame, int *iDataIdx, - struct sensor_value *sensorsdata) -{ - int iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->r = iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->g = iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->b = iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->w = iTemp; -} - -static void get_pressure_sensordata(char *pchRcvDataFrame, int *iDataIdx, - struct sensor_value *sensorsdata) -{ - int iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 16; - sensorsdata->pressure[0] = iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - sensorsdata->pressure[0] += iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->pressure[0] += iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += (int)pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->pressure[1] = (s16)iTemp; -} - -static void get_gesture_sensordata(char *pchRcvDataFrame, int *iDataIdx, - struct sensor_value *sensorsdata) -{ - int iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->data[0] = iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->data[1] = iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->data[2] = iTemp; - - iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; - iTemp <<= 8; - iTemp += pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->data[3] = iTemp; -} - -static void get_proximity_sensordata(char *pchRcvDataFrame, int *iDataIdx, - struct sensor_value *sensorsdata) -{ - sensorsdata->prox[0] = (u8)pchRcvDataFrame[(*iDataIdx)++]; - sensorsdata->prox[1] = (u8)pchRcvDataFrame[(*iDataIdx)++]; -} - -static void get_proximity_rawdata(char *pchRcvDataFrame, int *iDataIdx, - struct sensor_value *sensorsdata) -{ - sensorsdata->prox[0] = (u8)pchRcvDataFrame[(*iDataIdx)++]; -} - -static void get_factoty_data(struct ssp_data *data, int iSensorData, - char *pchRcvDataFrame, int *iDataIdx) -{ - int iIdx, iTotalLenth = 0; - unsigned int uTemp = 0; - - switch (iSensorData) { - case ACCELEROMETER_FACTORY: - uTemp = (1 << ACCELEROMETER_FACTORY); - iTotalLenth = ACCEL_FACTORY_DATA_LENGTH; - break; - case GYROSCOPE_FACTORY: - uTemp = (1 << GYROSCOPE_FACTORY); - iTotalLenth = GYRO_FACTORY_DATA_LENGTH; - break; - case GEOMAGNETIC_FACTORY: - uTemp = (1 << GEOMAGNETIC_FACTORY); - iTotalLenth = MAGNETIC_FACTORY_DATA_LENGTH; - break; - case PRESSURE_FACTORY: - uTemp = (1 << PRESSURE_FACTORY); - iTotalLenth = PRESSURE_FACTORY_DATA_LENGTH; - break; - case MCU_FACTORY: - uTemp = (1 << MCU_FACTORY); - iTotalLenth = MCU_FACTORY_DATA_LENGTH; - break; - case GYROSCOPE_TEMP_FACTORY: - uTemp = (1 << GYROSCOPE_TEMP_FACTORY); - iTotalLenth = GYRO_TEMP_FACTORY_DATA_LENGTH; - break; - case GYROSCOPE_DPS_FACTORY: - uTemp = (1 << GYROSCOPE_DPS_FACTORY); - iTotalLenth = GYRO_DPS_FACTORY_DATA_LENGTH; - break; - case MCU_SLEEP_FACTORY: - uTemp = (1 << MCU_SLEEP_FACTORY); - iTotalLenth = MCU_SLEEP_FACTORY_DATA_LENGTH; - break; - } - - ssp_dbg("[SSP]: %s - Factory test data %d\n", __func__, iSensorData); - for (iIdx = 0; iIdx < iTotalLenth; iIdx++) - data->uFactorydata[iIdx] = (u8)pchRcvDataFrame[(*iDataIdx)++]; - - data->uFactorydataReady = uTemp; -} - -int parse_dataframe(struct ssp_data *data, char *pchRcvDataFrame, int iLength) -{ - int iDataIdx, iSensorData; - struct sensor_value *sensorsdata; - - sensorsdata = kzalloc(sizeof(*sensorsdata), GFP_KERNEL); - if (sensorsdata == NULL) - return ERROR; - - for (iDataIdx = 0; iDataIdx < iLength;) { - if (pchRcvDataFrame[iDataIdx] == MSG2AP_INST_BYPASS_DATA) { - iDataIdx++; - iSensorData = pchRcvDataFrame[iDataIdx++]; - if ((iSensorData < 0) || - (iSensorData >= (SENSOR_MAX - 1))) { - pr_err("[SSP]: %s - Mcu data frame1 error %d\n", - __func__, iSensorData); - kfree(sensorsdata); - return ERROR; - } - - data->get_sensor_data[iSensorData](pchRcvDataFrame, - &iDataIdx, sensorsdata); - data->report_sensor_data[iSensorData](data, - sensorsdata); - } else if (pchRcvDataFrame[iDataIdx] == - MSG2AP_INST_SELFTEST_DATA) { - iDataIdx++; - iSensorData = pchRcvDataFrame[iDataIdx++]; - if ((iSensorData < 0) || - (iSensorData >= SENSOR_FACTORY_MAX)) { - pr_err("[SSP]: %s - Mcu data frame2 error %d\n", - __func__, iSensorData); - kfree(sensorsdata); - return ERROR; - } - get_factoty_data(data, iSensorData, pchRcvDataFrame, - &iDataIdx); - } else if (pchRcvDataFrame[iDataIdx] == - MSG2AP_INST_DEBUG_DATA) { - print_mcu_debug(pchRcvDataFrame + iDataIdx + 1, - &iDataIdx); -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - } else if (pchRcvDataFrame[iDataIdx] == - MSG2AP_INST_LIBRARY_DATA) { - ssp_handle_sensorhub_data(data, - pchRcvDataFrame, iDataIdx, iLength); - break; -#endif - } else - iDataIdx++; - } - kfree(sensorsdata); - return SUCCESS; -} - -void initialize_function_pointer(struct ssp_data *data) -{ - data->get_sensor_data[ACCELEROMETER_SENSOR] = get_3axis_sensordata; - data->get_sensor_data[GYROSCOPE_SENSOR] = get_3axis_sensordata; - data->get_sensor_data[GEOMAGNETIC_SENSOR] = get_3axis_sensordata; - data->get_sensor_data[PRESSURE_SENSOR] = get_pressure_sensordata; - data->get_sensor_data[GESTURE_SENSOR] = get_gesture_sensordata; - data->get_sensor_data[PROXIMITY_SENSOR] = get_proximity_sensordata; - data->get_sensor_data[PROXIMITY_RAW] = get_proximity_rawdata; - data->get_sensor_data[LIGHT_SENSOR] = get_light_sensordata; - - data->report_sensor_data[ACCELEROMETER_SENSOR] = report_acc_data; - data->report_sensor_data[GYROSCOPE_SENSOR] = report_gyro_data; - data->report_sensor_data[GEOMAGNETIC_SENSOR] = report_mag_data; - data->report_sensor_data[PRESSURE_SENSOR] = report_pressure_data; - data->report_sensor_data[GESTURE_SENSOR] = report_gesture_data; - data->report_sensor_data[PROXIMITY_SENSOR] = report_prox_data; - data->report_sensor_data[PROXIMITY_RAW] = report_prox_raw_data; - data->report_sensor_data[LIGHT_SENSOR] = report_light_data; -} diff --git a/drivers/sensorhub/ssp_debug.c b/drivers/sensorhub/ssp_debug.c deleted file mode 100644 index 6c9460634d7..00000000000 --- a/drivers/sensorhub/ssp_debug.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -#define SSP_DEBUG_TIMER_SEC (10 * HZ) - -#define LIMIT_RESET_CNT 20 -#define LIMIT_SSD_FAIL_CNT 3 -#define LIMIT_INSTRUCTION_FAIL_CNT 1 -#define LIMIT_IRQ_FAIL_CNT 2 -#define LIMIT_TIMEOUT_CNT 5 - -/*************************************************************************/ -/* SSP Debug timer function */ -/*************************************************************************/ - -void print_mcu_debug(char *pchRcvDataFrame, int *pDataIdx) -{ - int iLength; - - iLength = pchRcvDataFrame[0]; - pchRcvDataFrame[iLength] = 0; - *pDataIdx = *pDataIdx + iLength + 2; - - ssp_dbg("[SSP]: MSG From MCU - %s\n", pchRcvDataFrame + 1); -} - -void reset_mcu(struct ssp_data *data) -{ - data->bSspShutdown = true; - disable_irq(data->iIrq); - disable_irq_wake(data->iIrq); - - toggle_mcu_reset(data); - msleep(SSP_SW_RESET_TIME); - data->bSspShutdown = false; - - if (initialize_mcu(data) < 0) - data->bSspShutdown = true; - - sync_sensor_state(data); - - enable_irq(data->iIrq); - enable_irq_wake(data->iIrq); - -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - ssp_report_sensorhub_notice(data, MSG2SSP_AP_STATUS_RESET); -#endif -} - -void sync_sensor_state(struct ssp_data *data) -{ - unsigned char uBuf[2] = {0,}; - unsigned int uSensorCnt; - - proximity_open_calibration(data); - - udelay(10); - - for (uSensorCnt = 0; uSensorCnt < (SENSOR_MAX - 1); uSensorCnt++) { - if (atomic_read(&data->aSensorEnable) & (1 << uSensorCnt)) { - uBuf[1] = (u8)get_msdelay(data->adDelayBuf[uSensorCnt]); - uBuf[0] = (u8)get_delay_cmd(uBuf[1]); - send_instruction(data, ADD_SENSOR, uSensorCnt, uBuf, 2); - udelay(10); - } - } - - if (data->bProximityRawEnabled == true) { - uBuf[0] = 1; - uBuf[1] = 20; - send_instruction(data, ADD_SENSOR, PROXIMITY_RAW, uBuf, 2); - } -} - -static void print_sensordata(struct ssp_data *data, unsigned int uSensor) -{ - switch (uSensor) { - case ACCELEROMETER_SENSOR: - case GYROSCOPE_SENSOR: - case GEOMAGNETIC_SENSOR: - ssp_dbg(" %u : %d, %d, %d (%ums)\n", uSensor, - data->buf[uSensor].x, data->buf[uSensor].y, - data->buf[uSensor].z, - get_msdelay(data->adDelayBuf[uSensor])); - break; - case LIGHT_SENSOR: - ssp_dbg(" %u : %u, %u, %u, %u (%ums)\n", uSensor, - data->buf[uSensor].r, data->buf[uSensor].g, - data->buf[uSensor].b, data->buf[uSensor].w, - get_msdelay(data->adDelayBuf[uSensor])); - break; - case PRESSURE_SENSOR: - ssp_dbg(" %u : %d, %d (%ums)\n", uSensor, - data->buf[uSensor].pressure[0], - data->buf[uSensor].pressure[1], - get_msdelay(data->adDelayBuf[uSensor])); - break; - case GESTURE_SENSOR: - ssp_dbg(" %u : %d %d %d %d (%ums)\n", uSensor, - data->buf[uSensor].data[0], data->buf[uSensor].data[1], - data->buf[uSensor].data[2], data->buf[uSensor].data[3], - get_msdelay(data->adDelayBuf[uSensor])); - break; - case PROXIMITY_SENSOR: - ssp_dbg(" %u : %d %d(%ums)\n", uSensor, - data->buf[uSensor].prox[0], data->buf[uSensor].prox[1], - get_msdelay(data->adDelayBuf[uSensor])); - } -} - -static void debug_work_func(struct work_struct *work) -{ - unsigned int uSensorCnt; - struct ssp_data *data = container_of(work, struct ssp_data, work_debug); - - ssp_dbg("[SSP]: %s(%u) - Sensor state: 0x%x, RC: %u, MS: %u\n", - __func__, data->uIrqCnt, data->uSensorState, data->uResetCnt, - data->uMissSensorCnt); - - for (uSensorCnt = 0; uSensorCnt < (SENSOR_MAX - 1); uSensorCnt++) - if (atomic_read(&data->aSensorEnable) & (1 << uSensorCnt)) - print_sensordata(data, uSensorCnt); - - if ((atomic_read(&data->aSensorEnable) & 0x4f) && (data->uIrqCnt == 0)) - data->uIrqFailCnt++; - else - data->uIrqFailCnt = 0; - - if ((data->uSsdFailCnt >= LIMIT_SSD_FAIL_CNT) - || (data->uInstFailCnt >= LIMIT_INSTRUCTION_FAIL_CNT) - || (data->uIrqFailCnt >= LIMIT_IRQ_FAIL_CNT) - || ((data->uTimeOutCnt + data->uBusyCnt) > LIMIT_TIMEOUT_CNT)) { - - if (data->uResetCnt < LIMIT_RESET_CNT) { - reset_mcu(data); - data->uResetCnt++; - } else { - data->bSspShutdown = true; - } - - data->uSsdFailCnt = 0; - data->uInstFailCnt = 0; - data->uTimeOutCnt = 0; - data->uBusyCnt = 0; - data->uIrqFailCnt = 0; - } - - data->uIrqCnt = 0; -} - -static void debug_timer_func(unsigned long ptr) -{ - struct ssp_data *data = (struct ssp_data *)ptr; - - queue_work(data->debug_wq, &data->work_debug); - mod_timer(&data->debug_timer, - round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC)); -} - -void enable_debug_timer(struct ssp_data *data) -{ - mod_timer(&data->debug_timer, - round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC)); -} - -void disable_debug_timer(struct ssp_data *data) -{ - del_timer_sync(&data->debug_timer); - cancel_work_sync(&data->work_debug); -} - -int initialize_debug_timer(struct ssp_data *data) -{ - setup_timer(&data->debug_timer, debug_timer_func, (unsigned long)data); - - data->debug_wq = create_singlethread_workqueue("ssp_debug_wq"); - if (!data->debug_wq) - return ERROR; - - INIT_WORK(&data->work_debug, debug_work_func); - return SUCCESS; -} diff --git a/drivers/sensorhub/ssp_dev.c b/drivers/sensorhub/ssp_dev.c deleted file mode 100644 index 64932f13d5b..00000000000 --- a/drivers/sensorhub/ssp_dev.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -/* ssp mcu device ID */ -#define DEVICE_ID 0x55 - -static void ssp_early_suspend(struct early_suspend *handler); -static void ssp_late_resume(struct early_suspend *handler); - -/************************************************************************/ -/* interrupt happened due to transition/change of SSP MCU */ -/************************************************************************/ - -static irqreturn_t sensordata_irq_thread_fn(int iIrq, void *dev_id) -{ - struct ssp_data *data = dev_id; - - select_irq_msg(data); - data->uIrqCnt++; - - return IRQ_HANDLED; -} - -/*************************************************************************/ -/* initialize sensor hub */ -/*************************************************************************/ - -static void initialize_variable(struct ssp_data *data) -{ - int iSensorIndex; - - for (iSensorIndex = 0; iSensorIndex < SENSOR_MAX; iSensorIndex++) { - data->adDelayBuf[iSensorIndex] = DEFUALT_POLLING_DELAY; - data->aiCheckStatus[iSensorIndex] = INITIALIZATION_STATE; - } - - /* AKM Daemon Library */ - data->aiCheckStatus[GEOMAGNETIC_SENSOR] = NO_SENSOR_STATE; - data->aiCheckStatus[ORIENTATION_SENSOR] = NO_SENSOR_STATE; - memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); - - atomic_set(&data->aSensorEnable, 0); - data->iLibraryLength = 0; - data->uSensorState = 0; - data->uFactorydataReady = 0; - data->uFactoryProxAvg[0] = 0; - - data->uResetCnt = 0; - data->uInstFailCnt = 0; - data->uTimeOutCnt = 0; - data->uSsdFailCnt = 0; - data->uBusyCnt = 0; - data->uIrqCnt = 0; - data->uIrqFailCnt = 0; - data->uMissSensorCnt = 0; - - data->bCheckSuspend = false; - data->bSspShutdown = false; - data->bDebugEnabled = false; - data->bProximityRawEnabled = false; - data->bMcuIRQTestSuccessed = false; - data->bBarcodeEnabled = false; - data->bAccelAlert = false; - - data->accelcal.x = 0; - data->accelcal.y = 0; - data->accelcal.z = 0; - - data->gyrocal.x = 0; - data->gyrocal.y = 0; - data->gyrocal.z = 0; - - data->iPressureCal = 0; - data->uProxCanc = 0; - data->uProxHiThresh = 0; - data->uProxLoThresh = 0; - data->uGyroDps = GYROSCOPE_DPS500; - - data->mcu_device = NULL; - data->acc_device = NULL; - data->gyro_device = NULL; - data->mag_device = NULL; - data->prs_device = NULL; - data->prox_device = NULL; - data->light_device = NULL; - - initialize_function_pointer(data); -} - -int initialize_mcu(struct ssp_data *data) -{ - int iRet = 0; - - iRet = get_chipid(data); - pr_info("[SSP] MCU device ID = %d, reading ID = %d\n", DEVICE_ID, iRet); - if (iRet != DEVICE_ID) { - if (iRet < 0) { - pr_err("[SSP]: %s - MCU is not working : 0x%x\n", - __func__, iRet); - } else { - pr_err("[SSP]: %s - MCU identification failed\n", - __func__); - iRet = -ENODEV; - } - return iRet; - } - - iRet = set_sensor_position(data); - if (iRet < 0) { - pr_err("[SSP]: %s - set_sensor_position failed\n", __func__); - return iRet; - } - - iRet = get_fuserom_data(data); - if (iRet < 0) { - pr_err("[SSP]: %s - get_fuserom_data failed\n", __func__); - return FAIL; - } - - data->uSensorState = get_sensor_scanning_info(data); - if (data->uSensorState == 0) { - pr_err("[SSP]: %s - get_sensor_scanning_info failed\n", - __func__); - return FAIL; - } - - return SUCCESS; -} - -static int initialize_irq(struct ssp_data *data) -{ - int iRet, iIrq; - - iRet = gpio_request(data->client->irq, "mpu_ap_int1"); - if (iRet < 0) { - pr_err("[SSP]: %s - gpio %d request failed (%d)\n", - __func__, data->client->irq, iRet); - return iRet; - } - - iRet = gpio_direction_input(data->client->irq); - if (iRet < 0) { - pr_err("[SSP]: %s - failed to set gpio %d as input (%d)\n", - __func__, data->client->irq, iRet); - goto err_irq_direction_input; - } - - iIrq = gpio_to_irq(data->client->irq); - - pr_info("[SSP]: requesting IRQ %d\n", iIrq); - iRet = request_threaded_irq(iIrq, NULL, sensordata_irq_thread_fn, - IRQF_TRIGGER_FALLING, "SSP_Int", data); - if (iRet < 0) { - pr_err("[SSP]: %s - request_irq(%d) failed for gpio %d (%d)\n", - __func__, iIrq, iIrq, iRet); - goto err_request_irq; - } - - /* start with interrupts disabled */ - data->iIrq = iIrq; - disable_irq(data->iIrq); - return 0; - -err_request_irq: -err_irq_direction_input: - gpio_free(data->client->irq); - return iRet; -} - -static int ssp_probe(struct i2c_client *client, - const struct i2c_device_id *devid) -{ - int iRet = 0; - struct ssp_data *data; - struct ssp_platform_data *pdata = client->dev.platform_data; - - if (pdata == NULL) { - pr_err("[SSP]: %s - platform_data is null..\n", __func__); - iRet = -ENOMEM; - goto exit; - } - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) { - pr_err("[SSP]: %s - failed to allocate memory for data\n", - __func__); - iRet = -ENOMEM; - goto exit; - } - - data->client = client; - i2c_set_clientdata(client, data); - - data->wakeup_mcu = pdata->wakeup_mcu; - data->check_mcu_ready = pdata->check_mcu_ready; - data->check_mcu_busy = pdata->check_mcu_busy; - data->set_mcu_reset = pdata->set_mcu_reset; - data->check_ap_rev = pdata->check_ap_rev; - - if ((data->wakeup_mcu == NULL) - || (data->check_mcu_ready == NULL) - || (data->check_mcu_busy == NULL) - || (data->set_mcu_reset == NULL) - || (data->check_ap_rev == NULL)) { - pr_err("[SSP]: %s - function callback is null\n", __func__); - iRet = -EIO; - goto err_reset_null; - } - - pr_info("\n#####################################################\n"); - - /* check boot loader binary */ - check_fwbl(data); - - initialize_variable(data); - - iRet = initialize_mcu(data); - if (iRet < 0) { - pr_err("[SSP]: %s - initialize_mcu failed\n", __func__); - goto err_read_reg; - } - - wake_lock_init(&data->ssp_wake_lock, - WAKE_LOCK_SUSPEND, "ssp_wake_lock"); - - iRet = initialize_input_dev(data); - if (iRet < 0) { - pr_err("[SSP]: %s - could not create input device\n", __func__); - goto err_input_register_device; - } - - initialize_magnetic(data); - - iRet = misc_register(&data->akmd_device); - if (iRet) - goto err_akmd_device_register; - - iRet = initialize_debug_timer(data); - if (iRet < 0) { - pr_err("[SSP]: %s - could not create workqueue\n", __func__); - goto err_create_workqueue; - } - - iRet = initialize_irq(data); - if (iRet < 0) { - pr_err("[SSP]: %s - could not create irq\n", __func__); - goto err_setup_irq; - } - - iRet = initialize_sysfs(data); - if (iRet < 0) { - pr_err("[SSP]: %s - could not create sysfs\n", __func__); - goto err_sysfs_create; - } - - iRet = initialize_event_symlink(data); - if (iRet < 0) { - pr_err("[SSP]: %s - could not create symlink\n", __func__); - goto err_symlink_create; - } - -#ifdef CONFIG_HAS_EARLYSUSPEND - data->early_suspend.suspend = ssp_early_suspend; - data->early_suspend.resume = ssp_late_resume; - register_early_suspend(&data->early_suspend); -#endif - -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - /* init sensorhub device */ - iRet = ssp_initialize_sensorhub(data); - if (iRet < 0) { - pr_err("%s: ssp_initialize_sensorhub err(%d)", __func__, iRet); - ssp_remove_sensorhub(data); - } -#endif - - enable_irq(data->iIrq); - enable_irq_wake(data->iIrq); - pr_info("[SSP]: %s - probe success!\n", __func__); - - enable_debug_timer(data); - - iRet = 0; - goto exit; - -err_symlink_create: - remove_sysfs(data); -err_sysfs_create: - free_irq(data->iIrq, data); - gpio_free(data->client->irq); -err_setup_irq: - destroy_workqueue(data->debug_wq); -err_create_workqueue: - misc_deregister(&data->akmd_device); -err_akmd_device_register: - remove_input_dev(data); -err_input_register_device: - wake_lock_destroy(&data->ssp_wake_lock); -err_read_reg: -err_reset_null: - kfree(data); - pr_err("[SSP]: %s - probe failed!\n", __func__); -exit: - pr_info("#####################################################\n\n"); - return iRet; -} - -static void ssp_shutdown(struct i2c_client *client) -{ - struct ssp_data *data = i2c_get_clientdata(client); - - func_dbg(); - data->bSspShutdown = true; - -#ifdef CONFIG_HAS_EARLYSUSPEND - unregister_early_suspend(&data->early_suspend); -#endif - - disable_debug_timer(data); - - disable_irq_wake(data->iIrq); - disable_irq(data->iIrq); - free_irq(data->iIrq, data); - gpio_free(data->client->irq); - - remove_sysfs(data); - remove_event_symlink(data); - remove_input_dev(data); - -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - ssp_remove_sensorhub(data); -#endif - - misc_deregister(&data->akmd_device); - - del_timer_sync(&data->debug_timer); - cancel_work_sync(&data->work_debug); - destroy_workqueue(data->debug_wq); - wake_lock_destroy(&data->ssp_wake_lock); - - toggle_mcu_reset(data); - - kfree(data); -} - -#ifdef CONFIG_HAS_EARLYSUSPEND -static void ssp_early_suspend(struct early_suspend *handler) -{ - struct ssp_data *data; - data = container_of(handler, struct ssp_data, early_suspend); - - func_dbg(); - disable_debug_timer(data); - -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - /* give notice to user that AP goes to sleep */ - ssp_report_sensorhub_notice(data, MSG2SSP_AP_STATUS_SLEEP); - ssp_sleep_mode(data); -#else - if (atomic_read(&data->aSensorEnable) > 0) - ssp_sleep_mode(data); -#endif - - data->bCheckSuspend = true; -} - -static void ssp_late_resume(struct early_suspend *handler) -{ - struct ssp_data *data; - data = container_of(handler, struct ssp_data, early_suspend); - - func_dbg(); - enable_debug_timer(data); - - data->bCheckSuspend = false; - -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - /* give notice to user that AP goes to sleep */ - ssp_report_sensorhub_notice(data, MSG2SSP_AP_STATUS_WAKEUP); - ssp_resume_mode(data); -#else - if (atomic_read(&data->aSensorEnable) > 0) - ssp_resume_mode(data); -#endif -} - -#else /* CONFIG_HAS_EARLYSUSPEND */ - -static int ssp_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ssp_data *data = i2c_get_clientdata(client); - - func_dbg(); - disable_debug_timer(data); - - if (atomic_read(&data->aSensorEnable) > 0) - ssp_sleep_mode(data); - - data->bCheckSuspend = true; - return 0; -} - -static int ssp_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ssp_data *data = i2c_get_clientdata(client); - - func_dbg(); - enable_debug_timer(data); - - data->bCheckSuspend = false; - - if (atomic_read(&data->aSensorEnable) > 0) - ssp_resume_mode(data); - - return 0; -} - -static const struct dev_pm_ops ssp_pm_ops = { - .suspend = ssp_suspend, - .resume = ssp_resume -}; - -#endif /* CONFIG_HAS_EARLYSUSPEND */ - -static const struct i2c_device_id ssp_id[] = { - {"ssp", 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, ssp_id); - -static struct i2c_driver ssp_driver = { - .probe = ssp_probe, - .shutdown = ssp_shutdown, - .id_table = ssp_id, - .driver = { -#ifndef CONFIG_HAS_EARLYSUSPEND - .pm = &ssp_pm_ops, -#endif - .owner = THIS_MODULE, - .name = "ssp" - }, -}; - -static int __init ssp_init(void) -{ - return i2c_add_driver(&ssp_driver); -} - -static void __exit ssp_exit(void) -{ - i2c_del_driver(&ssp_driver); -} - -module_init(ssp_init); -module_exit(ssp_exit); - -MODULE_DESCRIPTION("ssp driver"); -MODULE_AUTHOR("Samsung Electronics"); -MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/ssp_firmware.c b/drivers/sensorhub/ssp_firmware.c deleted file mode 100644 index 62e5efe4843..00000000000 --- a/drivers/sensorhub/ssp_firmware.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -#define SSP_FIRMWARE_REVISION 92800 - -/* Bootload mode cmd */ -#define BL_FW_NAME "ssp.fw" -#define BL_CRASHED_FW_NAME "ssp_crashed.fw" - -#define APP_SLAVE_ADDR 0x18 -#define BOOTLOADER_SLAVE_ADDR 0x26 - -/* Bootloader mode status */ -#define BL_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ -#define BL_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ -#define BL_FRAME_CRC_CHECK 0x02 -#define BL_FRAME_CRC_FAIL 0x03 -#define BL_FRAME_CRC_PASS 0x04 -#define BL_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ -#define BL_BOOT_STATUS_MASK 0x3f - -/* Command to unlock bootloader */ -#define BL_UNLOCK_CMD_MSB 0xaa -#define BL_UNLOCK_CMD_LSB 0xdc - -unsigned int get_module_rev(void) -{ - return SSP_FIRMWARE_REVISION; -} - -static int check_bootloader(struct i2c_client *client, unsigned int uState) -{ - u8 uVal; - u8 uTemp; - -recheck: - if (i2c_master_recv(client, &uVal, 1) != 1) - return -EIO; - - if (uVal & 0x20) { - if (i2c_master_recv(client, &uTemp, 1) != 1) { - pr_err("[SSP]: %s - i2c recv fail\n", __func__); - return -EIO; - } - - if (i2c_master_recv(client, &uTemp, 1) != 1) { - pr_err("[SSP]: %s - i2c recv fail\n", __func__); - return -EIO; - } - - uVal &= ~0x20; - } - - if ((uVal & 0xF0) == BL_APP_CRC_FAIL) { - pr_info("[SSP] SSP_APP_CRC_FAIL - There is no bootloader.\n"); - if (i2c_master_recv(client, &uVal, 1) != 1) { - pr_err("[SSP]: %s - i2c recv fail\n", __func__); - return -EIO; - } - - if (uVal & 0x20) { - if (i2c_master_recv(client, &uTemp, 1) != 1) { - pr_err("[SSP]: %s - i2c recv fail\n", __func__); - return -EIO; - } - - if (i2c_master_recv(client, &uTemp, 1) != 1) { - pr_err("[SSP]: %s - i2c recv fail\n", __func__); - return -EIO; - } - - uVal &= ~0x20; - } - } - - switch (uState) { - case BL_WAITING_BOOTLOAD_CMD: - case BL_WAITING_FRAME_DATA: - uVal &= ~BL_BOOT_STATUS_MASK; - break; - case BL_FRAME_CRC_PASS: - if (uVal == BL_FRAME_CRC_CHECK) - goto recheck; - break; - default: - return -EINVAL; - } - - if (uVal != uState) { - pr_err("[SSP]: %s - Unvalid bootloader mode state\n", __func__); - return -EINVAL; - } - - return 0; -} - -static int unlock_bootloader(struct i2c_client *client) -{ - u8 uBuf[2]; - - uBuf[0] = BL_UNLOCK_CMD_LSB; - uBuf[1] = BL_UNLOCK_CMD_MSB; - - if (i2c_master_send(client, uBuf, 2) != 2) { - pr_err("[SSP]: %s - i2c send failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int fw_write(struct i2c_client *client, - const u8 *pData, unsigned int uFrameSize) -{ - if (i2c_master_send(client, pData, uFrameSize) != uFrameSize) { - pr_err("[SSP]: %s - i2c send failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int load_fw_bootmode(struct i2c_client *client, const char *pFn) -{ - const struct firmware *fw = NULL; - unsigned int uFrameSize; - unsigned int uPos = 0; - int iRet; - int iCheckFrameCrcError = 0; - int iCheckWatingFrameDataError = 0; - - pr_info("[SSP] ssp_load_fw start!!!\n"); - - iRet = request_firmware(&fw, pFn, &client->dev); - if (iRet) { - pr_err("[SSP]: %s - Unable to open firmware %s\n", - __func__, pFn); - return iRet; - } - - /* Unlock bootloader */ - unlock_bootloader(client); - - while (uPos < fw->size) { - iRet = check_bootloader(client, BL_WAITING_FRAME_DATA); - if (iRet) { - iCheckWatingFrameDataError++; - if (iCheckWatingFrameDataError > 10) { - pr_err("[SSP]: %s - F/W update fail\n", - __func__); - goto out; - } else { - pr_err("[SSP]: %s - F/W data_error %d, retry\n", - __func__, iCheckWatingFrameDataError); - continue; - } - } - - uFrameSize = ((*(fw->data + uPos) << 8) | - *(fw->data + uPos + 1)); - - /* We should add 2 at frame size as the the firmware data is not - * included the CRC bytes. - */ - uFrameSize += 2; - - /* Write one frame to device */ - fw_write(client, fw->data + uPos, uFrameSize); - iRet = check_bootloader(client, BL_FRAME_CRC_PASS); - if (iRet) { - iCheckFrameCrcError++; - if (iCheckFrameCrcError > 10) { - pr_err("[SSP]: %s - F/W Update Fail. crc err\n", - __func__); - goto out; - } else { - pr_err("[SSP]: %s - F/W crc_error %d, retry\n", - __func__, iCheckFrameCrcError); - continue; - } - } - - uPos += uFrameSize; - - pr_info("[SSP] Updated %d bytes / %zd bytes\n", uPos, fw->size); - mdelay(1); - } - -out: - release_firmware(fw); - return iRet; -} - -static void change_to_bootmode(struct ssp_data *data) -{ - int iCnt = 0; - - for (iCnt = 0; iCnt < 10; iCnt++) { - data->set_mcu_reset(0); - udelay(10); - - data->set_mcu_reset(1); - msleep(100); - } - - msleep(50); -} - -void toggle_mcu_reset(struct ssp_data *data) -{ - u8 uBuf[2]; - - uBuf[0] = 0x00; - uBuf[1] = 0x00; - - data->set_mcu_reset(0); - udelay(10); - data->set_mcu_reset(1); - mdelay(50); - - data->client->addr = BOOTLOADER_SLAVE_ADDR; - - if (i2c_master_send(data->client, uBuf, 2) != 2) - pr_err("[SSP]: %s - ssp_Normal Mode\n", __func__); - else - pr_err("[SSP]: %s - ssp_load_fw_bootmode\n", __func__); - - data->client->addr = APP_SLAVE_ADDR; -} - -int update_mcu_bin(struct ssp_data *data) -{ - int iRet = 0; - - pr_info("[SSP] ssp_change_to_bootmode\n"); - change_to_bootmode(data); - data->client->addr = BOOTLOADER_SLAVE_ADDR; - iRet = load_fw_bootmode(data->client, BL_FW_NAME); - - msleep(SSP_SW_RESET_TIME); - - data->client->addr = APP_SLAVE_ADDR; - - if (iRet < 0) - data->bSspShutdown = true; - else - data->bSspShutdown = false; - - return iRet; -} - -int update_crashed_mcu_bin(struct ssp_data *data) -{ - int iRet = 0; - pr_info("[SSP] ssp_change_to_bootmode\n"); - change_to_bootmode(data); - data->client->addr = BOOTLOADER_SLAVE_ADDR; - iRet = load_fw_bootmode(data->client, BL_CRASHED_FW_NAME); - - msleep(SSP_SW_RESET_TIME); - - data->client->addr = APP_SLAVE_ADDR; - data->bSspShutdown = true; - return iRet; -} - -void check_fwbl(struct ssp_data *data) -{ - int iRet; - - data->client->addr = BOOTLOADER_SLAVE_ADDR; - iRet = check_bootloader(data->client, BL_WAITING_BOOTLOAD_CMD); - - if (iRet >= 0) { - pr_info("[SSP] ssp_load_fw_bootmode\n"); - load_fw_bootmode(data->client, BL_FW_NAME); - msleep(SSP_SW_RESET_TIME); - } else { - data->client->addr = APP_SLAVE_ADDR; - data->uCurFirmRev = get_firmware_rev(data); - if (data->uCurFirmRev != SSP_FIRMWARE_REVISION) { - pr_info("[SSP] MPU Firm Rev. : Old = %8u, New = %8u\n", - data->uCurFirmRev, SSP_FIRMWARE_REVISION); - update_mcu_bin(data); - } - } - - data->client->addr = APP_SLAVE_ADDR; - data->uCurFirmRev = get_firmware_rev(data); - pr_info("[SSP] MPU Firm Rev. : Old = %8u, New = %8u\n", - data->uCurFirmRev, SSP_FIRMWARE_REVISION); -} diff --git a/drivers/sensorhub/ssp_i2c.c b/drivers/sensorhub/ssp_i2c.c deleted file mode 100644 index 695ad8dae34..00000000000 --- a/drivers/sensorhub/ssp_i2c.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -#define LIMIT_DELAY_CNT 200 - -int waiting_wakeup_mcu(struct ssp_data *data) -{ - int iDelaycnt = 0; - - while (!data->check_mcu_busy() && (iDelaycnt++ < LIMIT_DELAY_CNT) - && (data->bSspShutdown == false)) - mdelay(5); - - if (iDelaycnt >= LIMIT_DELAY_CNT) { - pr_err("[SSP]: %s - MCU Irq Timeout!!\n", __func__); - data->uBusyCnt++; - } else { - data->uBusyCnt = 0; - } - - iDelaycnt = 0; - data->wakeup_mcu(); - while (data->check_mcu_ready() && (iDelaycnt++ < LIMIT_DELAY_CNT) - && (data->bSspShutdown == false)) - mdelay(5); - - if (iDelaycnt >= LIMIT_DELAY_CNT) { - pr_err("[SSP]: %s - MCU Wakeup Timeout!!\n", __func__); - data->uTimeOutCnt++; - } else { - data->uTimeOutCnt = 0; - } - - if (data->bSspShutdown == true) - return FAIL; - - return SUCCESS; -} - -int ssp_i2c_read(struct ssp_data *data, char *pTxData, u16 uTxLength, - char *pRxData, u16 uRxLength, int iRetries) -{ - int iRet = 0, iDiffTime = 0, iTimeTemp; - struct timeval cur_time; - struct i2c_client *client = data->client; - struct i2c_msg msgs[] = { - { - .addr = client->addr, - .flags = 0, - .len = uTxLength, - .buf = pTxData, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = uRxLength, - .buf = pRxData, - }, - }; - - do_gettimeofday(&cur_time); - iTimeTemp = (int)cur_time.tv_sec; - do { - iRet = i2c_transfer(client->adapter, msgs, 2); - if (iRet < 0) { - do_gettimeofday(&cur_time); - iDiffTime = (int)cur_time.tv_sec - iTimeTemp; - iTimeTemp = (int)cur_time.tv_sec; - if (iDiffTime >= 4) { - pr_err("[SSP]: %s - i2c time out %d!\n", - __func__, iDiffTime); - break; - } - pr_err("[SSP]: %s - i2c transfer error %d! retry...\n", - __func__, iRet); - mdelay(10); - } else { - return SUCCESS; - } - } while (--iRetries); - - return ERROR; -} - -int ssp_sleep_mode(struct ssp_data *data) -{ - char chRxBuf = 0; - char chTxBuf = MSG2SSP_AP_STATUS_SLEEP; - int iRet = 0, iRetries = DEFAULT_RETRIES; - - if (waiting_wakeup_mcu(data) < 0) - return ERROR; - - /* send to AP_STATUS_SLEEP */ - iRet = ssp_i2c_read(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD fail %d\n", - __func__, iRet); - return ERROR; - } else if (chRxBuf != MSG_ACK) { - while (iRetries--) { - mdelay(10); - pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD " - "retry...\n", __func__); - iRet = ssp_i2c_read(data, &chTxBuf, 1, - &chRxBuf, 1, DEFAULT_RETRIES); - if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) - break; - } - - if (iRetries < 0) { - data->uInstFailCnt++; - return FAIL; - } - } - - data->uInstFailCnt = 0; - ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD\n", __func__); - - return SUCCESS; -} - -int ssp_resume_mode(struct ssp_data *data) -{ - char chRxBuf = 0; - char chTxBuf = MSG2SSP_AP_STATUS_WAKEUP; - int iRet = 0, iRetries = DEFAULT_RETRIES; - - if (waiting_wakeup_mcu(data) < 0) - return ERROR; - - /* send to MSG2SSP_AP_STATUS_WAKEUP */ - iRet = ssp_i2c_read(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD fail %d\n", - __func__, iRet); - return ERROR; - } else if (chRxBuf != MSG_ACK) { - while (iRetries--) { - mdelay(10); - pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD " - "retry...\n", __func__); - iRet = ssp_i2c_read(data, &chTxBuf, 1, &chRxBuf, 1, - DEFAULT_RETRIES); - if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) - break; - } - - if (iRetries < 0) { - data->uInstFailCnt++; - return FAIL; - } - } - - data->uInstFailCnt = 0; - ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD\n", __func__); - - return SUCCESS; -} - -int send_instruction(struct ssp_data *data, u8 uInst, - u8 uSensorType, u8 *uSendBuf, u8 uLength) -{ - char chTxbuf[uLength + 3]; - char chRxbuf = 0; - int iRet = 0, iRetries = DEFAULT_RETRIES; - - if ((!(data->uSensorState & (1 << uSensorType))) - && (uInst <= CHANGE_DELAY)) { - pr_err("[SSP]: %s - Bypass Inst Skip! - %u\n", - __func__, uSensorType); - return FAIL; - } else if ((!((data->uSensorState | 0xf0) & (1 << uSensorType))) - && (uInst == FACTORY_MODE)) { - pr_err("[SSP]: %s - Factory Inst Skip! - %u\n", - __func__, uSensorType); - return FAIL; - } - - if (waiting_wakeup_mcu(data) < 0) - return ERROR; - - chTxbuf[0] = MSG2SSP_SSM; - - switch (uInst) { - case REMOVE_SENSOR: - chTxbuf[1] = MSG2SSP_INST_BYPASS_SENSOR_REMOVE; - break; - case ADD_SENSOR: - chTxbuf[1] = MSG2SSP_INST_BYPASS_SENSOR_ADD; - break; - case CHANGE_DELAY: - chTxbuf[1] = MSG2SSP_INST_CHANGE_DELAY; - break; - case GO_SLEEP: - chTxbuf[1] = MSG2SSP_AP_STATUS_SLEEP; - break; - case FACTORY_MODE: - chTxbuf[1] = MSG2SSP_INST_SENSOR_SELFTEST; - break; - case REMOVE_LIBRARY: - chTxbuf[1] = MSG2SSP_INST_LIBRARY_REMOVE; - break; - case ADD_LIBRARY: - chTxbuf[1] = MSG2SSP_INST_LIBRARY_ADD; - break; - default: - chTxbuf[1] = uInst; - break; - } - - chTxbuf[2] = uSensorType; - memcpy(&chTxbuf[3], uSendBuf, uLength); - - iRet = ssp_i2c_read(data, &(chTxbuf[0]), uLength + 3, &chRxbuf, 1, - DEFAULT_RETRIES); - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - Instruction CMD Fail %d\n", __func__, iRet); - return ERROR; - } else if (chRxbuf != MSG_ACK) { - while (iRetries--) { - mdelay(10); - pr_err("[SSP]: %s - Instruction CMD retry...\n", - __func__); - if (waiting_wakeup_mcu(data) < 0) - return ERROR; - iRet = ssp_i2c_read(data, &(chTxbuf[0]), - uLength + 3, &chRxbuf, 1, DEFAULT_RETRIES); - if ((iRet == SUCCESS) && (chRxbuf == MSG_ACK)) - break; - } - - if (iRetries < 0) { - data->uInstFailCnt++; - return FAIL; - } - } - - data->uInstFailCnt = 0; - ssp_dbg("[SSP]: %s - Inst = 0x%x, Sensor Type = 0x%x, " - "data = %u, %u\n", __func__, chTxbuf[1], chTxbuf[2], - chTxbuf[3], chTxbuf[4]); - return SUCCESS; -} - -int get_chipid(struct ssp_data *data) -{ - int iRet; - - if (waiting_wakeup_mcu(data) < 0) - return ERROR; - - /* read chip id */ - iRet = i2c_smbus_read_byte_data(data->client, MSG2SSP_AP_WHOAMI); - - return iRet; -} - -int set_sensor_position(struct ssp_data *data) -{ - char chTxBuf[5] = { 0, }; - char chRxData = 0; - int iRet = 0; - - if (waiting_wakeup_mcu(data) < 0) - return ERROR; - - chTxBuf[0] = MSG2SSP_AP_SENSOR_FORMATION; - - chTxBuf[1] = CONFIG_SENSORS_SSP_ACCELEROMETER_POSITION; - chTxBuf[2] = CONFIG_SENSORS_SSP_GYROSCOPE_POSITION; - chTxBuf[3] = CONFIG_SENSORS_SSP_MAGNETOMETER_POSITION; - chTxBuf[4] = 0; - - pr_info("[SSP] Sensor Posision A : %u, G : %u, M: %u, P: %u\n", - chTxBuf[1], chTxBuf[2], chTxBuf[3], chTxBuf[4]); - - iRet = ssp_i2c_read(data, chTxBuf, 5, &chRxData, 1, DEFAULT_RETRIES); - if ((chRxData != MSG_ACK) || (iRet != SUCCESS)) { - pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); - iRet = ERROR; - } - - return iRet; -} - -void set_proximity_threshold(struct ssp_data *data, - unsigned char uData1, unsigned char uData2) -{ - char chTxBuf[3] = { 0, }; - char chRxBuf = 0; - int iRet = 0, iRetries = DEFAULT_RETRIES; - - if (waiting_wakeup_mcu(data) < 0) - return; - - chTxBuf[0] = MSG2SSP_AP_SENSOR_PROXTHRESHOLD; - chTxBuf[1] = uData1; - chTxBuf[2] = uData2; - - iRet = ssp_i2c_read(data, chTxBuf, 3, &chRxBuf, 1, DEFAULT_RETRIES); - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - SENSOR_PROXTHRESHOLD CMD fail %d\n", - __func__, iRet); - return; - } else if (chRxBuf != MSG_ACK) { - while (iRetries--) { - mdelay(10); - pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_PROXTHRESHOLD CMD" - " retry...\n", __func__); - iRet = ssp_i2c_read(data, chTxBuf, 3, &chRxBuf, 1, - DEFAULT_RETRIES); - if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) - break; - } - - if (iRetries < 0) { - data->uInstFailCnt++; - return; - } - } - - data->uInstFailCnt = 0; - pr_info("[SSP]: Proximity Threshold - %u, %u\n", uData1, uData2); -} - -void set_proximity_barcode_enable(struct ssp_data *data, bool bEnable) -{ - char chTxBuf[2] = { 0, }; - char chRxBuf = 0; - int iRet = 0, iRetries = DEFAULT_RETRIES; - - if (waiting_wakeup_mcu(data) < 0) - return ; - - chTxBuf[0] = MSG2SSP_AP_SENSOR_BARCODE_EMUL; - chTxBuf[1] = bEnable; - - data->bBarcodeEnabled = bEnable; - - iRet = ssp_i2c_read(data, chTxBuf, 2, &chRxBuf, 1, DEFAULT_RETRIES); - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - SENSOR_BARCODE_EMUL CMD fail %d\n", - __func__, iRet); - return; - } else if (chRxBuf != MSG_ACK) { - while (iRetries--) { - mdelay(10); - pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_BARCODE_EMUL CMD " - "retry...\n", __func__); - iRet = ssp_i2c_read(data, chTxBuf, 2, &chRxBuf, 1, - DEFAULT_RETRIES); - if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) - break; - } - - if (iRetries < 0) { - data->uInstFailCnt++; - return; - } - } - - data->uInstFailCnt = 0; - pr_info("[SSP] Proximity Barcode En : %u\n", bEnable); -} - -unsigned int get_sensor_scanning_info(struct ssp_data *data) -{ - char chTxBuf = MSG2SSP_AP_SENSOR_SCANNING; - char chRxData[2] = {0,}; - int iRet = 0; - - if (waiting_wakeup_mcu(data) < 0) - return ERROR; - - iRet = ssp_i2c_read(data, &chTxBuf, 1, chRxData, 2, DEFAULT_RETRIES); - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - i2c failed %d\n", __func__, iRet); - return 0; - } - return ((unsigned int)chRxData[0] << 8) | chRxData[1]; -} - -unsigned int get_firmware_rev(struct ssp_data *data) -{ - char chTxData = MSG2SSP_AP_FIRMWARE_REV; - char chRxBuf[3] = { 0, }; - unsigned int uRev = 99999; - int iRet; - - if (waiting_wakeup_mcu(data) < 0) - return ERROR; - - iRet = ssp_i2c_read(data, &chTxData, 1, chRxBuf, 3, DEFAULT_RETRIES); - if (iRet != SUCCESS) - pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); - else - uRev = ((unsigned int)chRxBuf[0] << 16) - | ((unsigned int)chRxBuf[1] << 8) | chRxBuf[2]; - return uRev; -} - -int get_fuserom_data(struct ssp_data *data) -{ - char chTxBuf[2] = { 0, }; - char chRxBuf[2] = { 0, }; - int iRet = 0; - unsigned int uLength = 0; - - if (waiting_wakeup_mcu(data) < 0) - return ERROR; - - chTxBuf[0] = MSG2SSP_AP_STT; - chTxBuf[1] = MSG2SSP_AP_FUSEROM; - - /* chRxBuf is Two Byte because msg is large */ - iRet = ssp_i2c_read(data, chTxBuf, 2, chRxBuf, 2, DEFAULT_RETRIES); - uLength = ((unsigned int)chRxBuf[0] << 8) + (unsigned int)chRxBuf[1]; - - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - MSG2SSP_AP_STT - i2c fail %d\n", - __func__, iRet); - goto err_read_fuserom; - } else if (uLength <= 0) { - pr_err("[SSP]: %s - No ready data. length = %u\n", - __func__, uLength); - goto err_read_fuserom; - } else { - if (data->iLibraryLength != 0) - kfree(data->pchLibraryBuf); - - data->iLibraryLength = (int)uLength; - data->pchLibraryBuf = - kzalloc((data->iLibraryLength * sizeof(char)), GFP_KERNEL); - - chTxBuf[0] = MSG2SSP_SRM; - iRet = ssp_i2c_read(data, chTxBuf, 1, data->pchLibraryBuf, - (u16)data->iLibraryLength, DEFAULT_RETRIES); - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - Fail to receive SSP data %d\n", - __func__, iRet); - kfree(data->pchLibraryBuf); - data->iLibraryLength = 0; - goto err_read_fuserom; - } - } - - data->uFuseRomData[0] = data->pchLibraryBuf[0]; - data->uFuseRomData[1] = data->pchLibraryBuf[1]; - data->uFuseRomData[2] = data->pchLibraryBuf[2]; - - pr_info("[SSP] FUSE ROM Data %d , %d, %d\n", data->uFuseRomData[0], - data->uFuseRomData[1], data->uFuseRomData[2]); - - data->iLibraryLength = 0; - kfree(data->pchLibraryBuf); - return SUCCESS; - -err_read_fuserom: - data->uFuseRomData[0] = 0; - data->uFuseRomData[1] = 0; - data->uFuseRomData[2] = 0; - - return FAIL; -} - -static int ssp_receive_msg(struct ssp_data *data, u8 uLength) -{ - char chTxBuf = 0; - char *pchRcvDataFrame; /* SSP-AP Massage data buffer */ - int iRet = 0; - - if (uLength > 0) { - pchRcvDataFrame = kzalloc((uLength * sizeof(char)), GFP_KERNEL); - chTxBuf = MSG2SSP_SRM; - iRet = ssp_i2c_read(data, &chTxBuf, 1, pchRcvDataFrame, - (u16)uLength, 0); - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - Fail to receive data %d\n", - __func__, iRet); - kfree(pchRcvDataFrame); - return ERROR; - } - } else { - pr_err("[SSP]: %s - No ready data. length = %d\n", - __func__, uLength); - return FAIL; - } - - parse_dataframe(data, pchRcvDataFrame, uLength); - - kfree(pchRcvDataFrame); - return uLength; -} - -int select_irq_msg(struct ssp_data *data) -{ - u8 chLength = 0; - char chTxBuf = 0; - char chRxBuf[2] = { 0, }; - int iRet = 0; - - chTxBuf = MSG2SSP_SSD; - iRet = ssp_i2c_read(data, &chTxBuf, 1, chRxBuf, 2, 0); - - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - MSG2SSP_SSD error %d\n", __func__, iRet); - return ERROR; - } else { - if (chRxBuf[0] == MSG2SSP_RTS) { - chLength = (u8)chRxBuf[1]; - ssp_receive_msg(data, chLength); - data->uSsdFailCnt = 0; - } -#ifdef CONFIG_SENSORS_SSP_SENSORHUB - else if (chRxBuf[0] == MSG2SSP_STT) { - pr_info("%s: MSG2SSP_STT irq", __func__); - iRet = ssp_handle_sensorhub_large_data(data, - (u8)chRxBuf[1]); - if (iRet < 0) { - pr_err("%s: ssp_handle_sensorhub_data(%d)", - __func__, iRet); - } - data->uSsdFailCnt = 0; - } -#endif - else { - pr_err("[SSP]: %s - MSG2SSP_SSD Data fail " - "[0]: 0x%x, [1]: 0x%x\n", __func__, - chRxBuf[0], chRxBuf[1]); - if ((chRxBuf[0] == 0) && (chRxBuf[1] == 0)) - data->uSsdFailCnt++; - } - } - return SUCCESS; -} diff --git a/drivers/sensorhub/ssp_input.c b/drivers/sensorhub/ssp_input.c deleted file mode 100644 index a7de8c60836..00000000000 --- a/drivers/sensorhub/ssp_input.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -/*************************************************************************/ -/* SSP Kernel -> HAL input evnet function */ -/*************************************************************************/ -void convert_acc_data(s16 *iValue) -{ - if (*iValue > 2048) - *iValue = ((4096 - *iValue)) * (-1); -} - -void report_acc_data(struct ssp_data *data, struct sensor_value *accdata) -{ - convert_acc_data(&accdata->x); - convert_acc_data(&accdata->y); - convert_acc_data(&accdata->z); - - data->buf[ACCELEROMETER_SENSOR].x = accdata->x - data->accelcal.x; - data->buf[ACCELEROMETER_SENSOR].y = accdata->y - data->accelcal.y; - data->buf[ACCELEROMETER_SENSOR].z = accdata->z - data->accelcal.z; - - input_report_rel(data->acc_input_dev, REL_X, - data->buf[ACCELEROMETER_SENSOR].x); - input_report_rel(data->acc_input_dev, REL_Y, - data->buf[ACCELEROMETER_SENSOR].y); - input_report_rel(data->acc_input_dev, REL_Z, - data->buf[ACCELEROMETER_SENSOR].z); - input_sync(data->acc_input_dev); -} - -void report_gyro_data(struct ssp_data *data, struct sensor_value *gyrodata) -{ - long lTemp[3] = {0,}; - data->buf[GYROSCOPE_SENSOR].x = gyrodata->x - data->gyrocal.x; - data->buf[GYROSCOPE_SENSOR].y = gyrodata->y - data->gyrocal.y; - data->buf[GYROSCOPE_SENSOR].z = gyrodata->z - data->gyrocal.z; - - if (data->uGyroDps == GYROSCOPE_DPS250) { - lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x >> 1; - lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y >> 1; - lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z >> 1; - } else if (data->uGyroDps == GYROSCOPE_DPS2000) { - lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x << 2; - lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y << 2; - lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z << 2; - } else { - lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x; - lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y; - lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z; - } - - input_report_rel(data->gyro_input_dev, REL_RX, lTemp[0]); - input_report_rel(data->gyro_input_dev, REL_RY, lTemp[1]); - input_report_rel(data->gyro_input_dev, REL_RZ, lTemp[2]); - input_sync(data->gyro_input_dev); -} - -void report_mag_data(struct ssp_data *data, struct sensor_value *magdata) -{ - data->buf[GEOMAGNETIC_SENSOR].x = magdata->x; - data->buf[GEOMAGNETIC_SENSOR].y = magdata->y; - data->buf[GEOMAGNETIC_SENSOR].z = magdata->z; -} - -void report_gesture_data(struct ssp_data *data, struct sensor_value *gesdata) -{ - /* todo: remove func*/ -} - -void report_pressure_data(struct ssp_data *data, struct sensor_value *predata) -{ - data->buf[PRESSURE_SENSOR].pressure[0] = - predata->pressure[0] - data->iPressureCal; - data->buf[PRESSURE_SENSOR].pressure[1] = predata->pressure[1]; - - /* pressure */ - input_report_rel(data->pressure_input_dev, REL_HWHEEL, - data->buf[PRESSURE_SENSOR].pressure[0]); - /* temperature */ - input_report_rel(data->pressure_input_dev, REL_WHEEL, - data->buf[PRESSURE_SENSOR].pressure[1]); - input_sync(data->pressure_input_dev); -} - -void report_light_data(struct ssp_data *data, struct sensor_value *lightdata) -{ - data->buf[LIGHT_SENSOR].r = lightdata->r; - data->buf[LIGHT_SENSOR].g = lightdata->g; - data->buf[LIGHT_SENSOR].b = lightdata->b; - data->buf[LIGHT_SENSOR].w = lightdata->w; - - input_report_rel(data->light_input_dev, REL_HWHEEL, - data->buf[LIGHT_SENSOR].r + 1); - input_report_rel(data->light_input_dev, REL_DIAL, - data->buf[LIGHT_SENSOR].g + 1); - input_report_rel(data->light_input_dev, REL_WHEEL, - data->buf[LIGHT_SENSOR].b + 1); - input_report_rel(data->light_input_dev, REL_MISC, - data->buf[LIGHT_SENSOR].w + 1); - input_sync(data->light_input_dev); -} - -void report_prox_data(struct ssp_data *data, struct sensor_value *proxdata) -{ - ssp_dbg("[SSP] Proximity Sensor Detect : %u, raw : %u\n", - proxdata->prox[0], proxdata->prox[1]); - - data->buf[PROXIMITY_SENSOR].prox[0] = proxdata->prox[0]; - data->buf[PROXIMITY_SENSOR].prox[1] = proxdata->prox[1]; - - input_report_abs(data->prox_input_dev, ABS_DISTANCE, - (!proxdata->prox[0])); - input_sync(data->prox_input_dev); - - wake_lock_timeout(&data->ssp_wake_lock, 3 * HZ); -} - -void report_prox_raw_data(struct ssp_data *data, - struct sensor_value *proxrawdata) -{ - if (data->uFactoryProxAvg[0]++ >= PROX_AVG_READ_NUM) { - data->uFactoryProxAvg[2] /= PROX_AVG_READ_NUM; - data->buf[PROXIMITY_RAW].prox[1] = (u8)data->uFactoryProxAvg[1]; - data->buf[PROXIMITY_RAW].prox[2] = (u8)data->uFactoryProxAvg[2]; - data->buf[PROXIMITY_RAW].prox[3] = (u8)data->uFactoryProxAvg[3]; - - data->uFactoryProxAvg[0] = 0; - data->uFactoryProxAvg[1] = 0; - data->uFactoryProxAvg[2] = 0; - data->uFactoryProxAvg[3] = 0; - } else { - data->uFactoryProxAvg[2] += proxrawdata->prox[0]; - - if (data->uFactoryProxAvg[0] == 1) - data->uFactoryProxAvg[1] = proxrawdata->prox[0]; - else if (proxrawdata->prox[0] < data->uFactoryProxAvg[1]) - data->uFactoryProxAvg[1] = proxrawdata->prox[0]; - - if (proxrawdata->prox[0] > data->uFactoryProxAvg[3]) - data->uFactoryProxAvg[3] = proxrawdata->prox[0]; - } - - data->buf[PROXIMITY_RAW].prox[0] = proxrawdata->prox[0]; -} - -int initialize_event_symlink(struct ssp_data *data) -{ - int iRet = 0; - struct class *event_class = NULL; - - event_class = class_create(THIS_MODULE, "sensor_event"); - data->sen_dev = device_create(event_class, NULL, 0, NULL, - "%s", "symlink"); - - iRet = sysfs_create_link(&data->sen_dev->kobj, - &data->acc_input_dev->dev.kobj, - data->acc_input_dev->name); - if (iRet < 0) - goto iRet_acc_sysfs_create_link; - - iRet = sysfs_create_link(&data->sen_dev->kobj, - &data->gyro_input_dev->dev.kobj, - data->gyro_input_dev->name); - if (iRet < 0) - goto iRet_gyro_sysfs_create_link; - - iRet = sysfs_create_link(&data->sen_dev->kobj, - &data->pressure_input_dev->dev.kobj, - data->pressure_input_dev->name); - if (iRet < 0) - goto iRet_prs_sysfs_create_link; - - iRet = sysfs_create_link(&data->sen_dev->kobj, - &data->light_input_dev->dev.kobj, - data->light_input_dev->name); - if (iRet < 0) - goto iRet_light_sysfs_create_link; - - iRet = sysfs_create_link(&data->sen_dev->kobj, - &data->prox_input_dev->dev.kobj, - data->prox_input_dev->name); - if (iRet < 0) - goto iRet_prox_sysfs_create_link; - - return SUCCESS; - -iRet_prox_sysfs_create_link: - sysfs_delete_link(&data->sen_dev->kobj, - &data->light_input_dev->dev.kobj, - data->light_input_dev->name); -iRet_light_sysfs_create_link: - sysfs_delete_link(&data->sen_dev->kobj, - &data->pressure_input_dev->dev.kobj, - data->pressure_input_dev->name); -iRet_prs_sysfs_create_link: - sysfs_delete_link(&data->sen_dev->kobj, - &data->gyro_input_dev->dev.kobj, - data->gyro_input_dev->name); -iRet_gyro_sysfs_create_link: - sysfs_delete_link(&data->sen_dev->kobj, - &data->acc_input_dev->dev.kobj, - data->acc_input_dev->name); -iRet_acc_sysfs_create_link: - pr_err("[SSP]: %s - could not create event symlink\n", __func__); - - return FAIL; -} - -void remove_event_symlink(struct ssp_data *data) -{ - sysfs_delete_link(&data->sen_dev->kobj, - &data->acc_input_dev->dev.kobj, - data->acc_input_dev->name); - sysfs_delete_link(&data->sen_dev->kobj, - &data->gyro_input_dev->dev.kobj, - data->gyro_input_dev->name); - sysfs_delete_link(&data->sen_dev->kobj, - &data->pressure_input_dev->dev.kobj, - data->pressure_input_dev->name); - sysfs_delete_link(&data->sen_dev->kobj, - &data->light_input_dev->dev.kobj, - data->light_input_dev->name); - sysfs_delete_link(&data->sen_dev->kobj, - &data->prox_input_dev->dev.kobj, - data->prox_input_dev->name); -} - -int initialize_input_dev(struct ssp_data *data) -{ - int iRet = 0; - struct input_dev *acc_input_dev, *gyro_input_dev, *pressure_input_dev, - *light_input_dev, *prox_input_dev; - - /* allocate input_device */ - acc_input_dev = input_allocate_device(); - if (acc_input_dev == NULL) - goto iRet_acc_input_free_device; - - gyro_input_dev = input_allocate_device(); - if (gyro_input_dev == NULL) - goto iRet_gyro_input_free_device; - - pressure_input_dev = input_allocate_device(); - if (pressure_input_dev == NULL) - goto iRet_pressure_input_free_device; - - light_input_dev = input_allocate_device(); - if (light_input_dev == NULL) - goto iRet_light_input_free_device; - - prox_input_dev = input_allocate_device(); - if (prox_input_dev == NULL) - goto iRet_proximity_input_free_device; - - input_set_drvdata(acc_input_dev, data); - input_set_drvdata(gyro_input_dev, data); - input_set_drvdata(pressure_input_dev, data); - input_set_drvdata(light_input_dev, data); - input_set_drvdata(prox_input_dev, data); - - acc_input_dev->name = "accelerometer_sensor"; - gyro_input_dev->name = "gyro_sensor"; - pressure_input_dev->name = "pressure_sensor"; - light_input_dev->name = "light_sensor"; - prox_input_dev->name = "proximity_sensor"; - - input_set_capability(acc_input_dev, EV_REL, REL_X); - input_set_capability(acc_input_dev, EV_REL, REL_Y); - input_set_capability(acc_input_dev, EV_REL, REL_Z); - - input_set_capability(gyro_input_dev, EV_REL, REL_RX); - input_set_capability(gyro_input_dev, EV_REL, REL_RY); - input_set_capability(gyro_input_dev, EV_REL, REL_RZ); - - input_set_capability(pressure_input_dev, EV_REL, REL_HWHEEL); - input_set_capability(pressure_input_dev, EV_REL, REL_DIAL); - input_set_capability(pressure_input_dev, EV_REL, REL_WHEEL); - - input_set_capability(light_input_dev, EV_REL, REL_HWHEEL); - input_set_capability(light_input_dev, EV_REL, REL_DIAL); - input_set_capability(light_input_dev, EV_REL, REL_WHEEL); - input_set_capability(light_input_dev, EV_REL, REL_MISC); - - input_set_capability(prox_input_dev, EV_ABS, ABS_DISTANCE); - input_set_abs_params(prox_input_dev, ABS_DISTANCE, 0, 1, 0, 0); - - /* register input_device */ - iRet = input_register_device(acc_input_dev); - if (iRet < 0) - goto iRet_acc_input_unreg_device; - - iRet = input_register_device(gyro_input_dev); - if (iRet < 0) { - input_free_device(gyro_input_dev); - goto iRet_gyro_input_unreg_device; - } - - iRet = input_register_device(pressure_input_dev); - if (iRet < 0) { - input_free_device(pressure_input_dev); - goto iRet_pressure_input_unreg_device; - } - - iRet = input_register_device(light_input_dev); - if (iRet < 0) { - input_free_device(light_input_dev); - goto iRet_light_input_unreg_device; - } - - iRet = input_register_device(prox_input_dev); - if (iRet < 0) { - input_free_device(prox_input_dev); - goto iRet_proximity_input_unreg_device; - } - - data->acc_input_dev = acc_input_dev; - data->gyro_input_dev = gyro_input_dev; - data->pressure_input_dev = pressure_input_dev; - data->light_input_dev = light_input_dev; - data->prox_input_dev = prox_input_dev; - - return SUCCESS; - -iRet_proximity_input_unreg_device: - input_unregister_device(light_input_dev); -iRet_light_input_unreg_device: - input_unregister_device(pressure_input_dev); -iRet_pressure_input_unreg_device: - input_unregister_device(gyro_input_dev); -iRet_gyro_input_unreg_device: - input_unregister_device(acc_input_dev); - return ERROR; - -iRet_acc_input_unreg_device: - pr_err("[SSP]: %s - could not register input device\n", __func__); - input_free_device(prox_input_dev); -iRet_proximity_input_free_device: - input_free_device(light_input_dev); -iRet_light_input_free_device: - input_free_device(pressure_input_dev); -iRet_pressure_input_free_device: - input_free_device(gyro_input_dev); -iRet_gyro_input_free_device: - input_free_device(acc_input_dev); -iRet_acc_input_free_device: - pr_err("[SSP]: %s - could not allocate input device\n", __func__); - return ERROR; -} - -void remove_input_dev(struct ssp_data *data) -{ - input_unregister_device(data->acc_input_dev); - input_unregister_device(data->gyro_input_dev); - input_unregister_device(data->pressure_input_dev); - input_unregister_device(data->light_input_dev); - input_unregister_device(data->prox_input_dev); -} diff --git a/drivers/sensorhub/ssp_sensorhub.c b/drivers/sensorhub/ssp_sensorhub.c deleted file mode 100644 index bfa80d0845e..00000000000 --- a/drivers/sensorhub/ssp_sensorhub.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "ssp.h" - -static const struct fast_data { - char library_data[3]; -} fast_data_table[] = { - { { 1, 1, 7 } }, -}; - -static ssize_t ssp_sensorhub_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) -{ - struct ssp_sensorhub_data *hub_data - = container_of(file->private_data, - struct ssp_sensorhub_data, sensorhub_device); - int ret = 0; - int i; - u8 instruction = buf[0]; - - if (count == 0) { - pr_err("%s: library command length err(%d)", __func__, count); - return -EINVAL; - } - - for (i = 0; i < count; i++) - pr_info("%s[%d] = 0x%x", __func__, i, buf[i]); - - if (buf[0] == MSG2SSP_INST_LIBRARY_REMOVE) - instruction = REMOVE_LIBRARY; - else if (buf[0] == MSG2SSP_INST_LIBRARY_ADD) - instruction = ADD_LIBRARY; - - if (hub_data->ssp_data->bSspShutdown) { - pr_err("%s: stop sending command(no ssp_data)", __func__); - return -ENOMEM; - } - - ret = send_instruction(hub_data->ssp_data, instruction, - (u8)buf[1], (u8 *)(buf+2), count-2); - if (ret <= 0) - pr_err("%s: send library command err(%d)", __func__, ret); - - /* i2c transfer fail */ - if (ret == ERROR) - return -EIO; - /* no ack from MCU */ - else if (ret == FAIL) - return -EAGAIN; - /* success */ - else - return count; -} - -static long ssp_sensorhub_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - struct ssp_sensorhub_data *hub_data - = container_of(file->private_data, - struct ssp_sensorhub_data, sensorhub_device); - int ret = 0; - int i = 0; - - switch (cmd) { - case IOCTL_READ_CONTEXT_DATA: - /* for receive_msg */ - if (!hub_data->large_library_length && - hub_data->large_library_data == NULL) { - - ret = copy_to_user(argp, - hub_data->first_event->library_data, - hub_data->first_event->length); - if (ret < 0) { - pr_err("%s: send library data err(%d)", - __func__, ret); - complete(&hub_data->transfer_done); - goto exit; - } - - for (i = 0; i < hub_data->first_event->length; i++) { - pr_info("%s[%d] = 0x%x", __func__, i, - hub_data->first_event->library_data[i]); - } - - hub_data->transfer_try = 0; - complete(&hub_data->transfer_done); - - /* for receive_large_msg */ - } else { - pr_info("%s: receive_large_msg ioctl", __func__); - ret = copy_to_user(argp, hub_data->large_library_data, - hub_data->large_library_length); - if (ret < 0) { - pr_err("%s: send large library data err(%d)", - __func__, ret); - goto exit; - } - - kfree(hub_data->large_library_data); - hub_data->large_library_length = 0; - } - break; - - default: - pr_err("%s: icotl cmd err(%d)", __func__, cmd); - ret = -EINVAL; - } - -exit: - return ret; -} - -static struct file_operations ssp_sensorhub_fops = { - .owner = THIS_MODULE, - .open = nonseekable_open, - .write = ssp_sensorhub_write, - .unlocked_ioctl = ssp_sensorhub_ioctl, -}; - -void ssp_report_sensorhub_notice(struct ssp_data *ssp_data, char notice) -{ - struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; - - input_report_rel(hub_data->sensorhub_input_dev, REL_RY, notice); - input_sync(hub_data->sensorhub_input_dev); - - if (notice == MSG2SSP_AP_STATUS_WAKEUP) - pr_info("%s: wake up", __func__); - else if (notice == MSG2SSP_AP_STATUS_SLEEP) - pr_info("%s: sleep", __func__); - else if (notice == MSG2SSP_AP_STATUS_RESET) - pr_info("%s: reset", __func__); - else - pr_err("%s: invalid notice", __func__); -} - -static void ssp_report_sensorhub_length(struct ssp_sensorhub_data *hub_data, - int length) -{ - input_report_rel(hub_data->sensorhub_input_dev, REL_RX, length); - input_sync(hub_data->sensorhub_input_dev); - pr_info("%s = %d", __func__, length); -} - -static int ssp_sensorhub_is_fast_data(char *data, int start) -{ - int i, j; - - for (i = 0; i < ARRAY_SIZE(fast_data_table); i++) { - for (j = 0; j < sizeof(fast_data_table[0]); j++) { - if (data[start + j] != - fast_data_table[i].library_data[j]) - break; - } - if (j == sizeof(fast_data_table[0])) - return i; - } - - return -EINVAL; -} - -static int ssp_queue_sensorhub_events(struct ssp_sensorhub_data *hub_data, - char *dataframe, int start, int end) -{ - struct sensorhub_event *event; - int length = end - start; - int event_number = hub_data->event_number; - int events = 0; - int ret = 0; - int i = 0; - - if (length <= 0) { - pr_err("%s: library length err(%d)", __func__, length); - return -EINVAL; - } - - /* how many events in the list? */ - spin_lock_bh(&hub_data->sensorhub_lock); - list_for_each_entry(event, &hub_data->events_head.list, list) - events++; - spin_unlock_bh(&hub_data->sensorhub_lock); - - /* drop event if queue is full */ - if (events >= LIBRARY_MAX_NUM) { - pr_info("%s: queue is full", __func__); - hub_data->transfer_ready++; - ret = ssp_sensorhub_is_fast_data(dataframe, start); - if (ret >= 0) - event_number = LIBRARY_MAX_NUM + ret; - else - return -ENOMEM; - } - - /* allocate memory for new event */ - if (hub_data->events[event_number].library_data != NULL) - kfree(hub_data->events[event_number].library_data); - - hub_data->events[event_number].library_data - = kzalloc(length * sizeof(char), GFP_KERNEL); - if (hub_data->events[event_number].library_data == NULL) { - pr_err("%s: allocate memory for library data err", __func__); - return -ENOMEM; - } - - /* copy sensorhub event into queue */ - while (start < end) { - hub_data->events[event_number].library_data[i++] - = dataframe[start++]; - pr_info("%s[%d] = 0x%x", __func__, i-1, - hub_data->events[event_number].library_data[i-1]); - } - hub_data->events[event_number].length = length; - - if (events <= LIBRARY_MAX_NUM) { - /* add new event at the end of queue */ - spin_lock_bh(&hub_data->sensorhub_lock); - list_add_tail(&hub_data->events[event_number].list, - &hub_data->events_head.list); - if (events++ < LIBRARY_MAX_NUM) - hub_data->transfer_ready = 0; - spin_unlock_bh(&hub_data->sensorhub_lock); - - /* do not exceed max queue number */ - if (hub_data->event_number++ >= LIBRARY_MAX_NUM - 1) - hub_data->event_number = 0; - } else { - spin_lock_bh(&hub_data->sensorhub_lock); - list_replace(hub_data->events_head.list.prev, - &hub_data->events[event_number].list); - spin_unlock_bh(&hub_data->sensorhub_lock); - } - - pr_info("%s: total %d events", __func__, events); - return events; -} - -static int ssp_receive_large_msg(struct ssp_sensorhub_data *hub_data, - u8 sub_cmd) -{ - char send_data[2] = { 0, }; - char receive_data[2] = { 0, }; - char *large_msg_data; /* Nth large msg data */ - int length = 0; /* length of Nth large msg */ - int data_locater = 0; /* large_library_data current position */ - int total_msg_number; /* total number of large msg */ - int msg_number; /* current number of large msg */ - int ret = 0; - - /* receive the first msg length */ - send_data[0] = MSG2SSP_STT; - send_data[1] = sub_cmd; - - /* receive_data(msg length) is two byte because msg is large */ - ret = ssp_i2c_read(hub_data->ssp_data, send_data, 2, - receive_data, 2, 0); - if (ret < 0) { - pr_err("%s: MSG2SSP_STT i2c err(%d)", __func__, ret); - return ret; - } - - /* get the first msg length */ - length = ((unsigned int)receive_data[0] << 8) - + (unsigned int)receive_data[1]; - if (length < 3) { - /* do not print err message with power-up */ - if (sub_cmd != SUBCMD_POWEREUP) - pr_err("%s: 1st large msg data not ready(length=%d)", - __func__, length); - return -EINVAL; - } - - /* receive the first msg data */ - send_data[0] = MSG2SSP_SRM; - large_msg_data = kzalloc((length * sizeof(char)), GFP_KERNEL); - ret = ssp_i2c_read(hub_data->ssp_data, send_data, 1, - large_msg_data, length, 0); - if (ret < 0) { - pr_err("%s: receive 1st large msg err(%d)", __func__, ret); - kfree(large_msg_data); - return ret; - } - - /* empty the previous large library data */ - if (hub_data->large_library_length != 0) - kfree(hub_data->large_library_data); - - /* large_msg_data[0] of the first msg: total number of large msg - * large_msg_data[1-2] of the first msg: total msg length - * large_msg_data[3-N] of the first msg: the first msg data itself */ - total_msg_number = large_msg_data[0]; - hub_data->large_library_length - = (int)((unsigned int)large_msg_data[1] << 8) - + (unsigned int)large_msg_data[2]; - hub_data->large_library_data - = kzalloc((hub_data->large_library_length * sizeof(char)), - GFP_KERNEL); - - /* copy the fist msg data into large_library_data */ - memcpy(hub_data->large_library_data, &large_msg_data[3], - (length - 3) * sizeof(char)); - kfree(large_msg_data); - - data_locater = length - 3; - - /* 2nd, 3rd,...Nth msg */ - for (msg_number = 0; msg_number < total_msg_number; msg_number++) { - /* receive Nth msg length */ - send_data[0] = MSG2SSP_STT; - send_data[1] = 0x81 + msg_number; - - /* receive_data(msg length) is two byte because msg is large */ - ret = ssp_i2c_read(hub_data->ssp_data, send_data, 2, - receive_data, 2, 0); - if (ret < 0) { - pr_err("%s: MSG2SSP_STT i2c err(%d)", - __func__, ret); - return ret; - } - - /* get the Nth msg length */ - length = ((unsigned int)receive_data[0] << 8) - + (unsigned int)receive_data[1]; - if (length <= 0) { - pr_err("%s: %dth large msg data not ready(length=%d)", - __func__, msg_number + 2, length); - return -EINVAL; - } - - large_msg_data = kzalloc((length * sizeof(char)), - GFP_KERNEL); - - /* receive Nth msg data */ - send_data[0] = MSG2SSP_SRM; - ret = ssp_i2c_read(hub_data->ssp_data, send_data, 1, - large_msg_data, length, 0); - if (ret < 0) { - pr_err("%s: recieve %dth large msg err(%d)", - __func__, msg_number + 2, ret); - kfree(large_msg_data); - return ret; - } - - /* copy(append) Nth msg data into large_library_data */ - memcpy(&hub_data->large_library_data[data_locater], - large_msg_data, length * sizeof(char)); - data_locater += length; - kfree(large_msg_data); - } - - return hub_data->large_library_length; -} - -static int ssp_senosrhub_thread_func(void *arg) -{ - struct ssp_sensorhub_data *hub_data = (struct ssp_sensorhub_data *)arg; - struct sensorhub_event *event; - int events = 0; - int ret = 0; - - while (!kthread_should_stop()) { - /* run if only event queue is not empty */ - wait_event_interruptible(hub_data->sensorhub_waitqueue, - kthread_should_stop() || - !list_empty(&hub_data->events_head.list)); - - /* exit thread if kthread should stop */ - if (unlikely(kthread_should_stop())) { - pr_info("%s: kthread_stop()", __func__); - break; - } - - /* exit thread - * if user does not get data with consecutive trials - */ - if (unlikely(hub_data->transfer_try++ >= LIBRARY_MAX_TRY)) { - pr_err("%s: user does not get data", __func__); - break; - } - - /* report sensorhub event to user */ - if (hub_data->transfer_ready == 0) { - /* first in first out */ - hub_data->first_event - = list_first_entry(&hub_data->events_head.list, - struct sensorhub_event, list); - if (IS_ERR(hub_data->first_event)) { - pr_err("%s: first event err(%ld)", __func__, - PTR_ERR(hub_data->first_event)); - continue; - } - - /* report sensorhub event to user */ - ssp_report_sensorhub_length(hub_data, - hub_data->first_event->length); - wake_lock_timeout(&hub_data->sensorhub_wake_lock, 5*HZ); - hub_data->transfer_ready++; - } - - /* wait until user gets data */ - ret = wait_for_completion_timeout(&hub_data->transfer_done, - 3*HZ); - if (ret == 0) { - pr_err("%s: wait timed out", __func__); - hub_data->transfer_ready = 0; - } else if (ret < 0) { - pr_err("%s: wait_for_completion_timeout err(%d)", - __func__, ret); - } - - /* remove first event only if transfer succeed */ - if (hub_data->transfer_try == 0) { - /* remove first event */ - spin_lock_bh(&hub_data->sensorhub_lock); - if (!list_empty(&hub_data->events_head.list)) - list_del(&hub_data->first_event->list); - hub_data->transfer_ready = 0; - - /* how many events in the list? */ - events = 0; - list_for_each_entry(event, - &hub_data->events_head.list, list) - events++; - spin_unlock_bh(&hub_data->sensorhub_lock); - - pr_info("%s: %d events remain", __func__, events); - continue; - } - - /* throw away extra events */ - if (hub_data->transfer_ready > EVENT_WAIT_COUNT) - hub_data->transfer_ready = 0; - - usleep_range(10000, 10000); - } - - pr_info("%s: exit", __func__); - return ret; -} - -int ssp_handle_sensorhub_data(struct ssp_data *ssp_data, char *dataframe, - int start, int end) -{ - struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; - - /* add new sensorhub event into queue */ - int ret = ssp_queue_sensorhub_events(hub_data, dataframe, start, end); - wake_up(&hub_data->sensorhub_waitqueue); - - return ret; -} - -int ssp_handle_sensorhub_large_data(struct ssp_data *ssp_data, u8 sub_cmd) -{ - struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; - - /* receive large size of library data */ - int ret = ssp_receive_large_msg(hub_data, sub_cmd); - if (ret >= 0) { - ssp_report_sensorhub_length(hub_data, - hub_data->large_library_length); - wake_lock_timeout(&hub_data->sensorhub_wake_lock, 3*HZ); - } else { - pr_err("%s: ssp_receive_large_msg err(%d)", __func__, ret); - } - - return ret; -} - -int ssp_initialize_sensorhub(struct ssp_data *ssp_data) -{ - struct ssp_sensorhub_data *hub_data; - int ret; - - hub_data = kzalloc(sizeof(*hub_data), GFP_KERNEL); - if (!hub_data) { - pr_err("%s: failed to allocate memory for sensorhub data", - __func__); - return -ENOMEM; - } - hub_data->ssp_data = ssp_data; - ssp_data->hub_data = hub_data; - - /* allocate sensorhub input devices */ - hub_data->sensorhub_input_dev = input_allocate_device(); - if (!hub_data->sensorhub_input_dev) { - pr_err("%s: allocate sensorhub input devices err", __func__); - ret = -ENOMEM; - goto err_input_allocate_device_sensorhub; - } - - wake_lock_init(&hub_data->sensorhub_wake_lock, WAKE_LOCK_SUSPEND, - "sensorhub_wake_lock"); - INIT_LIST_HEAD(&hub_data->events_head.list); - init_waitqueue_head(&hub_data->sensorhub_waitqueue); - init_completion(&hub_data->transfer_done); - spin_lock_init(&hub_data->sensorhub_lock); - - ret = input_register_device(hub_data->sensorhub_input_dev); - if (ret < 0) { - pr_err("%s: could not register sensorhub input device(%d)", - __func__, ret); - input_free_device(hub_data->sensorhub_input_dev); - goto err_input_register_device_sensorhub; - } - - hub_data->sensorhub_input_dev->name = "ssp_context"; - input_set_drvdata(hub_data->sensorhub_input_dev, hub_data); - input_set_capability(hub_data->sensorhub_input_dev, EV_REL, REL_RX); - input_set_capability(hub_data->sensorhub_input_dev, EV_REL, REL_RY); - - /* create sensorhub device node */ - hub_data->sensorhub_device.minor = MISC_DYNAMIC_MINOR; - hub_data->sensorhub_device.name = "ssp_sensorhub"; - hub_data->sensorhub_device.fops = &ssp_sensorhub_fops; - - ret = misc_register(&hub_data->sensorhub_device); - if (ret < 0) { - pr_err("%s: misc_register() failed", __func__); - goto err_misc_register; - } - - hub_data->sensorhub_task = kthread_run(ssp_senosrhub_thread_func, - (void *)hub_data, "ssp_sensorhub_task"); - if (IS_ERR(hub_data->sensorhub_task)) { - ret = PTR_ERR(hub_data->sensorhub_task); - goto err_kthread_create; - } - - return 0; - -err_kthread_create: - misc_deregister(&hub_data->sensorhub_device); -err_misc_register: - input_unregister_device(hub_data->sensorhub_input_dev); -err_input_register_device_sensorhub: - complete_all(&hub_data->transfer_done); - wake_lock_destroy(&hub_data->sensorhub_wake_lock); -err_input_allocate_device_sensorhub: - kfree(hub_data); - return ret; -} - -void ssp_remove_sensorhub(struct ssp_data *ssp_data) -{ - struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; - - ssp_sensorhub_fops.write = NULL; - ssp_sensorhub_fops.unlocked_ioctl = NULL; - misc_deregister(&hub_data->sensorhub_device); - input_unregister_device(hub_data->sensorhub_input_dev); - wake_lock_destroy(&hub_data->sensorhub_wake_lock); - complete_all(&hub_data->transfer_done); - if (hub_data->sensorhub_task) - kthread_stop(hub_data->sensorhub_task); - kfree(hub_data); -} - -MODULE_DESCRIPTION("Samsung Sensor Platform(SSP) sensorhub driver"); -MODULE_AUTHOR("Samsung Electronics"); -MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/ssp_sensorhub.h b/drivers/sensorhub/ssp_sensorhub.h deleted file mode 100644 index 4ececf6b6ec..00000000000 --- a/drivers/sensorhub/ssp_sensorhub.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __SSP_SENSORHUB__ -#define __SSP_SENSORHUB__ - -#include -#include -#include -#include -#include "ssp.h" - -#define SUBCMD_GPIOWAKEUP 0X02 -#define SUBCMD_POWEREUP 0X04 -#define LIBRARY_MAX_NUM 5 -#define LIBRARY_MAX_TRY 32 -#define EVENT_WAIT_COUNT 3 - -/* sensorhub ioctl command */ -#define SENSORHUB_IOCTL_MAGIC 'S' -#define IOCTL_READ_CONTEXT_DATA _IOR(SENSORHUB_IOCTL_MAGIC, 3, char *) - - -struct sensorhub_event { - char *library_data; - int length; - struct list_head list; -}; - -struct ssp_sensorhub_data { - struct ssp_data *ssp_data; - struct input_dev *sensorhub_input_dev; - struct miscdevice sensorhub_device; - struct wake_lock sensorhub_wake_lock; - struct completion transfer_done; - struct task_struct *sensorhub_task; - struct sensorhub_event events_head; - struct sensorhub_event events[LIBRARY_MAX_NUM + 1]; - struct sensorhub_event *first_event; - int event_number; - int transfer_try; - int transfer_ready; - int large_library_length; - char *large_library_data; - wait_queue_head_t sensorhub_waitqueue; - spinlock_t sensorhub_lock; -}; - -void ssp_report_sensorhub_notice(struct ssp_data *data, char notice); -int ssp_handle_sensorhub_data(struct ssp_data *data, char *dataframe, - int start, int end); -int ssp_handle_sensorhub_large_data(struct ssp_data *data, u8 sub_cmd); -int ssp_initialize_sensorhub(struct ssp_data *data); -void ssp_remove_sensorhub(struct ssp_data *data); - -#endif diff --git a/drivers/sensorhub/ssp_sysfs.c b/drivers/sensorhub/ssp_sysfs.c deleted file mode 100644 index 1bc7f178d68..00000000000 --- a/drivers/sensorhub/ssp_sysfs.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#include "ssp.h" - -/*************************************************************************/ -/* SSP data delay function */ -/*************************************************************************/ - -unsigned int get_msdelay(int64_t dDelayRate) -{ - if (dDelayRate <= SENSOR_NS_DELAY_FASTEST) - return SENSOR_MS_DELAY_FASTEST; - else if (dDelayRate <= SENSOR_NS_DELAY_GAME) - return SENSOR_MS_DELAY_GAME; - else if (dDelayRate <= SENSOR_NS_DELAY_UI) - return SENSOR_MS_DELAY_UI; - else - return SENSOR_MS_DELAY_NORMAL; -} - -unsigned int get_delay_cmd(u8 uDelayRate) -{ - if (uDelayRate <= SENSOR_MS_DELAY_FASTEST) - return SENSOR_CMD_DELAY_FASTEST; - else if (uDelayRate <= SENSOR_MS_DELAY_GAME) - return SENSOR_CMD_DELAY_GAME; - else if (uDelayRate <= SENSOR_MS_DELAY_UI) - return SENSOR_CMD_DELAY_UI; - else - return SENSOR_CMD_DELAY_NORMAL; -} - -static void change_sensor_delay(struct ssp_data *data, - int iSensorType, int64_t dNewDelay) -{ - u8 uBuf[2]; - unsigned int uNewEnable = 0; - int64_t dTempDelay = data->adDelayBuf[iSensorType]; - - if (!(atomic_read(&data->aSensorEnable) & (1 << iSensorType))) { - data->aiCheckStatus[iSensorType] = NO_SENSOR_STATE; - return; - } - - data->adDelayBuf[iSensorType] = dNewDelay; - - if (iSensorType == ORIENTATION_SENSOR) - iSensorType = ACCELEROMETER_SENSOR; - - switch (data->aiCheckStatus[iSensorType]) { - case ADD_SENSOR_STATE: - ssp_dbg("[SSP]: %s - add %u, New = %lldns\n", - __func__, 1 << iSensorType, dNewDelay); - - uBuf[1] = (u8)get_msdelay(dNewDelay); - uBuf[0] = (u8)get_delay_cmd(uBuf[1]); - - if (send_instruction(data, ADD_SENSOR, iSensorType, uBuf, 2) - != SUCCESS) { - uNewEnable = - (unsigned int)atomic_read(&data->aSensorEnable) - & (~(unsigned int)(1 << iSensorType)); - atomic_set(&data->aSensorEnable, uNewEnable); - - data->aiCheckStatus[iSensorType] = NO_SENSOR_STATE; - data->uMissSensorCnt++; - break; - } - - data->aiCheckStatus[iSensorType] = RUNNING_SENSOR_STATE; - - if (iSensorType == PROXIMITY_SENSOR) { - proximity_open_lcd_ldi(data); - proximity_open_calibration(data); - - input_report_abs(data->prox_input_dev, ABS_DISTANCE, 1); - input_sync(data->prox_input_dev); - } - break; - case RUNNING_SENSOR_STATE: - if (get_msdelay(dTempDelay) - == get_msdelay(data->adDelayBuf[iSensorType])) - break; - - ssp_dbg("[SSP]: %s - Change %u, New = %lldns\n", - __func__, 1 << iSensorType, dNewDelay); - - uBuf[1] = (u8)get_msdelay(dNewDelay); - uBuf[0] = (u8)get_delay_cmd(uBuf[1]); - send_instruction(data, CHANGE_DELAY, iSensorType, uBuf, 2); - - break; - default: - break; - } -} - -/*************************************************************************/ -/* SSP data enable function */ -/*************************************************************************/ - -static int ssp_add_sensor(struct ssp_data *data, unsigned int uChangedSensor) -{ - if ((data->aiCheckStatus[uChangedSensor] != INITIALIZATION_STATE) - && (!atomic_read(&data->aSensorEnable))) { - if (data->bCheckSuspend == false) - data->bDebugEnabled = true; - } - - return 0; -} - -static int ssp_remove_sensor(struct ssp_data *data, - unsigned int uChangedSensor, unsigned int uNewEnable) -{ - u8 uBuf[2]; - int64_t dSensorDelay = data->adDelayBuf[uChangedSensor]; - - ssp_dbg("[SSP]: %s - remove sensor = %d, current state = %d\n", - __func__, (1 << uChangedSensor), uNewEnable); - - data->adDelayBuf[uChangedSensor] = DEFUALT_POLLING_DELAY; - - if (uChangedSensor == ORIENTATION_SENSOR) { - if (!(atomic_read(&data->aSensorEnable) - & (1 << ACCELEROMETER_SENSOR))) { - uChangedSensor = ACCELEROMETER_SENSOR; - } else { - change_sensor_delay(data, ACCELEROMETER_SENSOR, - data->adDelayBuf[ACCELEROMETER_SENSOR]); - return 0; - } - } else if (uChangedSensor == ACCELEROMETER_SENSOR) { - if (atomic_read(&data->aSensorEnable) - & (1 << ORIENTATION_SENSOR)) { - change_sensor_delay(data, ORIENTATION_SENSOR, - data->adDelayBuf[ORIENTATION_SENSOR]); - return 0; - } - } - - if (!uNewEnable) { - if (data->bCheckSuspend == false) - data->bDebugEnabled = false; - } - - if (atomic_read(&data->aSensorEnable) & (1 << uChangedSensor)) { - uBuf[1] = (u8)get_msdelay(dSensorDelay); - uBuf[0] = (u8)get_delay_cmd(uBuf[1]); - - send_instruction(data, REMOVE_SENSOR, uChangedSensor, uBuf, 2); - } - data->aiCheckStatus[uChangedSensor] = NO_SENSOR_STATE; - return 0; -} - -/*************************************************************************/ -/* ssp Sysfs */ -/*************************************************************************/ - -static ssize_t show_sensors_enable(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - ssp_dbg("[SSP]: %s - cur_enable = %d\n", __func__, - atomic_read(&data->aSensorEnable)); - - return sprintf(buf, "%9u\n", atomic_read(&data->aSensorEnable)); -} - -static ssize_t set_sensors_enable(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int64_t dTemp; - unsigned int uNewEnable = 0, uChangedSensor = 0; - struct ssp_data *data = dev_get_drvdata(dev); - int iRet; - - if (strict_strtoll(buf, 10, &dTemp) < 0) - return -1; - - uNewEnable = (unsigned int)dTemp; - ssp_dbg("[SSP]: %s - new_enable = %u, old_enable = %u\n", __func__, - uNewEnable, atomic_read(&data->aSensorEnable)); - - if (uNewEnable == atomic_read(&data->aSensorEnable)) - return 0; - - for (uChangedSensor = 0; uChangedSensor < SENSOR_MAX; uChangedSensor++) - if ((atomic_read(&data->aSensorEnable) & (1 << uChangedSensor)) - != (uNewEnable & (1 << uChangedSensor))) { - - if (!(uNewEnable & (1 << uChangedSensor))) - ssp_remove_sensor(data, uChangedSensor, - uNewEnable); /* disable */ - else { /* Change to ADD_SENSOR_STATE from KitKat */ - if (data->aiCheckStatus[uChangedSensor] == INITIALIZATION_STATE) { - if (uChangedSensor == ACCELEROMETER_SENSOR) - accel_open_calibration(data); - else if (uChangedSensor == GYROSCOPE_SENSOR) - gyro_open_calibration(data); - else if (uChangedSensor == PRESSURE_SENSOR) - pressure_open_calibration(data); - else if (uChangedSensor == PROXIMITY_SENSOR) { - proximity_open_lcd_ldi(data); - proximity_open_calibration(data); - } - } - data->aiCheckStatus[uChangedSensor] = ADD_SENSOR_STATE; - } - break; - } - - atomic_set(&data->aSensorEnable, uNewEnable); - - return size; -} - -static ssize_t show_acc_delay(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%lld\n", data->adDelayBuf[ACCELEROMETER_SENSOR]); -} - -static ssize_t set_acc_delay(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int64_t dNewDelay; - struct ssp_data *data = dev_get_drvdata(dev); - - if (strict_strtoll(buf, 10, &dNewDelay) < 0) - return -1; - - if ((atomic_read(&data->aSensorEnable) & (1 << ORIENTATION_SENSOR)) && - (data->adDelayBuf[ORIENTATION_SENSOR] < dNewDelay)) - data->adDelayBuf[ACCELEROMETER_SENSOR] = dNewDelay; - else - change_sensor_delay(data, ACCELEROMETER_SENSOR, dNewDelay); - - return size; -} - -static ssize_t show_ori_delay(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%lld\n", data->adDelayBuf[ORIENTATION_SENSOR]); -} - -static ssize_t set_ori_delay(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int64_t dNewDelay; - struct ssp_data *data = dev_get_drvdata(dev); - - if (strict_strtoll(buf, 10, &dNewDelay) < 0) - return -1; - - if (data->aiCheckStatus[ACCELEROMETER_SENSOR] == NO_SENSOR_STATE) { - data->aiCheckStatus[ACCELEROMETER_SENSOR] = ADD_SENSOR_STATE; - change_sensor_delay(data, ORIENTATION_SENSOR, dNewDelay); - } else if (data->aiCheckStatus[ACCELEROMETER_SENSOR] == - RUNNING_SENSOR_STATE) { - if (dNewDelay < data->adDelayBuf[ACCELEROMETER_SENSOR]) - change_sensor_delay(data, - ORIENTATION_SENSOR, dNewDelay); - else - data->adDelayBuf[ORIENTATION_SENSOR] = dNewDelay; - } - return size; -} - -static ssize_t show_gyro_delay(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%lld\n", data->adDelayBuf[GYROSCOPE_SENSOR]); -} - -static ssize_t set_gyro_delay(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int64_t dNewDelay; - struct ssp_data *data = dev_get_drvdata(dev); - - if (strict_strtoll(buf, 10, &dNewDelay) < 0) - return -1; - - change_sensor_delay(data, GYROSCOPE_SENSOR, dNewDelay); - return size; -} - -static ssize_t show_mag_delay(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%lld\n", data->adDelayBuf[GEOMAGNETIC_SENSOR]); -} - -static ssize_t set_mag_delay(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int64_t dNewDelay; - struct ssp_data *data = dev_get_drvdata(dev); - - if (strict_strtoll(buf, 10, &dNewDelay) < 0) - return -1; - - change_sensor_delay(data, GEOMAGNETIC_SENSOR, dNewDelay); - - return size; -} - -static ssize_t show_pressure_delay(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%lld\n", data->adDelayBuf[PRESSURE_SENSOR]); -} - -static ssize_t set_pressure_delay(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int64_t dNewDelay; - struct ssp_data *data = dev_get_drvdata(dev); - - if (strict_strtoll(buf, 10, &dNewDelay) < 0) - return -1; - - change_sensor_delay(data, PRESSURE_SENSOR, dNewDelay); - return size; -} - -static ssize_t show_light_delay(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%lld\n", data->adDelayBuf[LIGHT_SENSOR]); -} - -static ssize_t set_light_delay(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int64_t dNewDelay; - struct ssp_data *data = dev_get_drvdata(dev); - - if (strict_strtoll(buf, 10, &dNewDelay) < 0) - return -1; - - change_sensor_delay(data, LIGHT_SENSOR, dNewDelay); - return size; -} - -static ssize_t show_prox_delay(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - return sprintf(buf, "%lld\n", data->adDelayBuf[PROXIMITY_SENSOR]); -} - -static ssize_t set_prox_delay(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - int64_t dNewDelay; - struct ssp_data *data = dev_get_drvdata(dev); - - if (strict_strtoll(buf, 10, &dNewDelay) < 0) - return -1; - - change_sensor_delay(data, PROXIMITY_SENSOR, dNewDelay); - return size; -} - -static DEVICE_ATTR(mcu_rev, S_IRUGO, mcu_revision_show, NULL); -static DEVICE_ATTR(mcu_name, S_IRUGO, mcu_model_name_show, NULL); -static DEVICE_ATTR(mcu_update, S_IRUGO, mcu_update_show, NULL); -static DEVICE_ATTR(mcu_update2, S_IRUGO, mcu_update2_show, NULL); -static DEVICE_ATTR(mcu_reset, S_IRUGO, mcu_reset_show, NULL); - -static DEVICE_ATTR(mcu_test, S_IRUGO | S_IWUSR | S_IWGRP, - mcu_factorytest_show, mcu_factorytest_store); -static DEVICE_ATTR(mcu_sleep_test, S_IRUGO | S_IWUSR | S_IWGRP, - mcu_sleep_factorytest_show, mcu_sleep_factorytest_store); -static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, - show_sensors_enable, set_sensors_enable); -static DEVICE_ATTR(acc_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, - show_acc_delay, set_acc_delay); -static DEVICE_ATTR(gyro_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, - show_gyro_delay, set_gyro_delay); -static DEVICE_ATTR(mag_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, - show_mag_delay, set_mag_delay); -static DEVICE_ATTR(ori_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, - show_ori_delay, set_ori_delay); -static DEVICE_ATTR(pressure_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, - show_pressure_delay, set_pressure_delay); -static DEVICE_ATTR(light_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, - show_light_delay, set_light_delay); -static DEVICE_ATTR(prox_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, - show_prox_delay, set_prox_delay); - -static struct device_attribute *mcu_attrs[] = { - &dev_attr_enable, - &dev_attr_mcu_rev, - &dev_attr_mcu_name, - &dev_attr_mcu_test, - &dev_attr_mcu_reset, - &dev_attr_mcu_update, - &dev_attr_mcu_update2, - &dev_attr_mcu_sleep_test, - &dev_attr_mag_poll_delay, - &dev_attr_ori_poll_delay, - NULL, -}; - -static void initialize_mcu_factorytest(struct ssp_data *data) -{ - sensors_register(data->mcu_device, data, mcu_attrs, "ssp_sensor"); -} - -static void remove_mcu_factorytest(struct ssp_data *data) -{ - sensors_unregister(data->mcu_device, mcu_attrs); -} - -int initialize_sysfs(struct ssp_data *data) -{ - if (device_create_file(&data->acc_input_dev->dev, - &dev_attr_acc_poll_delay)) - goto err_acc_input_dev; - - if (device_create_file(&data->gyro_input_dev->dev, - &dev_attr_gyro_poll_delay)) - goto err_gyro_input_dev; - - if (device_create_file(&data->pressure_input_dev->dev, - &dev_attr_pressure_poll_delay)) - goto err_pressure_input_dev; - - if (device_create_file(&data->light_input_dev->dev, - &dev_attr_light_poll_delay)) - goto err_light_input_dev; - - if (device_create_file(&data->prox_input_dev->dev, - &dev_attr_prox_poll_delay)) - goto err_prox_input_dev; - - initialize_accel_factorytest(data); - initialize_gyro_factorytest(data); - initialize_prox_factorytest(data); - initialize_light_factorytest(data); - initialize_pressure_factorytest(data); - initialize_magnetic_factorytest(data); - initialize_mcu_factorytest(data); - - return SUCCESS; - -err_prox_input_dev: - device_remove_file(&data->light_input_dev->dev, - &dev_attr_light_poll_delay); -err_light_input_dev: - device_remove_file(&data->pressure_input_dev->dev, - &dev_attr_pressure_poll_delay); -err_pressure_input_dev: - device_remove_file(&data->gyro_input_dev->dev, - &dev_attr_gyro_poll_delay); -err_gyro_input_dev: - device_remove_file(&data->acc_input_dev->dev, - &dev_attr_acc_poll_delay); -err_acc_input_dev: - return ERROR; -} - -void remove_sysfs(struct ssp_data *data) -{ - device_remove_file(&data->acc_input_dev->dev, - &dev_attr_acc_poll_delay); - device_remove_file(&data->gyro_input_dev->dev, - &dev_attr_gyro_poll_delay); - device_remove_file(&data->pressure_input_dev->dev, - &dev_attr_pressure_poll_delay); - device_remove_file(&data->light_input_dev->dev, - &dev_attr_light_poll_delay); - device_remove_file(&data->prox_input_dev->dev, - &dev_attr_prox_poll_delay); - - remove_accel_factorytest(data); - remove_gyro_factorytest(data); - remove_prox_factorytest(data); - remove_light_factorytest(data); - remove_pressure_factorytest(data); - remove_magnetic_factorytest(data); - remove_mcu_factorytest(data); - destroy_sensor_class(); -} diff --git a/drivers/sensorhub/stm/Kconfig b/drivers/sensorhub/stm/Kconfig new file mode 100755 index 00000000000..6eab263d9e4 --- /dev/null +++ b/drivers/sensorhub/stm/Kconfig @@ -0,0 +1,142 @@ +# +# sensor drivers configuration +# +config SENSORS_SYSFS + tristate "Sensors sysfs" + help + Support sysfs for sensors. + If you say yes here you get sysfs support for + sensor factory test. + To compile this driver as a module, choose M here: the + module will be called sensors_core. + +config SENSORS_SSP + tristate "Sensors ssp" + default n + depends on SPI + help + ssp driver for sensor hub. + If you say yes here you get ssp support for + sensor hub. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_STM + tristate "Sensors ssp stm" + default n + depends on SPI + help + ssp driver for sensor hub. + If you say yes here you get ssp support for + sensor hub. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_MPU6500 + tristate "Sensors ssp mpu6500" + default n + depends on SPI + help + mpu6500 file for factory test in ssp driver. + If you say yes here you get mpu6500 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_YAS532 + tristate "Sensors ssp yas532" + default n + depends on SPI + help + yas532 file for factory test in ssp driver. + If you say yes here you get yas532 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_CM3320 + tristate "Sensors ssp cm3320" + default n + depends on SPI + help + cm3320 file for factory test in ssp driver. + If you say yes here you get cm3320 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_MAX88920 + tristate "Sensors ssp max88920" + default n + depends on SPI + help + max88920 file for factory test in ssp driver. + If you say yes here you get max88920 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_BMP182 + tristate "Sensors ssp bmp182" + default n + depends on SPI + help + bmp182 file for factory test in ssp driver. + If you say yes here you get bmp182 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_SHTC1 + tristate "Sensors ssp shtc1" + default n + depends on SPI + help + shtc1 file for factory test in ssp driver. + If you say yes here you get shtc1 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_SHTC1_VER + string "Sensors shtc1 version name" + default "No_Version_Name" + depends on SENSORS_SSP_SHTC1 + help + shtc1 version for temphumid factory test in ssp driver. + If you give version name here you get shtc1 version for + lcd test. + +config SENSORS_SSP_ATUC128L5HAR + tristate "Sensors ssp atuc128l5har" + default n + depends on SPI + help + atuc128l5har file for factory test in ssp driver. + If you say yes here you get atuc128l5har support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_STM32F401 + tristate "Sensors ssp stm32f401" + default n + depends on SPI + help + stm32f401 file for factory test in ssp driver. + If you say yes here you get stm32f401 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_SENSORHUB + tristate "Sensors ssp sensorhub" + default n + depends on SPI + help + ssp sensor hub driver for sensor hub. + If you say yes here you get ssp support for + sensor hub. + To compile this driver as a module, choose M here: the + module will be called ssp. + diff --git a/drivers/sensorhub/stm/Makefile b/drivers/sensorhub/stm/Makefile new file mode 100755 index 00000000000..9e7f81fd6ee --- /dev/null +++ b/drivers/sensorhub/stm/Makefile @@ -0,0 +1,23 @@ +# +# Makefile for the sensor drivers. +# + +# Each configuration option enables a list of files. +obj-$(CONFIG_SENSORS_SSP_STM) += ssp_dev.o ssp_comm.o ssp_data.o ssp_sysfs.o\ + ssp_input.o ssp_firmware.o ssp_debug.o ssp_spi.o +obj-$(CONFIG_SENSORS_SYSFS) += sensors_core.o + +obj-$(CONFIG_SENSORS_SSP_MPU6500) += factory/accel_mpu6500.o factory/gyro_mpu6500.o + +obj-$(CONFIG_SENSORS_SSP_CM3320) += factory/light_cm3320.o +obj-$(CONFIG_SENSORS_SSP_MAX88920) += factory/prox_max88920.o factory/gesture_max88920.o + +obj-$(CONFIG_SENSORS_SSP_YAS532) += factory/magnetic_yas532.o + +obj-$(CONFIG_SENSORS_SSP_BMP182) += factory/pressure_bmp182.o +obj-$(CONFIG_SENSORS_SSP_SHTC1) += factory/temphumidity_shtc1.o + +obj-$(CONFIG_SENSORS_SSP_ATUC128L5HAR) += factory/mcu_atuc128l5har.o +obj-$(CONFIG_SENSORS_SSP_STM32F401) += factory/mcu_stm32f401.o + +obj-$(CONFIG_SENSORS_SSP_SENSORHUB) += ssp_sensorhub.o diff --git a/drivers/sensorhub/stm/factory/accel_mpu6500.c b/drivers/sensorhub/stm/factory/accel_mpu6500.c new file mode 100755 index 00000000000..b5deb5101a1 --- /dev/null +++ b/drivers/sensorhub/stm/factory/accel_mpu6500.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "INVENSENSE" +#define CHIP_ID "MPU6500" + +#define CALIBRATION_FILE_PATH "/efs/calibration_data" +#define CALIBRATION_DATA_AMOUNT 20 + +static ssize_t accel_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t accel_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +int accel_open_calibration(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + + return iRet; + } + + iRet = cal_filp->f_op->read(cal_filp, (char *)&data->accelcal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) + iRet = -EIO; + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + ssp_dbg("[SSP]: open accel calibration %d, %d, %d\n", + data->accelcal.x, data->accelcal.y, data->accelcal.z); + + if ((data->accelcal.x == 0) && (data->accelcal.y == 0) + && (data->accelcal.z == 0)) + return ERROR; + + return iRet; +} + +static int enable_accel_for_cal(struct ssp_data *data) +{ + u8 uBuf[2] = {0, 10}; + + if (atomic_read(&data->aSensorEnable) & (1 << ACCELEROMETER_SENSOR)) { + if (get_msdelay(data->adDelayBuf[ACCELEROMETER_SENSOR]) != 10) { + send_instruction(data, CHANGE_DELAY, + ACCELEROMETER_SENSOR, uBuf, 2); + return SUCCESS; + } + } else { + send_instruction(data, ADD_SENSOR, + ACCELEROMETER_SENSOR, uBuf, 2); + } + + return FAIL; +} + +static void disable_accel_for_cal(struct ssp_data *data, int iDelayChanged) +{ + u8 uBuf[2] = {0, 10}; + + if (atomic_read(&data->aSensorEnable) & (1 << ACCELEROMETER_SENSOR)) { + uBuf[1] = get_msdelay(data->adDelayBuf[ACCELEROMETER_SENSOR]); + uBuf[0] = get_delay_cmd(uBuf[1]); + if (iDelayChanged) + send_instruction(data, CHANGE_DELAY, + ACCELEROMETER_SENSOR, uBuf, 2); + } else { + send_instruction(data, REMOVE_SENSOR, + ACCELEROMETER_SENSOR, uBuf, 2); + } +} + +static int accel_do_calibrate(struct ssp_data *data, int iEnable) +{ + int iSum[3] = { 0, }; + int iRet = 0, iCount; + struct file *cal_filp = NULL; + mm_segment_t old_fs; + + if (iEnable) { + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + + iRet = enable_accel_for_cal(data); + msleep(300); + + for (iCount = 0; iCount < CALIBRATION_DATA_AMOUNT; iCount++) { + iSum[0] += data->buf[ACCELEROMETER_SENSOR].x; + iSum[1] += data->buf[ACCELEROMETER_SENSOR].y; + iSum[2] += data->buf[ACCELEROMETER_SENSOR].z; + mdelay(10); + } + disable_accel_for_cal(data, iRet); + + data->accelcal.x = (iSum[0] / CALIBRATION_DATA_AMOUNT); + data->accelcal.y = (iSum[1] / CALIBRATION_DATA_AMOUNT); + data->accelcal.z = (iSum[2] / CALIBRATION_DATA_AMOUNT); + + if (data->accelcal.z > 0) + data->accelcal.z -= MAX_ACCEL_1G; + else if (data->accelcal.z < 0) + data->accelcal.z += MAX_ACCEL_1G; + } else { + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + } + + ssp_dbg("[SSP]: do accel calibrate %d, %d, %d\n", + data->accelcal.x, data->accelcal.y, data->accelcal.z); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[SSP]: %s - Can't open calibration file\n", __func__); + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + return iRet; + } + + iRet = cal_filp->f_op->write(cal_filp, (char *)&data->accelcal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) { + pr_err("[SSP]: %s - Can't write the accelcal to file\n", + __func__); + iRet = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return iRet; +} + +static ssize_t accel_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int iRet; + int iCount = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = accel_open_calibration(data); + if (iRet < 0) + pr_err("[SSP]: %s - calibration open failed(%d)\n", __func__, iRet); + + ssp_dbg("[SSP] Cal data : %d %d %d - %d\n", + data->accelcal.x, data->accelcal.y, data->accelcal.z, iRet); + + iCount = sprintf(buf, "%d %d %d %d\n", iRet, data->accelcal.x, + data->accelcal.y, data->accelcal.z); + return iCount; +} + +static ssize_t accel_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int iRet; + int64_t dEnable; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtoll(buf, 10, &dEnable); + if (iRet < 0) + return iRet; + + iRet = accel_do_calibrate(data, (int)dEnable); + if (iRet < 0) + pr_err("[SSP]: %s - accel_do_calibrate() failed\n", __func__); + + return size; +} + +static ssize_t raw_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", + data->buf[ACCELEROMETER_SENSOR].x, + data->buf[ACCELEROMETER_SENSOR].y, + data->buf[ACCELEROMETER_SENSOR].z); +} + +static ssize_t accel_reactive_alert_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + char chTempBuf[2] = {0, 10}; + int iRet, iDelayCnt = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "1")) + ssp_dbg("[SSP]: %s - on\n", __func__); + else if (sysfs_streq(buf, "0")) + ssp_dbg("[SSP]: %s - off\n", __func__); + else if (sysfs_streq(buf, "2")) { + ssp_dbg("[SSP]: %s - factory\n", __func__); + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + data->bAccelAlert = false; + iRet = send_instruction(data, FACTORY_MODE, + ACCELEROMETER_FACTORY, chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << ACCELEROMETER_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - accel Selftest Timeout!!\n", + __func__); + goto exit; + } + + mdelay(5); + + data->bAccelAlert = data->uFactorydata[0]; + ssp_dbg("[SSP]: %s factory test success!\n", __func__); + } else { + pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } +exit: + return size; +} + +static ssize_t accel_reactive_alert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->bAccelAlert == true) + bSuccess = true; + else + bSuccess = false; + + data->bAccelAlert = false; + return sprintf(buf, "%u\n", bSuccess); +} + +static DEVICE_ATTR(name, S_IRUGO, accel_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, accel_vendor_show, NULL); +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, + accel_calibration_show, accel_calibration_store); +static DEVICE_ATTR(raw_data, S_IRUGO, raw_data_read, NULL); +static DEVICE_ATTR(reactive_alert, S_IRUGO | S_IWUSR | S_IWGRP, + accel_reactive_alert_show, accel_reactive_alert_store); + +static struct device_attribute *acc_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_calibration, + &dev_attr_raw_data, + &dev_attr_reactive_alert, + NULL, +}; + +void initialize_accel_factorytest(struct ssp_data *data) +{ + sensors_register(data->acc_device, data, acc_attrs, + "accelerometer_sensor"); +} + +void remove_accel_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->acc_device, acc_attrs); +} diff --git a/drivers/sensorhub/stm/factory/gesture_max88920.c b/drivers/sensorhub/stm/factory/gesture_max88920.c new file mode 100755 index 00000000000..5205c3579dd --- /dev/null +++ b/drivers/sensorhub/stm/factory/gesture_max88920.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" + +#define VENDOR "MAXIM" +#define CHIP_ID "MAX88920" + +static ssize_t gestrue_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR); +} + +static ssize_t gestrue_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID); +} + +static ssize_t raw_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n", + data->buf[GESTURE_SENSOR].data[0], + data->buf[GESTURE_SENSOR].data[1], + data->buf[GESTURE_SENSOR].data[2], + data->buf[GESTURE_SENSOR].data[3]); +} + +static ssize_t gesture_get_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 raw_A = 0, raw_B = 0, raw_C = 0, raw_D = 0; + int iDelayCnt = 0, iRet = 0; + char chTempBuf[2] = { 0, 10 }; + struct ssp_data *data = dev_get_drvdata(dev); + + iDelayCnt = 0; + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GESTURE_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GESTURE_FACTORY)) + && (iDelayCnt++ < 100) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 100) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Gesture Selftest Timeout!!\n", __func__); + goto exit; + } + + raw_A = data->uFactorydata[0]; + raw_B = data->uFactorydata[1]; + raw_C = data->uFactorydata[2]; + raw_D = data->uFactorydata[3]; + + pr_info("[SSP] %s: self test A = %d, B = %d, C = %d, D = %d\n", + __func__, raw_A, raw_B, raw_C, raw_D); + +exit: + return sprintf(buf, "%d,%d,%d,%d\n", + raw_A, raw_B, raw_C, raw_D); +} + +static ssize_t ir_current_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - Ir_Current Setting = %d\n", + __func__, data->uIr_Current); + + return sprintf(buf, "%d\n", data->uIr_Current); +} + +static ssize_t ir_current_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u16 uNewIrCurrent = DEFUALT_IR_CURRENT; + int iRet = 0; + u16 current_index = 0; + struct ssp_data *data = dev_get_drvdata(dev); + static u16 set_current[2][16] = { {0, 25, 50, 75, 100, 125, 150, 175, 225, 250, 275, 300, 325, 350, 375, 400}, + {2, 28, 34, 50, 66, 82, 98, 114, 130, 146, 162, 178, 194, 210, 226, 242} }; + + iRet = kstrtou16(buf, 10, &uNewIrCurrent); + if (iRet < 0) + pr_err("[SSP]: %s - kstrtoint failed.(%d)\n", __func__, iRet); + else { + for(current_index = 0; current_index < 16; current_index++) { + if (set_current[0][current_index] == uNewIrCurrent) { + data->uIr_Current = set_current[1][current_index]; + } + } + set_gesture_current(data, data->uIr_Current); + data->uIr_Current = uNewIrCurrent; + } + + ssp_dbg("[SSP]: %s - new Ir_Current Setting : %d\n", + __func__, data->uIr_Current); + + return size; +} + +static DEVICE_ATTR(vendor, S_IRUGO, gestrue_vendor_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, gestrue_name_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, raw_data_read, NULL); +static DEVICE_ATTR(selftest, S_IRUGO, gesture_get_selftest_show, NULL); +static DEVICE_ATTR(ir_current, S_IRUGO | S_IWUSR | S_IWGRP, + ir_current_show, ir_current_store); + +static struct device_attribute *gesture_attrs[] = { + &dev_attr_vendor, + &dev_attr_name, + &dev_attr_raw_data, + &dev_attr_selftest, + &dev_attr_ir_current, + NULL, +}; + +void initialize_gesture_factorytest(struct ssp_data *data) +{ + sensors_register(data->ges_device, data, + gesture_attrs, "gesture_sensor"); +} + +void remove_gesture_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->ges_device, gesture_attrs); +} diff --git a/drivers/sensorhub/stm/factory/gyro_mpu6500.c b/drivers/sensorhub/stm/factory/gyro_mpu6500.c new file mode 100755 index 00000000000..ea0391e1f81 --- /dev/null +++ b/drivers/sensorhub/stm/factory/gyro_mpu6500.c @@ -0,0 +1,674 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include "../ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "INVENSENSE" +#define CHIP_ID "MPU6500" + +#define CALIBRATION_FILE_PATH "/efs/gyro_cal_data" +#define VERBOSE_OUT 1 +#define CALIBRATION_DATA_AMOUNT 20 +#define DEF_GYRO_FULLSCALE 2000 +#define DEF_GYRO_SENS (32768 / DEF_GYRO_FULLSCALE) +#define DEF_BIAS_LSB_THRESH_SELF (20 * DEF_GYRO_SENS) +#define DEF_BIAS_LSB_THRESH_SELF_6500 (30 * DEF_GYRO_SENS) +#define DEF_RMS_LSB_TH_SELF (5 * DEF_GYRO_SENS) +#define DEF_RMS_THRESH ((DEF_RMS_LSB_TH_SELF) * (DEF_RMS_LSB_TH_SELF)) +#define DEF_SCALE_FOR_FLOAT (1000) +#define DEF_RMS_SCALE_FOR_RMS (10000) +#define DEF_SQRT_SCALE_FOR_RMS (100) + +static ssize_t gyro_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t gyro_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +int gyro_open_calibration(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + + data->gyrocal.x = 0; + data->gyrocal.y = 0; + data->gyrocal.z = 0; + + return iRet; + } + + iRet = cal_filp->f_op->read(cal_filp, (char *)&data->gyrocal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) + iRet = -EIO; + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + ssp_dbg("[SSP]: open gyro calibration %d, %d, %d\n", + data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); + return iRet; +} + +static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) +{ + int iRet = 0; + struct file *cal_filp = NULL; + mm_segment_t old_fs; + + data->gyrocal.x = iCalData[0]; + data->gyrocal.y = iCalData[1]; + data->gyrocal.z = iCalData[2]; + + ssp_dbg("[SSP]: do gyro calibrate %d, %d, %d\n", + data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[SSP]: %s - Can't open calibration file\n", __func__); + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + return -EIO; + } + + iRet = cal_filp->f_op->write(cal_filp, (char *)&data->gyrocal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) { + pr_err("[SSP]: %s - Can't write gyro cal to file\n", __func__); + iRet = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return iRet; +} + +static ssize_t gyro_power_off(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssp_dbg("[SSP]: %s\n", __func__); + + return sprintf(buf, "%d\n", 1); +} + +static ssize_t gyro_power_on(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssp_dbg("[SSP]: %s\n", __func__); + + return sprintf(buf, "%d\n", 1); +} + +short mpu6500_gyro_get_temp(struct ssp_data *data) +{ + char chTempBuf[2] = { 0, 10}; + unsigned char reg[2]; + short temperature = 0; + int iDelayCnt = 0, iRet = 0; + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_TEMP_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GYROSCOPE_TEMP_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Gyro Temp Timeout!!\n", __func__); + goto exit; + } + reg[0] = data->uFactorydata[1]; + reg[1] = data->uFactorydata[0]; + temperature = (short) (((reg[0]) << 8) | reg[1]); + temperature = (((temperature + 521) / 340) + 35); + ssp_dbg("[SSP]: %s - %d\n", __func__, temperature); +exit: + return temperature; +} + +char k330_gyro_get_temp(struct ssp_data *data) +{ + char chTempBuf[2] = { 0, 10}, chTemp = 0; + int iDelayCnt = 0, iRet = 0; + + if (!(data->uSensorState & (1 << GYROSCOPE_SENSOR))) + goto exit; + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_TEMP_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GYROSCOPE_TEMP_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Gyro Temp Timeout!!\n", __func__); + goto exit; + } + + mdelay(5); + + chTemp = (char)data->uFactorydata[0]; + ssp_dbg("[SSP]: %s - %d\n", __func__, chTemp); +exit: + return chTemp; +} + +static ssize_t gyro_get_temp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + short temperature = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + temperature = mpu6500_gyro_get_temp(data); + + return sprintf(buf, "%d\n", temperature); +} + +u32 mpu6050_selftest_sqrt(u32 sqsum) +{ + u32 sq_rt; + u32 g0, g1, g2, g3, g4; + u32 seed; + u32 next; + u32 step; + + g4 = sqsum / 100000000; + g3 = (sqsum - g4 * 100000000) / 1000000; + g2 = (sqsum - g4 * 100000000 - g3 * 1000000) / 10000; + g1 = (sqsum - g4 * 100000000 - g3 * 1000000 - g2 * 10000) / 100; + g0 = (sqsum - g4 * 100000000 - g3 * 1000000 - g2 * 10000 - g1 * 100); + + next = g4; + step = 0; + seed = 0; + while (((seed + 1) * (step + 1)) <= next) { + step++; + seed++; + } + + sq_rt = seed * 10000; + next = (next - (seed * step)) * 100 + g3; + + step = 0; + seed = 2 * seed * 10; + while (((seed + 1) * (step + 1)) <= next) { + step++; + seed++; + } + + sq_rt = sq_rt + step * 1000; + next = (next - seed * step) * 100 + g2; + seed = (seed + step) * 10; + step = 0; + while (((seed + 1) * (step + 1)) <= next) { + step++; + seed++; + } + + sq_rt = sq_rt + step * 100; + next = (next - seed * step) * 100 + g1; + seed = (seed + step) * 10; + step = 0; + + while (((seed + 1) * (step + 1)) <= next) { + step++; + seed++; + } + + sq_rt = sq_rt + step * 10; + next = (next - seed * step) * 100 + g0; + seed = (seed + step) * 10; + step = 0; + + while (((seed + 1) * (step + 1)) <= next) { + step++; + seed++; + } + + sq_rt = sq_rt + step; + + return sq_rt; +} + +ssize_t k330_gyro_selftest(char *buf, struct ssp_data *data) +{ + char chTempBuf[2] = { 3, 200}; + u8 uFifoPass = 2; + u8 uBypassPass = 2; + u8 uCalPass = 0; + u8 dummy[2] = {0,}; + s16 iNOST[3] = {0,}, iST[3] = {0,}, iCalData[3] = {0,}; + s16 iZeroRateData[3] = {0,}, fifo_data[4] = {0,}; + int iDelayCnt = 0, iRet = 0; + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GYROSCOPE_FACTORY)) + && (iDelayCnt++ < 250) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 250) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Gyro Selftest Timeout!!\n", __func__); + goto exit; + } + mdelay(5); + + iNOST[0] = (s16)((data->uFactorydata[0] << 8) + data->uFactorydata[1]); + iNOST[1] = (s16)((data->uFactorydata[2] << 8) + data->uFactorydata[3]); + iNOST[2] = (s16)((data->uFactorydata[4] << 8) + data->uFactorydata[5]); + + iST[0] = (s16)((data->uFactorydata[6] << 8) + data->uFactorydata[7]); + iST[1] = (s16)((data->uFactorydata[8] << 8) + data->uFactorydata[9]); + iST[2] = (s16)((data->uFactorydata[10] << 8) + data->uFactorydata[11]); + + iCalData[0] = + (s16)((data->uFactorydata[12] << 8) + data->uFactorydata[13]); + iCalData[1] = + (s16)((data->uFactorydata[14] << 8) + data->uFactorydata[15]); + iCalData[2] = + (s16)((data->uFactorydata[16] << 8) + data->uFactorydata[17]); + + iZeroRateData[0] = + (s16)((data->uFactorydata[18] << 8) + data->uFactorydata[19]); + iZeroRateData[1] = + (s16)((data->uFactorydata[20] << 8) + data->uFactorydata[21]); + iZeroRateData[2] = + (s16)((data->uFactorydata[22] << 8) + data->uFactorydata[23]); + + fifo_data[0] = data->uFactorydata[24]; + fifo_data[1] = + (s16)((data->uFactorydata[25] << 8) + data->uFactorydata[26]); + fifo_data[2] = + (s16)((data->uFactorydata[27] << 8) + data->uFactorydata[28]); + fifo_data[3] = + (s16)((data->uFactorydata[29] << 8) + data->uFactorydata[30]); + + uCalPass = data->uFactorydata[31]; + uFifoPass = data->uFactorydata[32]; + uBypassPass = data->uFactorydata[33]; + dummy[0] = data->uFactorydata[34]; + dummy[1] = data->uFactorydata[35]; + pr_info("[SSP] %s dummy = 0x%X, 0x%X\n", __func__, dummy[0], dummy[1]); + if (uFifoPass && uBypassPass && uCalPass) + save_gyro_caldata(data, iCalData); + +exit: + ssp_dbg("[SSP]: %s - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + __func__, iNOST[0], iNOST[1], iNOST[2], iST[0], iST[1], iST[2], + iZeroRateData[0], iZeroRateData[1], iZeroRateData[2], + fifo_data[0], fifo_data[1], fifo_data[2], fifo_data[3], + uFifoPass & uBypassPass & uCalPass, uFifoPass, uCalPass); + + return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + iNOST[0], iNOST[1], iNOST[2], iST[0], iST[1], iST[2], + iZeroRateData[0], iZeroRateData[1], iZeroRateData[2], + fifo_data[0], fifo_data[1], fifo_data[2], fifo_data[3], + uFifoPass & uBypassPass & uCalPass, uFifoPass, uCalPass); +} + +ssize_t mpu6500_gyro_selftest(char *buf, struct ssp_data *data) +{ + char chTempBuf[2] = { 3, 200}; + u8 initialized = 0; + s8 hw_result = 0; + int i = 0, j = 0, total_count = 0, ret_val = 0; + long avg[3] = {0,}, rms[3] = {0,}; + int gyro_bias[3] = {0,}, gyro_rms[3] = {0,}; + s16 shift_ratio[3] = {0,}; + s16 iCalData[3] = {0,}; + char a_name[3][2] = { "X", "Y", "Z" }; + int iDelayCnt = 0, iRet = 0; + int dps_rms[3] = { 0, }; + u32 temp = 0; + int bias_thresh = DEF_BIAS_LSB_THRESH_SELF_6500; + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GYROSCOPE_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Gyro Selftest Timeout!!\n", __func__); + goto exit; + } + + initialized = data->uFactorydata[0]; + shift_ratio[0] = (s16)((data->uFactorydata[2] << 8) + + data->uFactorydata[1]); + shift_ratio[1] = (s16)((data->uFactorydata[4] << 8) + + data->uFactorydata[3]); + shift_ratio[2] = (s16)((data->uFactorydata[6] << 8) + + data->uFactorydata[5]); + hw_result = (s8)data->uFactorydata[7]; + total_count = (int)((data->uFactorydata[11] << 24) + + (data->uFactorydata[10] << 16) + + (data->uFactorydata[9] << 8) + + data->uFactorydata[8]); + avg[0] = (long)((data->uFactorydata[15] << 24) + + (data->uFactorydata[14] << 16) + + (data->uFactorydata[13] << 8) + + data->uFactorydata[12]); + avg[1] = (long)((data->uFactorydata[19] << 24) + + (data->uFactorydata[18] << 16) + + (data->uFactorydata[17] << 8) + + data->uFactorydata[16]); + avg[2] = (long)((data->uFactorydata[23] << 24) + + (data->uFactorydata[22] << 16) + + (data->uFactorydata[21] << 8) + + data->uFactorydata[20]); + rms[0] = (long)((data->uFactorydata[27] << 24) + + (data->uFactorydata[26] << 16) + + (data->uFactorydata[25] << 8) + + data->uFactorydata[24]); + rms[1] = (long)((data->uFactorydata[31] << 24) + + (data->uFactorydata[30] << 16) + + (data->uFactorydata[29] << 8) + + data->uFactorydata[28]); + rms[2] = (long)((data->uFactorydata[35] << 24) + + (data->uFactorydata[34] << 16) + + (data->uFactorydata[33] << 8) + + data->uFactorydata[32]); + pr_info("[SSP] init: %d, total cnt: %d\n", initialized, total_count); + pr_info("[SSP] hw_result: %d, %d, %d, %d\n", hw_result, + shift_ratio[0], shift_ratio[1], shift_ratio[2]); + pr_info("[SSP] avg %+8ld %+8ld %+8ld (LSB)\n", avg[0], avg[1], avg[2]); + pr_info("[SSP] rms %+8ld %+8ld %+8ld (LSB)\n", rms[0], rms[1], rms[2]); + + if (hw_result < 0) { + pr_err("[SSP] %s - hw selftest fail(%d), sw selftest skip\n", + __func__, hw_result); + return sprintf(buf, "-1,0,0,0,0,0,0,%d.%d,%d.%d,%d.%d,0,0,0\n", + shift_ratio[0] / 10, shift_ratio[0] % 10, + shift_ratio[1] / 10, shift_ratio[1] % 10, + shift_ratio[2] / 10, shift_ratio[2] % 10); + } + gyro_bias[0] = (avg[0] * DEF_SCALE_FOR_FLOAT) / DEF_GYRO_SENS; + gyro_bias[1] = (avg[1] * DEF_SCALE_FOR_FLOAT) / DEF_GYRO_SENS; + gyro_bias[2] = (avg[2] * DEF_SCALE_FOR_FLOAT) / DEF_GYRO_SENS; + iCalData[0] = (s16)avg[0]; + iCalData[1] = (s16)avg[1]; + iCalData[2] = (s16)avg[2]; + + if (VERBOSE_OUT) { + pr_info("[SSP] abs bias: %+8d.%03d %+8d.%03d %+8d.%03d (dps)\n", + (int)abs(gyro_bias[0]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[0]) % DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[1]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[1]) % DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[2]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[2]) % DEF_SCALE_FOR_FLOAT); + } + + for (j = 0; j < 3; j++) { + if (unlikely(abs(avg[j]) > bias_thresh)) { + pr_err("[SSP] %s-Gyro bias (%ld) exceeded threshold " + "(threshold = %d LSB)\n", a_name[j], + avg[j], bias_thresh); + ret_val |= 1 << (3 + j); + } + } + /* 3rd, check RMS for dead gyros + If any of the RMS noise value returns zero, + then we might have dead gyro or FIFO/register failure, + the part is sleeping, or the part is not responsive */ + if (rms[0] == 0 || rms[1] == 0 || rms[2] == 0) + ret_val |= 1 << 6; + + if (VERBOSE_OUT) { + pr_info("[SSP] RMS ^ 2 : %+8ld %+8ld %+8ld\n", + (long)rms[0] / total_count, + (long)rms[1] / total_count, (long)rms[2] / total_count); + } + + for (j = 0; j < 3; j++) { + if (unlikely(rms[j] / total_count > DEF_RMS_THRESH)) { + pr_err("[SSP] %s-Gyro rms (%ld) exceeded threshold " + "(threshold = %d LSB)\n", a_name[j], + rms[j] / total_count, DEF_RMS_THRESH); + ret_val |= 1 << (7 + j); + } + } + + for (i = 0; i < 3; i++) { + if (rms[i] > 10000) { + temp = + ((u32) (rms[i] / total_count)) * + DEF_RMS_SCALE_FOR_RMS; + } else { + temp = + ((u32) (rms[i] * DEF_RMS_SCALE_FOR_RMS)) / + total_count; + } + if (rms[i] < 0) + temp = 1 << 31; + + dps_rms[i] = mpu6050_selftest_sqrt(temp) / DEF_GYRO_SENS; + + gyro_rms[i] = + dps_rms[i] * DEF_SCALE_FOR_FLOAT / DEF_SQRT_SCALE_FOR_RMS; + } + + pr_info("[SSP] RMS : %+8d.%03d %+8d.%03d %+8d.%03d (dps)\n", + (int)abs(gyro_rms[0]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[0]) % DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[1]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[1]) % DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[2]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[2]) % DEF_SCALE_FOR_FLOAT); + + if (likely(!ret_val)) { + save_gyro_caldata(data, iCalData); + } else { + pr_err("[SSP] ret_val != 0, gyrocal is 0 at all axis\n"); + data->gyrocal.x = 0; + data->gyrocal.y = 0; + data->gyrocal.z = 0; + } + +exit: + ssp_dbg("[SSP]: %s - %d," + "%d.%03d,%d.%03d,%d.%03d," + "%d.%03d,%d.%03d,%d.%03d," + "%d.%d,%d.%d,%d.%d," + "%d,%d,%d\n", + __func__, ret_val, + (int)abs(gyro_bias[0]/1000), + (int)abs(gyro_bias[0])%1000, + (int)abs(gyro_bias[1]/1000), + (int)abs(gyro_bias[1])%1000, + (int)abs(gyro_bias[2]/1000), + (int)abs(gyro_bias[2])%1000, + gyro_rms[0]/1000, + (int)abs(gyro_rms[0])%1000, + gyro_rms[1]/1000, + (int)abs(gyro_rms[1])%1000, + gyro_rms[2]/1000, + (int)abs(gyro_rms[2])%1000, + shift_ratio[0] / 10, shift_ratio[0] % 10, + shift_ratio[1] / 10, shift_ratio[1] % 10, + shift_ratio[2] / 10, shift_ratio[2] % 10, + (int)(total_count/3), + (int)(total_count/3), + (int)(total_count/3)); + + return sprintf(buf, "%d," + "%d.%03d,%d.%03d,%d.%03d," + "%d.%03d,%d.%03d,%d.%03d," + "%d.%d,%d.%d,%d.%d," + "%d,%d,%d\n", + ret_val, + (int)abs(gyro_bias[0]/1000), + (int)abs(gyro_bias[0])%1000, + (int)abs(gyro_bias[1]/1000), + (int)abs(gyro_bias[1])%1000, + (int)abs(gyro_bias[2]/1000), + (int)abs(gyro_bias[2])%1000, + gyro_rms[0]/1000, + (int)abs(gyro_rms[0])%1000, + gyro_rms[1]/1000, + (int)abs(gyro_rms[1])%1000, + gyro_rms[2]/1000, + (int)abs(gyro_rms[2])%1000, + shift_ratio[0] / 10, shift_ratio[0] % 10, + shift_ratio[1] / 10, shift_ratio[1] % 10, + shift_ratio[2] / 10, shift_ratio[2] % 10, + (int)(total_count/3), + (int)(total_count/3), + (int)(total_count/3)); +} + +static ssize_t gyro_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return mpu6500_gyro_selftest(buf, data); +} + +static ssize_t gyro_selftest_dps_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int iNewDps = 0; + int iDelayCnt = 0, iRet = 0; + char chTempBuf[2] = { 0, 10 }; + + struct ssp_data *data = dev_get_drvdata(dev); + + if (!(data->uSensorState & (1 << GYROSCOPE_SENSOR))) + goto exit; + + sscanf(buf, "%d", &iNewDps); + + if (iNewDps == GYROSCOPE_DPS250) + chTempBuf[0] = 0; + else if (iNewDps == GYROSCOPE_DPS500) + chTempBuf[0] = 1; + else if (iNewDps == GYROSCOPE_DPS2000) + chTempBuf[0] = 2; + else { + chTempBuf[0] = 1; + iNewDps = GYROSCOPE_DPS500; + } + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_DPS_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GYROSCOPE_DPS_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Gyro Selftest DPS Timeout!!\n", __func__); + goto exit; + } + + mdelay(5); + + if (data->uFactorydata[0] != SUCCESS) { + pr_err("[SSP]: %s - Gyro Selftest DPS Error!!\n", __func__); + goto exit; + } + + data->uGyroDps = (unsigned int)iNewDps; + pr_err("[SSP]: %s - %u dps stored\n", __func__, data->uGyroDps); +exit: + return count; +} + +static ssize_t gyro_selftest_dps_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", data->uGyroDps); +} + +static DEVICE_ATTR(name, S_IRUGO, gyro_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, gyro_vendor_show, NULL); +static DEVICE_ATTR(power_off, S_IRUGO, gyro_power_off, NULL); +static DEVICE_ATTR(power_on, S_IRUGO, gyro_power_on, NULL); +static DEVICE_ATTR(temperature, S_IRUGO, gyro_get_temp, NULL); +static DEVICE_ATTR(selftest, S_IRUGO, gyro_selftest_show, NULL); +static DEVICE_ATTR(selftest_dps, S_IRUGO | S_IWUSR | S_IWGRP, + gyro_selftest_dps_show, gyro_selftest_dps_store); + +static struct device_attribute *gyro_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_selftest, + &dev_attr_power_on, + &dev_attr_power_off, + &dev_attr_temperature, + &dev_attr_selftest_dps, + NULL, +}; + +void initialize_gyro_factorytest(struct ssp_data *data) +{ + sensors_register(data->gyro_device, data, gyro_attrs, "gyro_sensor"); +} + +void remove_gyro_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->gyro_device, gyro_attrs); +} diff --git a/drivers/sensorhub/stm/factory/light_cm3320.c b/drivers/sensorhub/stm/factory/light_cm3320.c new file mode 100755 index 00000000000..a6438d086a3 --- /dev/null +++ b/drivers/sensorhub/stm/factory/light_cm3320.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" + +#define VENDOR "CAPELLA" +#define CHIP_ID_3320 "CM3320" +#define CHIP_ID "CM3323" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ +static ssize_t light_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t light_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID_3320); +} + +static ssize_t light_lux_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u,%u,%u,%u\n", + data->buf[LIGHT_SENSOR].r, data->buf[LIGHT_SENSOR].g, + data->buf[LIGHT_SENSOR].b, data->buf[LIGHT_SENSOR].w); +} + +static ssize_t light_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u,%u,%u,%u\n", + data->buf[LIGHT_SENSOR].r, data->buf[LIGHT_SENSOR].g, + data->buf[LIGHT_SENSOR].b, data->buf[LIGHT_SENSOR].w); +} + +static DEVICE_ATTR(vendor, S_IRUGO, light_vendor_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, light_name_show, NULL); +static DEVICE_ATTR(lux, S_IRUGO, light_lux_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, light_data_show, NULL); + +static struct device_attribute *light_attrs[] = { + &dev_attr_vendor, + &dev_attr_name, + &dev_attr_lux, + &dev_attr_raw_data, + NULL, +}; + +void initialize_light_factorytest(struct ssp_data *data) +{ + sensors_register(data->light_device, data, light_attrs, "light_sensor"); +} + +void remove_light_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->light_device, light_attrs); +} diff --git a/drivers/sensorhub/stm/factory/magnetic_yas532.c b/drivers/sensorhub/stm/factory/magnetic_yas532.c new file mode 100755 index 00000000000..be9a38f921d --- /dev/null +++ b/drivers/sensorhub/stm/factory/magnetic_yas532.c @@ -0,0 +1,456 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "YAMAHA" +#define CHIP_ID "YAS532" +#define MAG_HW_OFFSET_FILE_PATH "/efs/hw_offset" + +int mag_open_hwoffset(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[SSP] %s: filp_open failed\n", __func__); + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + + data->magoffset.x = 0; + data->magoffset.y = 0; + data->magoffset.z = 0; + + return iRet; + } + + iRet = cal_filp->f_op->read(cal_filp, (char *)&data->magoffset, + 3 * sizeof(char), &cal_filp->f_pos); + if (iRet != 3 * sizeof(char)) { + pr_err("[SSP] %s: filp_open failed\n", __func__); + iRet = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + ssp_dbg("[SSP]: %s: %d, %d, %d\n", __func__, + (s8)data->magoffset.x, + (s8)data->magoffset.y, + (s8)data->magoffset.z); + + if ((data->magoffset.x == 0) && (data->magoffset.y == 0) + && (data->magoffset.z == 0)) + return ERROR; + + return iRet; +} + +int mag_store_hwoffset(struct ssp_data *data) +{ + int iRet = 0; + struct file *cal_filp = NULL; + mm_segment_t old_fs; + + if (get_hw_offset(data) < 0) { + pr_err("[SSP]: %s - get_hw_offset failed\n", __func__); + return ERROR; + } else { + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (IS_ERR(cal_filp)) { + pr_err("[SSP]: %s - Can't open hw_offset file\n", + __func__); + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + return iRet; + } + iRet = cal_filp->f_op->write(cal_filp, + (char *)&data->magoffset, + 3 * sizeof(char), &cal_filp->f_pos); + if (iRet != 3 * sizeof(char)) { + pr_err("[SSP]: %s - Can't write the hw_offset" + " to file\n", __func__); + iRet = -EIO; + } + filp_close(cal_filp, current->files); + set_fs(old_fs); + return iRet; + } +} + +int set_hw_offset(struct ssp_data *data) +{ + char chTxBuf[4] = { 0, }; + char chRxBuf = 0; + int iRet = 0; + + if (waiting_wakeup_mcu(data) < 0 || + data->fw_dl_state == FW_DL_STATE_DOWNLOADING) { + pr_info("[SSP] : %s, skip DL state = %d\n", __func__, + data->fw_dl_state); + return FAIL; + } + + chTxBuf[0] = MSG2SSP_AP_SET_MAGNETIC_HWOFFSET; + chTxBuf[1] = data->magoffset.x; + chTxBuf[2] = data->magoffset.y; + chTxBuf[3] = data->magoffset.z; + + iRet = ssp_read_data(data, chTxBuf, 4, &chRxBuf, 1, DEFAULT_RETRIES); + if ((chRxBuf != MSG_ACK) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - spi fail %d, %d\n", + __func__, iRet, chRxBuf); + iRet = ERROR; + } + + pr_info("[SSP]: %s: x: %d, y: %d, z: %d\n", __func__, + (s8)chTxBuf[1], (s8)chTxBuf[2], (s8)chTxBuf[3]); + return iRet; +} + +int get_hw_offset(struct ssp_data *data) +{ + char chTxBuf = 0; + char chRxBuf[3] = { 0, }; + int iRet = 0; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + chTxBuf = MSG2SSP_AP_GET_MAGNETIC_HWOFFSET; + + data->magoffset.x = 0; + data->magoffset.y = 0; + data->magoffset.z = 0; + + iRet = ssp_read_data(data, &chTxBuf, 1, chRxBuf, 3, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - spi fail %d\n", __func__, iRet); + iRet = ERROR; + } + + data->magoffset.x = chRxBuf[0]; + data->magoffset.y = chRxBuf[1]; + data->magoffset.z = chRxBuf[2]; + + pr_info("[SSP]: %s: x: %d, y: %d, z: %d\n", __func__, + (s8)data->magoffset.x, + (s8)data->magoffset.y, + (s8)data->magoffset.z); + return iRet; +} + +static ssize_t magnetic_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t magnetic_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +static int check_rawdata_spec(struct ssp_data *data) +{ + if ((data->buf[GEOMAGNETIC_SENSOR].x == 0) && + (data->buf[GEOMAGNETIC_SENSOR].y == 0) && + (data->buf[GEOMAGNETIC_SENSOR].z == 0)) + return FAIL; + else + return SUCCESS; +} + +static ssize_t raw_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + pr_info("[SSP] %s - %d,%d,%d\n", __func__, + data->buf[GEOMAGNETIC_SENSOR].x, + data->buf[GEOMAGNETIC_SENSOR].y, + data->buf[GEOMAGNETIC_SENSOR].z); + + if (data->bGeomagneticRawEnabled == false) { + data->buf[GEOMAGNETIC_SENSOR].x = -1; + data->buf[GEOMAGNETIC_SENSOR].y = -1; + data->buf[GEOMAGNETIC_SENSOR].z = -1; + } else { + if (data->buf[GEOMAGNETIC_SENSOR].x > 18000) + data->buf[GEOMAGNETIC_SENSOR].x = 18000; + else if (data->buf[GEOMAGNETIC_SENSOR].x < -18000) + data->buf[GEOMAGNETIC_SENSOR].x = -18000; + if (data->buf[GEOMAGNETIC_SENSOR].y > 18000) + data->buf[GEOMAGNETIC_SENSOR].y = 18000; + else if (data->buf[GEOMAGNETIC_SENSOR].y < -18000) + data->buf[GEOMAGNETIC_SENSOR].y = -18000; + if (data->buf[GEOMAGNETIC_SENSOR].z > 18000) + data->buf[GEOMAGNETIC_SENSOR].z = 18000; + else if (data->buf[GEOMAGNETIC_SENSOR].z < -18000) + data->buf[GEOMAGNETIC_SENSOR].z = -18000; + } + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", + data->buf[GEOMAGNETIC_SENSOR].x, + data->buf[GEOMAGNETIC_SENSOR].y, + data->buf[GEOMAGNETIC_SENSOR].z); +} + +static ssize_t raw_data_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + char chTempbuf[2] = { 1, 20}; + int iRet; + int64_t dEnable; + int iRetries = 50; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtoll(buf, 10, &dEnable); + if (iRet < 0) + return iRet; + + if (dEnable) { + data->buf[GEOMAGNETIC_SENSOR].x = 0; + data->buf[GEOMAGNETIC_SENSOR].y = 0; + data->buf[GEOMAGNETIC_SENSOR].z = 0; + + send_instruction(data, ADD_SENSOR, GEOMAGNETIC_RAW, + chTempbuf, 2); + + do { + msleep(20); + if (check_rawdata_spec(data) == SUCCESS) + break; + } while (--iRetries); + + if (iRetries > 0) { + pr_info("[SSP] %s - success, %d\n", __func__, iRetries); + data->bGeomagneticRawEnabled = true; + } else { + pr_err("[SSP] %s - wait timeout, %d\n", __func__, + iRetries); + data->bGeomagneticRawEnabled = false; + } + } else { + send_instruction(data, REMOVE_SENSOR, GEOMAGNETIC_RAW, + chTempbuf, 2); + data->bGeomagneticRawEnabled = false; + } + + return size; +} + +static int check_data_spec(struct ssp_data *data) +{ + if ((data->buf[GEOMAGNETIC_SENSOR].x == 0) && + (data->buf[GEOMAGNETIC_SENSOR].y == 0) && + (data->buf[GEOMAGNETIC_SENSOR].z == 0)) + return FAIL; + else if ((data->buf[GEOMAGNETIC_SENSOR].x > 6500) || + (data->buf[GEOMAGNETIC_SENSOR].x < -6500) || + (data->buf[GEOMAGNETIC_SENSOR].y > 6500) || + (data->buf[GEOMAGNETIC_SENSOR].y < -6500) || + (data->buf[GEOMAGNETIC_SENSOR].z > 6500) || + (data->buf[GEOMAGNETIC_SENSOR].z < -6500)) + return FAIL; + else + return SUCCESS; +} + +static ssize_t adc_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + u8 chTempbuf[2] = {1, 20}; + s16 iSensorBuf[3] = {0, }; + int iRetries = 10; + struct ssp_data *data = dev_get_drvdata(dev); + + data->buf[GEOMAGNETIC_SENSOR].x = 0; + data->buf[GEOMAGNETIC_SENSOR].y = 0; + data->buf[GEOMAGNETIC_SENSOR].z = 0; + + if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_SENSOR))) + send_instruction(data, ADD_SENSOR, GEOMAGNETIC_SENSOR, + chTempbuf, 2); + + do { + msleep(60); + if (check_data_spec(data) == SUCCESS) + break; + } while (--iRetries); + + if (iRetries > 0) + bSuccess = true; + + iSensorBuf[0] = data->buf[GEOMAGNETIC_SENSOR].x; + iSensorBuf[1] = data->buf[GEOMAGNETIC_SENSOR].y; + iSensorBuf[2] = data->buf[GEOMAGNETIC_SENSOR].z; + + if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_SENSOR))) + send_instruction(data, REMOVE_SENSOR, GEOMAGNETIC_SENSOR, + chTempbuf, 2); + + pr_info("[SSP]: %s - x = %d, y = %d, z = %d\n", __func__, + iSensorBuf[0], iSensorBuf[1], iSensorBuf[2]); + + return sprintf(buf, "%s,%d,%d,%d\n", (bSuccess ? "OK" : "NG"), + iSensorBuf[0], iSensorBuf[1], iSensorBuf[2]); +} + +static ssize_t magnetic_get_selftest(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char chTempBuf[2] = { 0, 10 }; + int iDelayCnt = 0, iRet = 0, iTimeoutReties = 0; + s8 id = 0, x = 0, y1 = 0, y2 = 0, dir = 0; + s16 sx = 0, sy = 0, ohx = 0, ohy = 0, ohz = 0; + s8 err[7] = {0, }; + struct ssp_data *data = dev_get_drvdata(dev); + +reties: + iDelayCnt = 0; + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GEOMAGNETIC_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GEOMAGNETIC_FACTORY)) + && (iDelayCnt++ < 50) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 50) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Magnetic Selftest Timeout!! %d\n", + __func__, iRet); + if (iTimeoutReties++ < 3) + goto reties; + else + goto exit; + } + + mdelay(5); + + id = (s8)(data->uFactorydata[0]); + err[0] = (s8)(data->uFactorydata[1]); + err[1] = (s8)(data->uFactorydata[2]); + err[2] = (s8)(data->uFactorydata[3]); + x = (s8)(data->uFactorydata[4]); + y1 = (s8)(data->uFactorydata[5]); + y2 = (s8)(data->uFactorydata[6]); + err[3] = (s8)(data->uFactorydata[7]); + dir = (s8)(data->uFactorydata[8]); + err[4] = (s8)(data->uFactorydata[9]); + ohx = (s16)((data->uFactorydata[10] << 8) + data->uFactorydata[11]); + ohy = (s16)((data->uFactorydata[12] << 8) + data->uFactorydata[13]); + ohz = (s16)((data->uFactorydata[14] << 8) + data->uFactorydata[15]); + err[6] = (s8)(data->uFactorydata[16]); + sx = (s16)((data->uFactorydata[17] << 8) + data->uFactorydata[18]); + sy = (s16)((data->uFactorydata[19] << 8) + data->uFactorydata[20]); + err[5] = (s8)(data->uFactorydata[21]); + + if (unlikely(id != 0x2)) + err[0] = -1; + if (unlikely(x < -30 || x > 30)) + err[3] = -1; + if (unlikely(y1 < -30 || y1 > 30)) + err[3] = -1; + if (unlikely(y2 < -30 || y2 > 30)) + err[3] = -1; + if (unlikely(sx < 17 || sy < 22)) + err[5] = -1; + if (unlikely(ohx < -600 || ohx > 600)) + err[6] = -1; + if (unlikely(ohy < -600 || ohy > 600)) + err[6] = -1; + if (unlikely(ohz < -600 || ohz > 600)) + err[6] = -1; + + pr_info("[SSP] %s\n" + "[SSP] Test1 - err = %d, id = %d\n" + "[SSP] Test3 - err = %d\n" + "[SSP] Test4 - err = %d, offset = %d,%d,%d\n" + "[SSP] Test5 - err = %d, direction = %d\n" + "[SSP] Test6 - err = %d, sensitivity = %d,%d\n" + "[SSP] Test7 - err = %d, offset = %d,%d,%d\n" + "[SSP] Test2 - err = %d\n", + __func__, err[0], id, err[2], err[3], x, y1, y2, err[4], dir, + err[5], sx, sy, err[6], ohx, ohy, ohz, err[1]); + +exit: + return sprintf(buf, + "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + err[0], id, err[2], err[3], x, y1, y2, err[4], dir, + err[5], sx, sy, err[6], ohx, ohy, ohz, err[1]); +} + +static ssize_t hw_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + mag_open_hwoffset(data); + + pr_info("[SSP] %s: %d %d %d\n", __func__, + (s8)data->magoffset.x, + (s8)data->magoffset.y, + (s8)data->magoffset.z); + + return sprintf(buf, "%d %d %d\n", + (s8)data->magoffset.x, + (s8)data->magoffset.y, + (s8)data->magoffset.z); +} + +static DEVICE_ATTR(name, S_IRUGO, magnetic_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, magnetic_vendor_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO | S_IWUSR | S_IWGRP, + raw_data_show, raw_data_store); +static DEVICE_ATTR(adc, S_IRUGO, adc_data_read, NULL); +static DEVICE_ATTR(selftest, S_IRUGO, magnetic_get_selftest, NULL); +static DEVICE_ATTR(hw_offset, S_IRUGO, hw_offset_show, NULL); + +static struct device_attribute *mag_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_adc, + &dev_attr_raw_data, + &dev_attr_selftest, + &dev_attr_hw_offset, + NULL, +}; + +void initialize_magnetic_factorytest(struct ssp_data *data) +{ + sensors_register(data->mag_device, data, mag_attrs, "magnetic_sensor"); +} + +void remove_magnetic_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->mag_device, mag_attrs); +} diff --git a/drivers/sensorhub/stm/factory/mcu_atuc128l5har.c b/drivers/sensorhub/stm/factory/mcu_atuc128l5har.c new file mode 100755 index 00000000000..7f6a7a15ee3 --- /dev/null +++ b/drivers/sensorhub/stm/factory/mcu_atuc128l5har.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define MODEL_NAME "ATUC128L5HAR" + +ssize_t mcu_revision_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "AT01%u,AT01%u\n", data->uCurFirmRev, + get_module_rev(data)); +} + +ssize_t mcu_model_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", MODEL_NAME); +} + +ssize_t mcu_update_kernel_bin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + iRet = forced_to_download_binary(data, UMS_BINARY); + if (iRet == SUCCESS) { + bSuccess = true; + goto out; + } + + iRet = forced_to_download_binary(data, KERNEL_BINARY); + if (iRet == SUCCESS) + bSuccess = true; + else + bSuccess = false; +out: + return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); +} + +ssize_t mcu_update_kernel_crashed_bin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + iRet = forced_to_download_binary(data, UMS_BINARY); + if (iRet == SUCCESS) { + bSuccess = true; + goto out; + } + + iRet = forced_to_download_binary(data, KERNEL_CRASHED_BINARY); + if (iRet == SUCCESS) + bSuccess = true; + else + bSuccess = false; +out: + return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); +} + +ssize_t mcu_update_ums_bin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + iRet = forced_to_download_binary(data, UMS_BINARY); + if (iRet == SUCCESS) + bSuccess = true; + else + bSuccess = false; + + return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); +} + +ssize_t mcu_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + reset_mcu(data); + + return sprintf(buf, "OK\n"); +} + +ssize_t mcu_factorytest_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + char chTempBuf[2] = {0, 10}; + int iRet = 0; + + if (sysfs_streq(buf, "1")) { + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + data->bMcuIRQTestSuccessed = false; + data->uTimeOutCnt = 0; + + iRet = send_instruction(data, FACTORY_MODE, + MCU_FACTORY, chTempBuf, 2); + if (data->uTimeOutCnt == 0) + data->bMcuIRQTestSuccessed = true; + } else { + pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + ssp_dbg("[SSP]: MCU Factory Test Start! - %d\n", iRet); + + return size; +} + +ssize_t mcu_factorytest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bMcuTestSuccessed = false; + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->bSspShutdown == true) { + ssp_dbg("[SSP]: %s - MCU Bin is crashed\n", __func__); + return sprintf(buf, "NG,NG,NG\n"); + } + + if (data->uFactorydataReady & (1 << MCU_FACTORY)) { + ssp_dbg("[SSP] MCU Factory Test Data : %u, %u, %u, %u, %u\n", + data->uFactorydata[0], data->uFactorydata[1], + data->uFactorydata[2], data->uFactorydata[3], + data->uFactorydata[4]); + + /* system clock, RTC, I2C Master, I2C Slave, externel pin */ + if ((data->uFactorydata[0] == SUCCESS) + && (data->uFactorydata[1] == SUCCESS) + && (data->uFactorydata[2] == SUCCESS) + && (data->uFactorydata[3] == SUCCESS) + && (data->uFactorydata[4] == SUCCESS)) + bMcuTestSuccessed = true; + } else { + pr_err("[SSP]: %s - The Sensorhub is not ready %u\n", __func__, + data->uFactorydataReady); + } + + ssp_dbg("[SSP]: MCU Factory Test Result - %s, %s, %s\n", MODEL_NAME, + (data->bMcuIRQTestSuccessed ? "OK" : "NG"), + (bMcuTestSuccessed ? "OK" : "NG")); + + return sprintf(buf, "%s,%s,%s\n", MODEL_NAME, + (data->bMcuIRQTestSuccessed ? "OK" : "NG"), + (bMcuTestSuccessed ? "OK" : "NG")); +} + +ssize_t mcu_sleep_factorytest_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + char chTempBuf[2] = {0, 10}; + int iRet = 0; + + if (sysfs_streq(buf, "1")) { + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, + MCU_SLEEP_FACTORY, chTempBuf, 2); + } else { + pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + ssp_dbg("[SSP]: MCU Sleep Factory Test Start! - %d\n", iRet); + + return size; +} + +ssize_t mcu_sleep_factorytest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int iDataIdx, iSensorData = 0; + struct ssp_data *data = dev_get_drvdata(dev); + struct sensor_value fsb[SENSOR_MAX]; + + if (!(data->uFactorydataReady & (1 << MCU_SLEEP_FACTORY))) { + pr_err("[SSP]: %s - The Sensorhub is not ready\n", __func__); + goto exit; + } + + for (iDataIdx = 0; iDataIdx < FACTORY_DATA_MAX;) { + iSensorData = (int)data->uFactorydata[iDataIdx++]; + + if ((iSensorData < 0) || + (iSensorData >= (SENSOR_MAX - 1))) { + pr_err("[SSP]: %s - Mcu data frame error %d\n", + __func__, iSensorData); + goto exit; + } + + data->get_sensor_data[iSensorData]((char *)data->uFactorydata, + &iDataIdx, &(fsb[iSensorData])); + } + + convert_acc_data(&fsb[ACCELEROMETER_SENSOR].x); + convert_acc_data(&fsb[ACCELEROMETER_SENSOR].y); + convert_acc_data(&fsb[ACCELEROMETER_SENSOR].z); + + fsb[ACCELEROMETER_SENSOR].x -= data->accelcal.x; + fsb[ACCELEROMETER_SENSOR].y -= data->accelcal.y; + fsb[ACCELEROMETER_SENSOR].z -= data->accelcal.z; + + fsb[GYROSCOPE_SENSOR].x -= data->gyrocal.x; + fsb[GYROSCOPE_SENSOR].y -= data->gyrocal.y; + fsb[GYROSCOPE_SENSOR].z -= data->gyrocal.z; + + fsb[PRESSURE_SENSOR].pressure[0] -= data->iPressureCal; + +exit: + ssp_dbg("[SSP]: %s Result\n" + "accel %d,%d,%d\n" + "gyro %d,%d,%d\n" + "mag %d,%d,%d\n" + "baro %d,%d\n" + "ges %d,%d,%d,%d\n" + "prox %u,%u\n" + "temp %d,%d,%d\n" + "light %u,%u,%u,%u\n", __func__, + fsb[ACCELEROMETER_SENSOR].x, fsb[ACCELEROMETER_SENSOR].y, + fsb[ACCELEROMETER_SENSOR].z, fsb[GYROSCOPE_SENSOR].x, + fsb[GYROSCOPE_SENSOR].y, fsb[GYROSCOPE_SENSOR].z, + fsb[GEOMAGNETIC_SENSOR].x, fsb[GEOMAGNETIC_SENSOR].y, + fsb[GEOMAGNETIC_SENSOR].z, fsb[PRESSURE_SENSOR].pressure[0], + fsb[PRESSURE_SENSOR].pressure[1], + fsb[GESTURE_SENSOR].data[0], fsb[GESTURE_SENSOR].data[1], + fsb[GESTURE_SENSOR].data[2], fsb[GESTURE_SENSOR].data[3], + fsb[PROXIMITY_SENSOR].prox[0], fsb[PROXIMITY_SENSOR].prox[1], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[0], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[1], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[2], + fsb[LIGHT_SENSOR].r, fsb[LIGHT_SENSOR].g, fsb[LIGHT_SENSOR].b, + fsb[LIGHT_SENSOR].w); + + return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%u," + "%u,%u,%u,%u,%d,%d,%d,%d,%d,%d\n", + fsb[ACCELEROMETER_SENSOR].x, fsb[ACCELEROMETER_SENSOR].y, + fsb[ACCELEROMETER_SENSOR].z, fsb[GYROSCOPE_SENSOR].x, + fsb[GYROSCOPE_SENSOR].y, fsb[GYROSCOPE_SENSOR].z, + fsb[GEOMAGNETIC_SENSOR].x, fsb[GEOMAGNETIC_SENSOR].y, + fsb[GEOMAGNETIC_SENSOR].z, fsb[PRESSURE_SENSOR].pressure[0], + fsb[PRESSURE_SENSOR].pressure[1], fsb[PROXIMITY_SENSOR].prox[1], + fsb[LIGHT_SENSOR].r, fsb[LIGHT_SENSOR].g, fsb[LIGHT_SENSOR].b, + fsb[LIGHT_SENSOR].w, + fsb[GESTURE_SENSOR].data[0], fsb[GESTURE_SENSOR].data[1], + fsb[GESTURE_SENSOR].data[2], fsb[GESTURE_SENSOR].data[3], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[0], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[1]); +} diff --git a/drivers/sensorhub/stm/factory/mcu_stm32f401.c b/drivers/sensorhub/stm/factory/mcu_stm32f401.c new file mode 100755 index 00000000000..b49fffcf1ce --- /dev/null +++ b/drivers/sensorhub/stm/factory/mcu_stm32f401.c @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define MODEL_NAME "STM32F401CCY6B" + +ssize_t mcu_revision_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "ST01%u,ST01%u\n", data->uCurFirmRev, + get_module_rev(data)); +} + +ssize_t mcu_model_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", MODEL_NAME); +} + +ssize_t mcu_update_kernel_bin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + iRet = forced_to_download_binary(data, UMS_BINARY); + if (iRet == SUCCESS) { + bSuccess = true; + goto out; + } + + iRet = forced_to_download_binary(data, KERNEL_BINARY); + if (iRet == SUCCESS) + bSuccess = true; + else + bSuccess = false; +out: + return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); +} + +ssize_t mcu_update_kernel_crashed_bin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + iRet = forced_to_download_binary(data, UMS_BINARY); + if (iRet == SUCCESS) { + bSuccess = true; + goto out; + } + + iRet = forced_to_download_binary(data, KERNEL_CRASHED_BINARY); + if (iRet == SUCCESS) + bSuccess = true; + else + bSuccess = false; +out: + return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); +} + +ssize_t mcu_update_ums_bin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + iRet = forced_to_download_binary(data, UMS_BINARY); + if (iRet == SUCCESS) + bSuccess = true; + else + bSuccess = false; + + return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG")); +} + +ssize_t mcu_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + reset_mcu(data); + + return sprintf(buf, "OK\n"); +} + +ssize_t mcu_factorytest_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + char chTempBuf[2] = {0, 10}; + int iRet = 0; + + if (sysfs_streq(buf, "1")) { + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + data->bMcuIRQTestSuccessed = false; + data->uTimeOutCnt = 0; + + iRet = send_instruction(data, FACTORY_MODE, + MCU_FACTORY, chTempBuf, 2); + if (data->uTimeOutCnt == 0) + data->bMcuIRQTestSuccessed = true; + } else { + pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + ssp_dbg("[SSP]: MCU Factory Test Start! - %d\n", iRet); + + return size; +} + +ssize_t mcu_factorytest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bMcuTestSuccessed = false; + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->bSspShutdown == true) { + ssp_dbg("[SSP]: %s - MCU Bin is crashed\n", __func__); + return sprintf(buf, "NG,NG,NG\n"); + } + + if (data->uFactorydataReady & (1 << MCU_FACTORY)) { + ssp_dbg("[SSP] MCU Factory Test Data : %u, %u, %u, %u, %u\n", + data->uFactorydata[0], data->uFactorydata[1], + data->uFactorydata[2], data->uFactorydata[3], + data->uFactorydata[4]); + + /* system clock, RTC, I2C Master, I2C Slave, externel pin */ + if ((data->uFactorydata[0] == SUCCESS) + && (data->uFactorydata[1] == SUCCESS) + && (data->uFactorydata[2] == SUCCESS) + && (data->uFactorydata[3] == SUCCESS) + && (data->uFactorydata[4] == SUCCESS)) + bMcuTestSuccessed = true; + } else { + pr_err("[SSP]: %s - The Sensorhub is not ready %u\n", __func__, + data->uFactorydataReady); + } + + ssp_dbg("[SSP]: MCU Factory Test Result - %s, %s, %s\n", MODEL_NAME, + (data->bMcuIRQTestSuccessed ? "OK" : "NG"), + (bMcuTestSuccessed ? "OK" : "NG")); + + return sprintf(buf, "%s,%s,%s\n", MODEL_NAME, + (data->bMcuIRQTestSuccessed ? "OK" : "NG"), + (bMcuTestSuccessed ? "OK" : "NG")); +} + +ssize_t mcu_sleep_factorytest_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + char chTempBuf[2] = {0, 10}; + int iRet = 0; + + if (sysfs_streq(buf, "1")) { + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, + MCU_SLEEP_FACTORY, chTempBuf, 2); + } else { + pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + ssp_dbg("[SSP]: MCU Sleep Factory Test Start! - %d\n", iRet); + + return size; +} + +ssize_t mcu_sleep_factorytest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int iDataIdx, iSensorData = 0; + struct ssp_data *data = dev_get_drvdata(dev); + struct sensor_value fsb[SENSOR_MAX]; + + if (!(data->uFactorydataReady & (1 << MCU_SLEEP_FACTORY))) { + pr_err("[SSP]: %s - The Sensorhub is not ready\n", __func__); + goto exit; + } + + for (iDataIdx = 0; iDataIdx < FACTORY_DATA_MAX;) { + iSensorData = (int)data->uFactorydata[iDataIdx++]; + + if ((iSensorData < 0) || + (iSensorData >= (SENSOR_MAX - 1))) { + pr_err("[SSP]: %s - Mcu data frame error %d\n", + __func__, iSensorData); + goto exit; + } + + data->get_sensor_data[iSensorData]((char *)data->uFactorydata, + &iDataIdx, &(fsb[iSensorData])); + } + + convert_acc_data(&fsb[ACCELEROMETER_SENSOR].x); + convert_acc_data(&fsb[ACCELEROMETER_SENSOR].y); + convert_acc_data(&fsb[ACCELEROMETER_SENSOR].z); + + fsb[ACCELEROMETER_SENSOR].x -= data->accelcal.x; + fsb[ACCELEROMETER_SENSOR].y -= data->accelcal.y; + fsb[ACCELEROMETER_SENSOR].z -= data->accelcal.z; + + fsb[GYROSCOPE_SENSOR].x -= data->gyrocal.x; + fsb[GYROSCOPE_SENSOR].y -= data->gyrocal.y; + fsb[GYROSCOPE_SENSOR].z -= data->gyrocal.z; + + fsb[PRESSURE_SENSOR].pressure[0] -= data->iPressureCal; + +exit: + ssp_dbg("[SSP]: %s Result\n" + "accel %d,%d,%d\n" + "gyro %d,%d,%d\n" + "mag %d,%d,%d\n" + "baro %d,%d\n" + "ges %d,%d,%d,%d\n" + "prox %u,%u\n" + "temp %d,%d,%d\n" + "light %u,%u,%u,%u\n", __func__, + fsb[ACCELEROMETER_SENSOR].x, fsb[ACCELEROMETER_SENSOR].y, + fsb[ACCELEROMETER_SENSOR].z, fsb[GYROSCOPE_SENSOR].x, + fsb[GYROSCOPE_SENSOR].y, fsb[GYROSCOPE_SENSOR].z, + fsb[GEOMAGNETIC_SENSOR].x, fsb[GEOMAGNETIC_SENSOR].y, + fsb[GEOMAGNETIC_SENSOR].z, fsb[PRESSURE_SENSOR].pressure[0], + fsb[PRESSURE_SENSOR].pressure[1], + fsb[GESTURE_SENSOR].data[0], fsb[GESTURE_SENSOR].data[1], + fsb[GESTURE_SENSOR].data[2], fsb[GESTURE_SENSOR].data[3], + fsb[PROXIMITY_SENSOR].prox[0], fsb[PROXIMITY_SENSOR].prox[1], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[0], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[1], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[2], + fsb[LIGHT_SENSOR].r, fsb[LIGHT_SENSOR].g, fsb[LIGHT_SENSOR].b, + fsb[LIGHT_SENSOR].w); + + return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%u," + "%u,%u,%u,%u,%d,%d,%d,%d,%d,%d\n", + fsb[ACCELEROMETER_SENSOR].x, fsb[ACCELEROMETER_SENSOR].y, + fsb[ACCELEROMETER_SENSOR].z, fsb[GYROSCOPE_SENSOR].x, + fsb[GYROSCOPE_SENSOR].y, fsb[GYROSCOPE_SENSOR].z, + fsb[GEOMAGNETIC_SENSOR].x, fsb[GEOMAGNETIC_SENSOR].y, + fsb[GEOMAGNETIC_SENSOR].z, fsb[PRESSURE_SENSOR].pressure[0], + fsb[PRESSURE_SENSOR].pressure[1], fsb[PROXIMITY_SENSOR].prox[1], + fsb[LIGHT_SENSOR].r, fsb[LIGHT_SENSOR].g, fsb[LIGHT_SENSOR].b, + fsb[LIGHT_SENSOR].w, + fsb[GESTURE_SENSOR].data[0], fsb[GESTURE_SENSOR].data[1], + fsb[GESTURE_SENSOR].data[2], fsb[GESTURE_SENSOR].data[3], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[0], + fsb[TEMPERATURE_HUMIDITY_SENSOR].data[1]); +} diff --git a/drivers/sensorhub/stm/factory/pressure_bmp182.c b/drivers/sensorhub/stm/factory/pressure_bmp182.c new file mode 100755 index 00000000000..a46266f4458 --- /dev/null +++ b/drivers/sensorhub/stm/factory/pressure_bmp182.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" + +#define VENDOR "BOSCH" +#define CHIP_ID "BMP180" +#define VENDOR_STM "STM" +#define CHIP_ID_LPS25H "LPS25H" + +#define CALIBRATION_FILE_PATH "/efs/FactoryApp/baro_delta" + +#define PR_ABS_MAX 8388607 /* 24 bit 2'compl */ +#define PR_ABS_MIN -8388608 + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +static ssize_t sea_level_pressure_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + int iNewSeaLevelPressure; + + sscanf(buf, "%d", &iNewSeaLevelPressure); + + if (iNewSeaLevelPressure == 0) { + pr_info("%s, our->temperature = 0\n", __func__); + iNewSeaLevelPressure = -1; + } + + input_report_rel(data->pressure_input_dev, REL_DIAL, + iNewSeaLevelPressure); + input_sync(data->pressure_input_dev); + + return size; +} + +int pressure_open_calibration(struct ssp_data *data) +{ + char chBuf[10] = {0,}; + int iErr = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cal_filp)) { + iErr = PTR_ERR(cal_filp); + if (iErr != -ENOENT) + pr_err("[SSP]: %s - Can't open calibration file(%d)\n", + __func__, iErr); + set_fs(old_fs); + return iErr; + } + iErr = cal_filp->f_op->read(cal_filp, + chBuf, 10 * sizeof(char), &cal_filp->f_pos); + if (iErr < 0) { + pr_err("[SSP]: %s - Can't read the cal data from file (%d)\n", + __func__, iErr); + return iErr; + } + filp_close(cal_filp, current->files); + set_fs(old_fs); + + iErr = kstrtoint(chBuf, 10, &data->iPressureCal); + if (iErr < 0) { + pr_err("[SSP]: %s - kstrtoint failed. %d", __func__, iErr); + return iErr; + } + + ssp_dbg("[SSP]: open barometer calibration %d\n", data->iPressureCal); + + if (data->iPressureCal < PR_ABS_MIN || data->iPressureCal > PR_ABS_MAX) + pr_err("[SSP]: %s - wrong offset value!!!\n", __func__); + + return iErr; +} + +static ssize_t pressure_cabratioin_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + int iPressureCal = 0, iErr = 0; + + iErr = kstrtoint(buf, 10, &iPressureCal); + if (iErr < 0) { + pr_err("[SSP]: %s - kstrtoint failed.(%d)", __func__, iErr); + return iErr; + } + + if (iPressureCal < PR_ABS_MIN || iPressureCal > PR_ABS_MAX) + return -EINVAL; + + data->iPressureCal = (s32)iPressureCal; + + return size; +} + +static ssize_t pressure_cabratioin_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + pressure_open_calibration(data); + + return sprintf(buf, "%d\n", data->iPressureCal); +} + +static ssize_t eeprom_check_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + char chTempBuf[2] = {0, 10}; + int iRet, iDelayCnt = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, PRESSURE_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << PRESSURE_FACTORY)) + && (iDelayCnt++ < 150) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 150) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Pressure Selftest Timeout!!\n", + __func__); + goto exit; + } + + mdelay(5); + + bSuccess = (bool)(!!data->uFactorydata[0]); + ssp_dbg("[SSP]: %s - %u\n", __func__, bSuccess); + +exit: + return snprintf(buf, PAGE_SIZE, "%d", bSuccess); +} + +/* sysfs for vendor & name */ +static ssize_t pressure_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t pressure_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +static DEVICE_ATTR(vendor, S_IRUGO, pressure_vendor_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, pressure_name_show, NULL); +static DEVICE_ATTR(eeprom_check, S_IRUGO, eeprom_check_show, NULL); +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, + pressure_cabratioin_show, pressure_cabratioin_store); +static DEVICE_ATTR(sea_level_pressure, S_IRUGO | S_IWUSR | S_IWGRP, + NULL, sea_level_pressure_store); + +static struct device_attribute *pressure_attrs[] = { + &dev_attr_vendor, + &dev_attr_name, + &dev_attr_calibration, + &dev_attr_sea_level_pressure, + &dev_attr_eeprom_check, + NULL, +}; + +void initialize_pressure_factorytest(struct ssp_data *data) +{ + sensors_register(data->prs_device, data, pressure_attrs, + "barometer_sensor"); +} + +void remove_pressure_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->prs_device, pressure_attrs); +} diff --git a/drivers/sensorhub/stm/factory/prox_max88920.c b/drivers/sensorhub/stm/factory/prox_max88920.c new file mode 100755 index 00000000000..84d4fd535da --- /dev/null +++ b/drivers/sensorhub/stm/factory/prox_max88920.c @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" + +#define VENDOR "MAXIM" +#define CHIP_ID "MAX88920" + +#define CANCELATION_FILE_PATH "/efs/prox_cal" +#define LCD_LDI_FILE_PATH "/sys/class/lcd/panel/window_type" + +#define LINE_1 '4' +#define LINE_2 '2' + +#define LDI_OTHERS '0' +#define LDI_GRAY '1' +#define LDI_WHITE '2' + +#define DEFUALT_HIGH_THRESHOLD 60 +#define DEFUALT_LOW_THRESHOLD 45 +#define TBD_HIGH_THRESHOLD 65 +#define TBD_LOW_THRESHOLD 50 +#define WHITE_HIGH_THRESHOLD 70 +#define WHITE_LOW_THRESHOLD 55 +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +static ssize_t prox_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t prox_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +static ssize_t proximity_avg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", + data->buf[PROXIMITY_RAW].prox[1], + data->buf[PROXIMITY_RAW].prox[2], + data->buf[PROXIMITY_RAW].prox[3]); +} + +static ssize_t proximity_avg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + char chTempbuf[2] = { 1, 20}; + int iRet; + int64_t dEnable; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtoll(buf, 10, &dEnable); + if (iRet < 0) + return iRet; + + if (dEnable) { + send_instruction(data, ADD_SENSOR, PROXIMITY_RAW, chTempbuf, 2); + data->bProximityRawEnabled = true; + } else { + send_instruction(data, REMOVE_SENSOR, PROXIMITY_RAW, + chTempbuf, 2); + data->bProximityRawEnabled = false; + } + + return size; +} + +static unsigned char get_proximity_rawdata(struct ssp_data *data) +{ + unsigned char uRowdata = 0; + char chTempbuf[2] = { 1, 20}; + + if (data->bProximityRawEnabled == false) { + send_instruction(data, ADD_SENSOR, PROXIMITY_RAW, chTempbuf, 2); + msleep(200); + uRowdata = data->buf[PROXIMITY_RAW].prox[0]; + send_instruction(data, REMOVE_SENSOR, PROXIMITY_RAW, + chTempbuf, 2); + } else { + uRowdata = data->buf[PROXIMITY_RAW].prox[0]; + } + + return uRowdata; +} + +static ssize_t proximity_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", get_proximity_rawdata(data)); +} + +static ssize_t proximity_raw_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", get_proximity_rawdata(data)); +} + +static int get_proximity_threshold(struct ssp_data *data) +{ + if (data->uProxCanc <= (data->uProxLoThresh_default >> 1)) + return FAIL; + + data->uProxHiThresh = data->uProxHiThresh_default + + (data->uProxCanc - (data->uProxLoThresh_default >> 1)); + data->uProxLoThresh = data->uProxLoThresh_default + + (data->uProxCanc - (data->uProxLoThresh_default >> 1)); + + return SUCCESS; +} + +static void change_proximity_default_threshold(struct ssp_data *data) +{ + switch (data->chLcdLdi[1]) { + case LDI_GRAY: + data->uProxHiThresh_default = TBD_HIGH_THRESHOLD; + data->uProxLoThresh_default = TBD_LOW_THRESHOLD; + break; + case LDI_WHITE: + data->uProxHiThresh_default = WHITE_HIGH_THRESHOLD; + data->uProxLoThresh_default = WHITE_LOW_THRESHOLD; + break; + case LDI_OTHERS: + data->uProxHiThresh_default = DEFUALT_HIGH_THRESHOLD; + data->uProxLoThresh_default = DEFUALT_LOW_THRESHOLD; + break; + default: + data->uProxHiThresh_default = DEFUALT_HIGH_THRESHOLD; + data->uProxLoThresh_default = DEFUALT_LOW_THRESHOLD; + break; + } + data->uProxHiThresh = data->uProxHiThresh_default; + data->uProxLoThresh = data->uProxLoThresh_default; +} + +int proximity_open_lcd_ldi(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cancel_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cancel_filp)) { + iRet = PTR_ERR(cancel_filp); + if (iRet != -ENOENT) + pr_err("[SSP]: %s - Can't open lcd ldi file\n", + __func__); + set_fs(old_fs); + data->chLcdLdi[0] = 0; + data->chLcdLdi[1] = 0; + goto exit; + } + + iRet = cancel_filp->f_op->read(cancel_filp, + (u8 *)data->chLcdLdi, sizeof(u8) * 2, &cancel_filp->f_pos); + if (iRet != (sizeof(u8) * 2)) { + pr_err("[SSP]: %s - Can't read the lcd ldi data\n", __func__); + iRet = -EIO; + } + + ssp_dbg("[SSP]: %s - %c%c\n", __func__, + data->chLcdLdi[0], data->chLcdLdi[1]); + + filp_close(cancel_filp, current->files); + set_fs(old_fs); + +exit: + change_proximity_default_threshold(data); + return iRet; +} + +int proximity_open_calibration(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cancel_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(cancel_filp)) { + iRet = PTR_ERR(cancel_filp); + if (iRet != -ENOENT) + pr_err("[SSP]: %s - Can't open cancelation file\n", + __func__); + set_fs(old_fs); + goto exit; + } + + iRet = cancel_filp->f_op->read(cancel_filp, + (u8 *)&data->uProxCanc, sizeof(u8), &cancel_filp->f_pos); + if (iRet != sizeof(u8)) { + pr_err("[SSP]: %s - Can't read the cancel data\n", __func__); + iRet = -EIO; + } + + if (data->uProxCanc != 0) /* If there is an offset cal data. */ + get_proximity_threshold(data); + + pr_info("%s: proximity ps_canc = %d, ps_thresh hi - %d lo - %d\n", + __func__, data->uProxCanc, data->uProxHiThresh, + data->uProxLoThresh); + + filp_close(cancel_filp, current->files); + set_fs(old_fs); + +exit: + set_proximity_threshold(data, data->uProxHiThresh, data->uProxLoThresh); + + return iRet; +} + +static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cancel_filp = NULL; + + if (iCalCMD) { + data->uProxCanc = get_proximity_rawdata(data); + get_proximity_threshold(data); + } else { + data->uProxHiThresh = data->uProxHiThresh_default; + data->uProxLoThresh = data->uProxLoThresh_default; + data->uProxCanc = 0; + } + + set_proximity_threshold(data, data->uProxHiThresh, data->uProxLoThresh); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cancel_filp = filp_open(CANCELATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + if (IS_ERR(cancel_filp)) { + pr_err("%s: Can't open cancelation file\n", __func__); + set_fs(old_fs); + iRet = PTR_ERR(cancel_filp); + return iRet; + } + + iRet = cancel_filp->f_op->write(cancel_filp, (u8 *)&data->uProxCanc, + sizeof(u8), &cancel_filp->f_pos); + if (iRet != sizeof(u8)) { + pr_err("%s: Can't write the cancel data to file\n", __func__); + iRet = -EIO; + } + + filp_close(cancel_filp, current->files); + set_fs(old_fs); + + return iRet; +} + +static ssize_t proximity_cancel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + unsigned char uProxCanc = data->uProxCanc; + + if (uProxCanc > (data->uProxLoThresh_default >> 1)) + uProxCanc = uProxCanc - (data->uProxLoThresh_default >> 1); + else + uProxCanc = 0; + + ssp_dbg("[SSP]: uProxThresh : hi : %u lo : %u, uProxCanc = %u\n", + data->uProxHiThresh, data->uProxLoThresh, uProxCanc); + + return sprintf(buf, "%u,%u,%u\n", uProxCanc, data->uProxHiThresh, + data->uProxLoThresh); +} + +static ssize_t proximity_cancel_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int iCalCMD = 0, iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "1")) /* calibrate cancelation value */ + iCalCMD = 1; + else if (sysfs_streq(buf, "0")) /* reset cancelation value */ + iCalCMD = 0; + else { + pr_debug("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + iRet = proximity_store_cancelation(data, iCalCMD); + if (iRet < 0) { + pr_err("[SSP]: - %s proximity_store_cancelation() failed\n", + __func__); + return iRet; + } + + ssp_dbg("[SSP]: %s - %u\n", __func__, iCalCMD); + return size; +} + +static ssize_t proximity_thresh_high_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: uProxThresh = hi - %u, lo - %u\n", + data->uProxHiThresh, data->uProxLoThresh); + + return sprintf(buf, "%u,%u\n", data->uProxHiThresh, + data->uProxLoThresh); +} + +static ssize_t proximity_thresh_high_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 uNewThresh; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtou8(buf, 10, &uNewThresh); + if (iRet < 0) + pr_err("[SSP]: %s - kstrtoint failed.(%d)\n", __func__, iRet); + else { + data->uProxHiThresh = uNewThresh; + set_proximity_threshold(data, data->uProxHiThresh, + data->uProxLoThresh); + } + + ssp_dbg("[SSP]: %s - new prox threshold : hi - %u, lo - %u\n", + __func__, data->uProxHiThresh, data->uProxLoThresh); + + return size; +} + +static ssize_t proximity_thresh_low_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: uProxThresh = hi - %u, lo - %u\n", + data->uProxHiThresh, data->uProxLoThresh); + + return sprintf(buf, "%u,%u\n", data->uProxHiThresh, + data->uProxLoThresh); +} + +static ssize_t proximity_thresh_low_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 uNewThresh; + int iRet = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtou8(buf, 10, &uNewThresh); + if (iRet < 0) + pr_err("[SSP]: %s - kstrtoint failed.(%d)\n", __func__, iRet); + else { + data->uProxLoThresh = uNewThresh; + set_proximity_threshold(data, data->uProxHiThresh, + data->uProxLoThresh); + } + + ssp_dbg("[SSP]: %s - new prox threshold : hi - %u, lo - %u\n", + __func__, data->uProxHiThresh, data->uProxLoThresh); + + return size; +} + +static ssize_t barcode_emul_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", data->bBarcodeEnabled); +} + +static ssize_t barcode_emul_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int iRet; + int64_t dEnable; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtoll(buf, 10, &dEnable); + if (iRet < 0) + return iRet; + + if (dEnable) + set_proximity_barcode_enable(data, true); + else + set_proximity_barcode_enable(data, false); + + return size; +} + +static DEVICE_ATTR(vendor, S_IRUGO, prox_vendor_show, NULL); +static DEVICE_ATTR(name, S_IRUGO, prox_name_show, NULL); +static DEVICE_ATTR(state, S_IRUGO, proximity_state_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, proximity_raw_data_show, NULL); +static DEVICE_ATTR(barcode_emul_en, S_IRUGO | S_IWUSR | S_IWGRP, + barcode_emul_enable_show, barcode_emul_enable_store); +static DEVICE_ATTR(prox_avg, S_IRUGO | S_IWUSR | S_IWGRP, + proximity_avg_show, proximity_avg_store); +static DEVICE_ATTR(prox_cal, S_IRUGO | S_IWUSR | S_IWGRP, + proximity_cancel_show, proximity_cancel_store); +static DEVICE_ATTR(thresh_high, S_IRUGO | S_IWUSR | S_IWGRP, + proximity_thresh_high_show, proximity_thresh_high_store); +static DEVICE_ATTR(thresh_low, S_IRUGO | S_IWUSR | S_IWGRP, + proximity_thresh_low_show, proximity_thresh_low_store); + +static struct device_attribute *prox_attrs[] = { + &dev_attr_vendor, + &dev_attr_name, + &dev_attr_state, + &dev_attr_raw_data, + &dev_attr_prox_avg, + &dev_attr_prox_cal, + &dev_attr_thresh_high, + &dev_attr_thresh_low, + &dev_attr_barcode_emul_en, + NULL, +}; + +void initialize_prox_factorytest(struct ssp_data *data) +{ + sensors_register(data->prox_device, data, + prox_attrs, "proximity_sensor"); +} + +void remove_prox_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->prox_device, prox_attrs); +} diff --git a/drivers/sensorhub/stm/factory/temphumidity_shtc1.c b/drivers/sensorhub/stm/factory/temphumidity_shtc1.c new file mode 100755 index 00000000000..45e0ea583a0 --- /dev/null +++ b/drivers/sensorhub/stm/factory/temphumidity_shtc1.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" +#include +#include + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "SENSIRION" +#define CHIP_ID "SHTC1" + +#define CP_THM_ADC_SAMPLING_CNT 7 +//#define DONE_CAL 3 + +static int cp_thm_get_adc_data(struct ssp_data *data) +{ + int adc_data; + int adc_max = 0; + int adc_min = 0; + int adc_total = 0; + int i; + int err_value; + + for (i = 0; i < CP_THM_ADC_SAMPLING_CNT; i++) { + mutex_lock(&data->cp_temp_adc_lock); + if (data->adc_client) + adc_data = s3c_adc_read(data->adc_client, data->cp_thm_adc_channel); + else + adc_data = 0; + mutex_unlock(&data->cp_temp_adc_lock); + + if (adc_data < 0) { + pr_err("[SSP] : %s err(%d) returned, skip read\n", + __func__, adc_data); + err_value = adc_data; + goto err; + } + + if (i != 0) { + if (adc_data > adc_max) + adc_max = adc_data; + else if (adc_data < adc_min) + adc_min = adc_data; + } else { + adc_max = adc_data; + adc_min = adc_data; + } + adc_total += adc_data; + } + + return (adc_total - adc_max - adc_min) / (CP_THM_ADC_SAMPLING_CNT - 2); +err: + return err_value; +} + +static int convert_adc_to_temp(struct ssp_data *data, unsigned int adc) +{ + u8 low = 0, mid = 0; + u8 high; + + if (!data->cp_thm_adc_table || !data->cp_thm_adc_arr_size) { + /* using fake temp */ + return 300; + } + + high = data->cp_thm_adc_arr_size - 1; + + while (low <= high) { + mid = (low + high) / 2; + if (data->cp_thm_adc_table[mid].adc > adc) + high = mid - 1; + else if (data->cp_thm_adc_table[mid].adc < adc) + low = mid + 1; + else + break; + } + return data->cp_thm_adc_table[mid].temperature; +} + +static ssize_t temphumidity_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t temphumidity_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +static ssize_t engine_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + pr_err("[SSP] %s - engine_ver = %s_%s\n", + __func__, CONFIG_SENSORS_SSP_SHTC1_VER, data->comp_engine_ver); + + return sprintf(buf, "%s_%s\n", + CONFIG_SENSORS_SSP_SHTC1_VER, data->comp_engine_ver); +} + +ssize_t engine_version_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + kfree(data->comp_engine_ver); + data->comp_engine_ver = + kzalloc(((strlen(buf)+1) * sizeof(char)), GFP_KERNEL); + strncpy(data->comp_engine_ver, buf, strlen(buf)+1); + pr_err("[SSP] %s - engine_ver = %s, %s\n", + __func__, data->comp_engine_ver, buf); + + return size; +} + +static ssize_t pam_adc_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + int cp_thm_adc = 0; + + if (data->bSspShutdown == false) + cp_thm_adc = cp_thm_get_adc_data(data); + else + pr_info("[SSP] : %s, device is shutting down", __func__); + + return sprintf(buf, "%d\n", cp_thm_adc); +} + +static ssize_t pam_temp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + int adc, temp; + +#if defined(CONFIG_MACH_J_CHN_CTC) + printk("[SSP] pam_temp_show : %d", data->ap_rev); + if((data->ap_rev) < 7) /* HW REV12 == 7*/ + temp = -990; + else + { +#endif + adc = cp_thm_get_adc_data(data); + if (adc < 0) { + pr_err("[SSP] : %s, reading adc failed.(%d)\n", __func__, adc); + temp = adc; + } else + temp = convert_adc_to_temp(data, adc); + +#if defined(CONFIG_MACH_J_CHN_CTC) + } +#endif + + return sprintf(buf, "%d\n", temp); +} + +static ssize_t temphumidity_crc_check(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char chTempBuf[2] = {0, 10}; + int iDelayCnt = 0, iRet; + struct ssp_data *data = dev_get_drvdata(dev); + + data->uFactorydata[0] = 0xff; + data->uFactorydataReady = 0; + iRet = send_instruction(data, FACTORY_MODE, + TEMPHUMIDITY_CRC_FACTORY, chTempBuf, 2); + + while (!(data->uFactorydataReady & + (1 << TEMPHUMIDITY_CRC_FACTORY)) + && (iDelayCnt++ < 50) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 50) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Temphumidity check crc Timeout!! %d\n", + __func__, iRet); + goto exit; + } + + mdelay(5); + + pr_info("[SSP] : %s -Check_CRC : %d\n", __func__, + data->uFactorydata[0]); + +exit: + if (data->uFactorydata[0] == 1) + return sprintf(buf, "%s\n", "OK"); + else if (data->uFactorydata[0] == 2) + return sprintf(buf, "%s\n","NG_NC"); + else + return sprintf(buf, "%s\n","NG"); +} + +static ssize_t temphumidity_compengine_reset(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + data->comp_engine_cmd = SHTC1_CMD_RESET; + + return sprintf(buf, "%d\n", 1); +} +/* +ssize_t temphumidity_send_accuracy(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct ssp_data *data = dev_get_drvdata(dev); + u8 accuracy; + + if (kstrtou8(buf, 10, &accuracy) < 0) { + pr_err("[SSP] %s - read buf is fail(%s)\n", __func__, buf); + return size; + } + + if (accuracy == DONE_CAL) + ssp_send_cmd(data, MSG2SSP_AP_TEMPHUMIDITY_CAL_DONE); + pr_info("[SSP] %s - accuracy = %d\n", __func__, accuracy); + + return size; +} +*/ +static DEVICE_ATTR(name, S_IRUGO, temphumidity_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, temphumidity_vendor_show, NULL); +static DEVICE_ATTR(engine_ver, S_IRUGO | S_IWUSR | S_IWGRP, + engine_version_show, engine_version_store); +static DEVICE_ATTR(cp_thm, S_IRUGO, + pam_adc_show, NULL); +static DEVICE_ATTR(cp_temperature, S_IRUGO, + pam_temp_show, NULL); +static DEVICE_ATTR(crc_check, S_IRUGO, + temphumidity_crc_check, NULL); +static DEVICE_ATTR(reset, S_IRUGO, + temphumidity_compengine_reset, NULL); +/*static DEVICE_ATTR(send_accuracy, S_IWUSR | S_IWGRP, + NULL, temphumidity_send_accuracy);*/ + +static struct device_attribute *temphumidity_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_engine_ver, + &dev_attr_cp_thm, + &dev_attr_cp_temperature, + &dev_attr_crc_check, + &dev_attr_reset, +// &dev_attr_send_accuracy, + NULL, +}; + +void initialize_temphumidity_factorytest(struct ssp_data *data) +{ + /* alloc platform device for adc client */ + data->pdev_pam_temp = platform_device_alloc("pam-temp-adc", -1); + if (!data->pdev_pam_temp) + pr_err("%s: could not allocation pam-temp-adc\n", __func__); + + data->adc_client = s3c_adc_register(data->pdev_pam_temp, NULL, NULL, 0); + if (IS_ERR(data->adc_client)) + pr_err("%s, fail to register pam-temp-adc(%ld)\n", + __func__, IS_ERR(data->adc_client)); + + sensors_register(data->temphumidity_device, + data, temphumidity_attrs, "temphumidity_sensor"); +} + +void remove_temphumidity_factorytest(struct ssp_data *data) +{ + if (data->adc_client) + s3c_adc_release(data->adc_client); + if (data->pdev_pam_temp) + platform_device_put(data->pdev_pam_temp); + sensors_unregister(data->temphumidity_device, temphumidity_attrs); + kfree(data->comp_engine_ver); +} diff --git a/drivers/sensorhub/stm/sensors_core.c b/drivers/sensorhub/stm/sensors_core.c new file mode 100755 index 00000000000..2e64ee34325 --- /dev/null +++ b/drivers/sensorhub/stm/sensors_core.c @@ -0,0 +1,173 @@ +/* + * Universal sensors core class + * + * Author : Ryunkyun Park + */ + +#include +#include +#include +#include +#include +#include + +struct class *sensors_class; +EXPORT_SYMBOL_GPL(sensors_class); +struct class *sensors_event_class; +EXPORT_SYMBOL_GPL(sensors_event_class); +static atomic_t sensor_count; +static struct device *symlink_dev; + +/* + * Create sysfs interface + */ +static void set_sensor_attr(struct device *dev, + struct device_attribute *attributes[]) +{ + int i; + + for (i = 0; attributes[i] != NULL; i++) + if ((device_create_file(dev, attributes[i])) < 0) + pr_err("[SENSOR CORE] fail device_create_file"\ + "(dev, attributes[%d])\n", i); +} + +int sensors_create_symlink(struct kobject *target, + const char *name) +{ + int err = 0; + + if (symlink_dev == NULL) { + pr_err("%s, symlink_dev is NULL!!!\n", __func__); + return err ; + } + + err = sysfs_create_link(&symlink_dev->kobj, target, name); + + if (err < 0) { + pr_err("%s, %s failed!(%d)\n", __func__, name, err); + return err; + } + + return err; +} +EXPORT_SYMBOL_GPL(sensors_create_symlink); + +void sensors_remove_symlink(struct kobject *target, + const char *name) +{ + + if (symlink_dev == NULL) { + pr_err("%s, symlink_dev is NULL!!!\n", __func__); + return; + } + + sysfs_delete_link(&symlink_dev->kobj, target, name); +} +EXPORT_SYMBOL_GPL(sensors_remove_symlink); + + +int sensors_register(struct device *dev, void *drvdata, + struct device_attribute *attributes[], char *name) +{ + int ret = 0; + + if (!sensors_class) { + sensors_class = class_create(THIS_MODULE, "sensors"); + if (IS_ERR(sensors_class)) + return PTR_ERR(sensors_class); + } + + dev = device_create(sensors_class, NULL, 0, drvdata, "%s", name); + + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + pr_err("[SENSORS CORE] device_create failed!"\ + "[%d]\n", ret); + return ret; + } + + set_sensor_attr(dev, attributes); + atomic_inc(&sensor_count); + + return 0; +} +EXPORT_SYMBOL_GPL(sensors_register); + +void sensors_unregister(struct device *dev, + struct device_attribute *attributes[]) +{ + int i; + + for (i = 0; attributes[i] != NULL; i++) + device_remove_file(dev, attributes[i]); +} +EXPORT_SYMBOL_GPL(sensors_unregister); + +void destroy_sensor_class(void) +{ + if (sensors_class) { + class_destroy(sensors_class); + sensors_class = NULL; + } + + if (sensors_event_class) { + device_destroy(sensors_event_class, symlink_dev->devt); + class_destroy(sensors_event_class); + symlink_dev = NULL; + sensors_event_class = NULL; + } +} +EXPORT_SYMBOL_GPL(destroy_sensor_class); + +static int __init sensors_class_init(void) +{ + pr_info("[SENSORS CORE] sensors_class_init\n"); + sensors_class = class_create(THIS_MODULE, "sensors"); + + if (IS_ERR(sensors_class)) { + pr_err("%s, create sensors_class is failed.(err=%ld)\n", + __func__, IS_ERR(sensors_class)); + return PTR_ERR(sensors_class); + } + + /* For symbolic link */ + sensors_event_class = class_create(THIS_MODULE, "sensor_event"); + if (IS_ERR(sensors_event_class)) { + pr_err("%s, create sensors_class is failed.(err=%ld)\n", + __func__, IS_ERR(sensors_event_class)); + return PTR_ERR(sensors_event_class); + } + + symlink_dev = device_create(sensors_event_class, NULL, 0, NULL, + "%s", "symlink"); + + if (IS_ERR(symlink_dev)) { + pr_err("[SENSORS CORE] symlink_dev create failed!"\ + "[%ld]\n", IS_ERR(symlink_dev)); + return PTR_ERR(symlink_dev); + } + + atomic_set(&sensor_count, 0); + sensors_class->dev_uevent = NULL; + pr_info("[SENSORS CORE] sensors_class_init succcess\n"); + + return 0; +} + +static void __exit sensors_class_exit(void) +{ + if (sensors_class || sensors_event_class) { + class_destroy(sensors_class); + sensors_class = NULL; + class_destroy(sensors_event_class); + sensors_event_class = NULL; + } +} + +subsys_initcall(sensors_class_init); +module_exit(sensors_class_exit); + +MODULE_DESCRIPTION("Universal sensors core class"); +MODULE_AUTHOR("Ryunkyun Park "); +MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/stm/ssp.h b/drivers/sensorhub/stm/ssp.h new file mode 100755 index 00000000000..bb0cb61c9c8 --- /dev/null +++ b/drivers/sensorhub/stm/ssp.h @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2011, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SSP_PRJ_H__ +#define __SSP_PRJ_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +#undef CONFIG_HAS_EARLYSUSPEND +#endif + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB +#include "ssp_sensorhub.h" +#endif + +#define SSP_DBG 1 + +#define SUCCESS 1 +#define FAIL 0 +#define ERROR -1 + +/* + 1. ACCEL : 6 Bytes + 2. GYRO : 6 Bytes + 3. MAGNETIC : 6 Bytes + 4. PRESSURE : 5 Bytes + 5. GESTURE : 4 Bytes + 6. PROXIMITY : 2 Bytes + 7. TEMPHUMI : 5 Bytes + 8. LIGHT : 8 Bytes + SUM : 42 Bytes + Total : 42 + 8(index) = 50 Bytes +*/ +#define FACTORY_DATA_MAX 63 +#if SSP_DBG +#define SSP_FUNC_DBG 1 +#define SSP_DATA_DBG 0 + +#define ssp_dbg(dev, format, ...) do { \ + printk(KERN_INFO dev, format, ##__VA_ARGS__); \ + } while (0) +#else +#define ssp_dbg(dev, format, ...) +#endif + +#if SSP_FUNC_DBG +#define func_dbg() do { \ + printk(KERN_INFO "[SSP]: %s\n", __func__); \ + } while (0) +#else +#define func_dbg() +#endif + +#if SSP_DATA_DBG +#define data_dbg(dev, format, ...) do { \ + printk(KERN_INFO dev, format, ##__VA_ARGS__); \ + } while (0) +#else +#define data_dbg(dev, format, ...) +#endif + +#define SSP_SW_RESET_TIME 3000 +#define DEFUALT_POLLING_DELAY (200 * NSEC_PER_MSEC) +#define PROX_AVG_READ_NUM 80 +#define DEFAULT_RETRIES 3 + +/* SSP Binary Type */ +enum { + KERNEL_BINARY = 0, + KERNEL_CRASHED_BINARY, + UMS_BINARY, +}; + +/* Sensor Sampling Time Define */ +enum { + SENSOR_NS_DELAY_FASTEST = 10000000, /* 10msec */ + SENSOR_NS_DELAY_GAME = 20000000, /* 20msec */ + SENSOR_NS_DELAY_UI = 66700000, /* 66.7msec */ + SENSOR_NS_DELAY_NORMAL = 200000000, /* 200msec */ +}; + +enum { + SENSOR_MS_DELAY_FASTEST = 10, /* 10msec */ + SENSOR_MS_DELAY_GAME = 20, /* 20msec */ + SENSOR_MS_DELAY_UI = 66, /* 66.7msec */ + SENSOR_MS_DELAY_NORMAL = 200, /* 200msec */ +}; + +enum { + SENSOR_CMD_DELAY_FASTEST = 0, /* 10msec */ + SENSOR_CMD_DELAY_GAME, /* 20msec */ + SENSOR_CMD_DELAY_UI, /* 66.7msec */ + SENSOR_CMD_DELAY_NORMAL, /* 200msec */ +}; + +/* + * SENSOR_DELAY_SET_STATE + * Check delay set to avoid sending ADD instruction twice + */ +enum { + INITIALIZATION_STATE = 0, + NO_SENSOR_STATE, + ADD_SENSOR_STATE, + RUNNING_SENSOR_STATE, +}; + +/* Firmware download STATE */ +enum { + FW_DL_STATE_FAIL = -1, + FW_DL_STATE_NONE = 0, + FW_DL_STATE_NEED_TO_SCHEDULE, + FW_DL_STATE_SCHEDULED, + FW_DL_STATE_DOWNLOADING, + FW_DL_STATE_SYNC, + FW_DL_STATE_DONE, +}; + +#define SSP_INVALID_REVISION 99999 + +/* Gyroscope DPS */ +#define GYROSCOPE_DPS250 250 +#define GYROSCOPE_DPS500 500 +#define GYROSCOPE_DPS2000 2000 + +/* Gesture Sensor Current */ +#define DEFUALT_IR_CURRENT 400 //0xF2 + +/* kernel -> ssp manager cmd*/ +#define SSP_LIBRARY_SLEEP_CMD (1 << 5) +#define SSP_LIBRARY_LARGE_DATA_CMD (1 << 6) +#define SSP_LIBRARY_WAKEUP_CMD (1 << 7) + +/* ioctl command */ +#define AKMIO 0xA1 +#define ECS_IOCTL_GET_FUSEROMDATA _IOR(AKMIO, 0x01, unsigned char[3]) +#define ECS_IOCTL_GET_MAGDATA _IOR(AKMIO, 0x02, unsigned char[8]) +#define ECS_IOCTL_GET_ACCDATA _IOR(AKMIO, 0x03, int[3]) + +/* AP -> SSP Instruction */ +#define MSG2SSP_INST_BYPASS_SENSOR_ADD 0xA1 +#define MSG2SSP_INST_BYPASS_SENSOR_REMOVE 0xA2 +#define MSG2SSP_INST_REMOVE_ALL 0xA3 +#define MSG2SSP_INST_CHANGE_DELAY 0xA4 +#define MSG2SSP_INST_SENSOR_SELFTEST 0xA8 +#define MSG2SSP_INST_LIBRARY_ADD 0xB1 +#define MSG2SSP_INST_LIBRARY_REMOVE 0xB2 +#define MSG2SSP_INST_LIB_NOTI 0xB4 + +#define MSG2SSP_AP_STT 0xC8 +#define MSG2SSP_AP_STATUS_WAKEUP 0xD1 +#define MSG2SSP_AP_STATUS_SLEEP 0xD2 +#define MSG2SSP_AP_STATUS_RESUME 0xD3 +#define MSG2SSP_AP_STATUS_SUSPEND 0xD4 +#define MSG2SSP_AP_STATUS_RESET 0xD5 +#define MSG2SSP_AP_STATUS_POW_CONNECTED 0xD6 +#define MSG2SSP_AP_STATUS_POW_DISCONNECTED 0xD7 +#define MSG2SSP_AP_STATUS_CALL_IDLE 0xD8 +#define MSG2SSP_AP_STATUS_CALL_ACTIVE 0xD9 +#define MSG2SSP_AP_TEMPHUMIDITY_CAL_DONE 0xDA + +#define MSG2SSP_AP_WHOAMI 0x0F +#define MSG2SSP_AP_FIRMWARE_REV 0xF0 +#define MSG2SSP_AP_SENSOR_FORMATION 0xF1 +#define MSG2SSP_AP_SENSOR_PROXTHRESHOLD 0xF2 +#define MSG2SSP_AP_SENSOR_BARCODE_EMUL 0xF3 +#define MSG2SSP_AP_SENSOR_SCANNING 0xF4 +#define MSG2SSP_AP_SET_MAGNETIC_HWOFFSET 0xF5 +#define MSG2SSP_AP_GET_MAGNETIC_HWOFFSET 0xF6 +#define MSG2SSP_AP_SENSOR_GESTURE_CURRENT 0xF7 + +#define MSG2SSP_AP_FUSEROM 0X01 + +/* AP -> SSP Data Protocol Frame Field */ +#define MSG2SSP_SSP_SLEEP 0xC1 +#define MSG2SSP_STS 0xC2 /* Start to Send */ +#define MSG2SSP_RTS 0xC4 /* Ready to Send */ +#define MSG2SSP_STT 0xC8 +#define MSG2SSP_SRM 0xCA /* Start to Read MSG */ +#define MSG2SSP_SSM 0xCB /* Start to Send MSG */ +#define MSG2SSP_SSD 0xCE /* Start to Send Data Type & Length */ +#define MSG2SSP_NO_DATA 0xCF /* There is no data to get from MCU */ + +/* SSP -> AP ACK about write CMD */ +#define MSG_ACK 0x80 /* ACK from SSP to AP */ +#define MSG_NAK 0x70 /* NAK from SSP to AP */ + +/* Accelerometer sensor*/ +/* 16bits */ +#define MAX_ACCEL_1G 16384 +#define MAX_ACCEL_2G 32767 +#define MIN_ACCEL_2G -32768 +#define MAX_ACCEL_4G 65536 + +#define MAX_GYRO 32767 +#define MIN_GYRO -32768 + +/* sensor combination, data->sns_combination */ +enum { + INVENSENSE_MPU6500_AG = 0, + STM_K330_AG, +}; + +/* SSP_INSTRUCTION_CMD */ +enum { + REMOVE_SENSOR = 0, + ADD_SENSOR, + CHANGE_DELAY, + GO_SLEEP, + FACTORY_MODE, + REMOVE_LIBRARY, + ADD_LIBRARY, +}; + +/* SENSOR_TYPE */ +enum { + ACCELEROMETER_SENSOR = 0, + GYROSCOPE_SENSOR, + GEOMAGNETIC_SENSOR, + PRESSURE_SENSOR, + GESTURE_SENSOR, + PROXIMITY_SENSOR, + TEMPERATURE_HUMIDITY_SENSOR, + LIGHT_SENSOR, + PROXIMITY_RAW, + GEOMAGNETIC_RAW, + ORIENTATION_SENSOR, + SENSOR_MAX, +}; + +#define SSP_BYPASS_SENSORS_EN_ALL (1 << ACCELEROMETER_SENSOR |\ + 1 << GYROSCOPE_SENSOR | 1 << GEOMAGNETIC_SENSOR | 1 << PRESSURE_SENSOR |\ + 1 << TEMPERATURE_HUMIDITY_SENSOR | 1 << LIGHT_SENSOR) + /* Proximity sensor is not continuous */ + +/* SENSOR_FACTORY_MODE_TYPE */ +enum { + ACCELEROMETER_FACTORY = 0, + GYROSCOPE_FACTORY, + GEOMAGNETIC_FACTORY, + PRESSURE_FACTORY, + MCU_FACTORY, + GYROSCOPE_TEMP_FACTORY, + GYROSCOPE_DPS_FACTORY, + MCU_SLEEP_FACTORY, + GESTURE_FACTORY, + TEMPHUMIDITY_CRC_FACTORY, + SENSOR_FACTORY_MAX, +}; + +enum { + SHTC1_CMD_NONE, + SHTC1_CMD_RESET, +}; + +struct sensor_value { + union { + struct { + s16 x; + s16 y; + s16 z; + }; + struct { + u16 r; + u16 g; + u16 b; + u16 w; + }; + u8 prox[4]; + s16 data[9]; + s32 pressure[3]; + }; +}; + +extern struct class *sensors_event_class; + +struct calibraion_data { + s16 x; + s16 y; + s16 z; +}; + +struct hw_offset_data { + char x; + char y; + char z; +}; + +struct ssp_data { + struct input_dev *acc_input_dev; + struct input_dev *gyro_input_dev; + struct input_dev *mag_input_dev; + struct input_dev *gesture_input_dev; + struct input_dev *pressure_input_dev; + struct input_dev *light_input_dev; + struct input_dev *prox_input_dev; + struct input_dev *temp_humi_input_dev; + + struct device *mcu_device; + struct device *acc_device; + struct device *gyro_device; + struct device *mag_device; + struct device *prs_device; + struct device *prox_device; + struct device *light_device; + struct device *ges_device; + struct device *temphumidity_device; + +#ifdef CONFIG_SENSORS_SSP_STM + struct spi_device *spi; +#endif + + struct wake_lock ssp_wake_lock; + struct miscdevice akmd_device; + struct timer_list debug_timer; + struct workqueue_struct *debug_wq; + struct delayed_work work_firmware; + struct work_struct work_debug; + struct calibraion_data accelcal; + struct calibraion_data gyrocal; + struct hw_offset_data magoffset; + struct sensor_value buf[SENSOR_MAX]; + + bool bSspShutdown; + bool bCheckSuspend; + bool bDebugEnabled; + bool bMcuIRQTestSuccessed; + bool bAccelAlert; + bool bProximityRawEnabled; + bool bGeomagneticRawEnabled; + bool bBarcodeEnabled; + bool bBinaryChashed; + bool bProbeIsDone; + + unsigned char uProxCanc; + unsigned char uProxHiThresh; + unsigned char uProxLoThresh; + unsigned char uProxHiThresh_default; + unsigned char uProxLoThresh_default; + unsigned int uIr_Current; + unsigned char uFuseRomData[3]; + unsigned char uFactorydata[FACTORY_DATA_MAX]; + char *pchLibraryBuf; + char chLcdLdi[2]; + int iIrq; + int iLibraryLength; + int aiCheckStatus[SENSOR_MAX]; + + unsigned int uIrqFailCnt; + unsigned int uSsdFailCnt; + unsigned int uResetCnt; + unsigned int uInstFailCnt; + unsigned int uTimeOutCnt; + unsigned int uIrqCnt; + unsigned int uBusyCnt; + unsigned int uMissSensorCnt; + + unsigned int uGyroDps; + unsigned int uSensorState; + unsigned int uCurFirmRev; + unsigned int uFactoryProxAvg[4]; + unsigned int uFactorydataReady; + s32 iPressureCal; + unsigned int uTempCount; + + atomic_t aSensorEnable; + int64_t adDelayBuf[SENSOR_MAX]; + + int (*wakeup_mcu)(void); + int (*check_mcu_ready)(void); + int (*check_mcu_busy)(void); + int (*set_mcu_reset)(int); + int (*read_chg)(void); + void (*get_sensor_data[SENSOR_MAX])(char *, int *, + struct sensor_value *); + void (*report_sensor_data[SENSOR_MAX])(struct ssp_data *, + struct sensor_value *); + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + struct ssp_sensorhub_data *hub_data; +#endif + int ap_rev; + int ssp_changes; + int accel_position; + int mag_position; + int fw_dl_state; +#ifdef CONFIG_SENSORS_SSP_SHTC1 + char *comp_engine_ver; + struct platform_device *pdev_pam_temp; + struct s3c_adc_client *adc_client; + u8 cp_thm_adc_channel; + u8 cp_thm_adc_arr_size; + struct cp_thm_adc_table *cp_thm_adc_table; + struct mutex cp_temp_adc_lock; +#endif + u8 comp_engine_cmd; + struct mutex comm_mutex; +}; + +void ssp_enable(struct ssp_data *, bool); +int waiting_init_mcu(struct ssp_data *); +int waiting_wakeup_mcu(struct ssp_data *); +int ssp_read_data(struct ssp_data *, char *, u16, char *, u16, int); +void toggle_mcu_reset(struct ssp_data *); +int initialize_mcu(struct ssp_data *); +int initialize_input_dev(struct ssp_data *); +int initialize_sysfs(struct ssp_data *); +void initialize_accel_factorytest(struct ssp_data *); +void initialize_prox_factorytest(struct ssp_data *); +void initialize_light_factorytest(struct ssp_data *); +void initialize_gyro_factorytest(struct ssp_data *); +void initialize_pressure_factorytest(struct ssp_data *); +void initialize_magnetic_factorytest(struct ssp_data *); +void initialize_function_pointer(struct ssp_data *); +void initialize_magnetic(struct ssp_data *); +void initialize_gesture_factorytest(struct ssp_data *data); +void initialize_temphumidity_factorytest(struct ssp_data *data); +void remove_accel_factorytest(struct ssp_data *); +void remove_gyro_factorytest(struct ssp_data *); +void remove_prox_factorytest(struct ssp_data *); +void remove_light_factorytest(struct ssp_data *); +void remove_pressure_factorytest(struct ssp_data *); +void remove_magnetic_factorytest(struct ssp_data *); +void remove_gesture_factorytest(struct ssp_data *data); +void remove_temphumidity_factorytest(struct ssp_data *data); +void remove_magnetic(struct ssp_data *data); +void sensors_remove_symlink(struct kobject *target, + const char *name); +void destroy_sensor_class(void); +int initialize_event_symlink(struct ssp_data *); +int sensors_create_symlink(struct kobject *target, + const char *name); +int accel_open_calibration(struct ssp_data *); +int gyro_open_calibration(struct ssp_data *); +int pressure_open_calibration(struct ssp_data *); +int proximity_open_calibration(struct ssp_data *); +int check_fwbl(struct ssp_data *); +void remove_input_dev(struct ssp_data *); +void remove_sysfs(struct ssp_data *); +void remove_event_symlink(struct ssp_data *); +int ssp_sleep_mode(struct ssp_data *); +int ssp_resume_mode(struct ssp_data *); +int ssp_ap_suspend(struct ssp_data *); +int ssp_ap_resume(struct ssp_data *); +int send_instruction(struct ssp_data *, u8, u8, u8 *, u8); +int ssp_send_cmd(struct ssp_data *, char); +int select_irq_msg(struct ssp_data *); +int get_chipid(struct ssp_data *); +int get_fuserom_data(struct ssp_data *); +int mag_open_hwoffset(struct ssp_data *); +int mag_store_hwoffset(struct ssp_data *); +int set_hw_offset(struct ssp_data *); +int get_hw_offset(struct ssp_data *); +int set_sensor_position(struct ssp_data *); +void sync_sensor_state(struct ssp_data *); +void set_proximity_threshold(struct ssp_data *, unsigned char, unsigned char); +void set_proximity_barcode_enable(struct ssp_data *, bool); +void set_gesture_current(struct ssp_data *, unsigned char); +unsigned int get_delay_cmd(u8); +unsigned int get_msdelay(int64_t); +unsigned int get_sensor_scanning_info(struct ssp_data *); +unsigned int get_firmware_rev(struct ssp_data *); +int forced_to_download_binary(struct ssp_data *, int); +int parse_dataframe(struct ssp_data *, char *, int); +void enable_debug_timer(struct ssp_data *); +void disable_debug_timer(struct ssp_data *); +int initialize_debug_timer(struct ssp_data *); +int proximity_open_lcd_ldi(struct ssp_data *); +void report_acc_data(struct ssp_data *, struct sensor_value *); +void report_gyro_data(struct ssp_data *, struct sensor_value *); +void report_mag_data(struct ssp_data *, struct sensor_value *); +void report_gesture_data(struct ssp_data *, struct sensor_value *); +void report_pressure_data(struct ssp_data *, struct sensor_value *); +void report_light_data(struct ssp_data *, struct sensor_value *); +void report_prox_data(struct ssp_data *, struct sensor_value *); +void report_prox_raw_data(struct ssp_data *, struct sensor_value *); +void report_geomagnetic_raw_data(struct ssp_data *, struct sensor_value *); +int print_mcu_debug(char *, int *, int); +void report_temp_humidity_data(struct ssp_data *, struct sensor_value *); +unsigned int get_module_rev(struct ssp_data *data); +void reset_mcu(struct ssp_data *); +void convert_acc_data(s16 *); +int sensors_register(struct device *, void *, + struct device_attribute*[], char *); +void sensors_unregister(struct device *, + struct device_attribute*[]); +ssize_t mcu_reset_show(struct device *, struct device_attribute *, char *); +ssize_t mcu_revision_show(struct device *, struct device_attribute *, char *); +ssize_t mcu_update_ums_bin_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_update_kernel_bin_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_update_kernel_crashed_bin_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_factorytest_store(struct device *, struct device_attribute *, + const char *, size_t); +ssize_t mcu_factorytest_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_model_name_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_sleep_factorytest_show(struct device *, + struct device_attribute *, char *); +ssize_t mcu_sleep_factorytest_store(struct device *, + struct device_attribute *, const char *, size_t); +ssize_t mpu6500_gyro_selftest(char *, struct ssp_data *); +ssize_t k330_gyro_selftest(char *, struct ssp_data *); +int ssp_spi_read(struct spi_device *, u8 *, size_t, const int); +int ssp_spi_write(struct spi_device *, const u8 *, const int, const int); +int ssp_spi_write_sync(struct spi_device *, const u8 *, const int); +int ssp_spi_read_sync(struct spi_device *, u8 *, size_t); +int ssp_spi_sync(struct spi_device *, u8 *, size_t,u8 *); +int ssp_spi_async(struct spi_device *, u8 *, size_t,u8 *); +#endif diff --git a/drivers/sensorhub/stm/ssp_comm.c b/drivers/sensorhub/stm/ssp_comm.c new file mode 100755 index 00000000000..e01548652cb --- /dev/null +++ b/drivers/sensorhub/stm/ssp_comm.c @@ -0,0 +1,898 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include "ssp.h" + +#define LIMIT_DELAY_CNT 200 +#define RECEIVEBUFFERSIZE 12 +#define DEBUG_SHOW_DATA 0 + +int waiting_wakeup_mcu(struct ssp_data *data) +{ + int iDelaycnt = 0; + + while (!data->check_mcu_busy() && (iDelaycnt++ < LIMIT_DELAY_CNT) + && (data->bSspShutdown == false)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Irq Timeout!!\n", __func__); + data->uBusyCnt++; + } else { + data->uBusyCnt = 0; + } + + iDelaycnt = 0; + data->wakeup_mcu(); + while (!data->check_mcu_ready() && (iDelaycnt++ < LIMIT_DELAY_CNT) + && (data->bSspShutdown == false)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Wakeup Timeout!!\n", __func__); + data->uTimeOutCnt++; + } else { + data->uTimeOutCnt = 0; + } + + if (data->bSspShutdown == true) + return ERROR; + + return SUCCESS; +} + +int waiting_init_mcu(struct ssp_data *data) +{ + int iDelaycnt = 0; + + while (!data->check_mcu_busy() && (iDelaycnt++ < LIMIT_DELAY_CNT)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Irq Timeout!!\n", __func__); + data->uBusyCnt++; + } else { + data->uBusyCnt = 0; + } + + iDelaycnt = 0; + data->wakeup_mcu(); + while (!data->check_mcu_ready() && (iDelaycnt++ < LIMIT_DELAY_CNT)) + mdelay(5); + + if (iDelaycnt >= LIMIT_DELAY_CNT) { + pr_err("[SSP]: %s - MCU Wakeup Timeout!!\n", __func__); + data->uTimeOutCnt++; + } else { + data->uTimeOutCnt = 0; + } + + return SUCCESS; +} + +int ssp_spi_checkrecvstart(char *rxBuf, int len) +{ + unsigned int i; + for (i = 0; i < len ; i++) { + if (rxBuf[i] == 0x00) + continue; + break; + } + + if (i == len) + return -EFAULT; + return i; +} + +#if DEBUG_SHOW_DATA +void show_ssp_data(char *buff, int len, int type) +{ + unsigned int i; + char showdata[len*2+2]; + memset(showdata, 0, len*2+2); + for (i = 0; i < len; i++) + sprintf(showdata, "%s%02x", showdata, buff[i]); + + if (type == 1) + pr_info("[SSP]hb received len=%d %s", len, showdata); + else if (type == 2) + pr_info("[SSP]hb received while send %s", showdata); + else + pr_info("[SSP]hb sending len=%d %s", len, showdata); +} + +#endif + + +int ssp_read_data(struct ssp_data *data, char *pTxData, u16 uTxLength, + char *pRxData, u16 uRxLength, int iRetries) +{ + int iRet = 0, iDiffTime = 0, iTimeTemp; + int txlen = uTxLength; + struct timeval cur_time; + + do_gettimeofday(&cur_time); + + iTimeTemp = (int)cur_time.tv_sec; + +#if DEBUG_SHOW_DATA + show_ssp_data(pTxData, txlen, 3); +#endif + + mutex_lock(&data->comm_mutex); + + do { + char synctxbuf[RECEIVEBUFFERSIZE]; + char syncrxbuf[RECEIVEBUFFERSIZE]; + char *bulktxbuf; + char *bulkrxbuf; + + int startpos; + + if (pTxData[0] != MSG2SSP_SRM) { + /* 0xCA : MASS DATA will be received */ + memset(synctxbuf, 0, RECEIVEBUFFERSIZE); + + /* prevent re-sending CMD when retry */ + if (txlen > 0) + memcpy(synctxbuf, pTxData, uTxLength); + + /* uTxLength should small than RECEIVEBUFFERSIZE */ + iRet = ssp_spi_sync(data->spi, synctxbuf, + RECEIVEBUFFERSIZE, syncrxbuf); + +#if DEBUG_SHOW_DATA + show_ssp_data(syncrxbuf, RECEIVEBUFFERSIZE, 2); +#endif + + startpos = ssp_spi_checkrecvstart(syncrxbuf + txlen, + RECEIVEBUFFERSIZE - txlen) + txlen; +#if DEBUG_SHOW_DATA + pr_info("[SSP]hb pTxData[0]=0x%x startpos " + "%d uTxLength %d,uRxLen %d", + pTxData[0], startpos, uTxLength, uRxLength); +#endif + if (startpos >= txlen && + (RECEIVEBUFFERSIZE - startpos - uRxLength >= 0)) + memcpy(pRxData, syncrxbuf + startpos, + uRxLength); + else /* timeout if receive within RECEIVEBUFFERSIZE */ + iRet = -ETIMEDOUT; + + } else { + bulktxbuf = (char *)kzalloc( + uRxLength + RECEIVEBUFFERSIZE, GFP_KERNEL); + bulkrxbuf = (char *)kzalloc( + uRxLength + RECEIVEBUFFERSIZE, GFP_KERNEL); + + /* prevent re-sending command when retry */ + if (txlen > 0) + memcpy(bulktxbuf, pTxData, txlen); + iRet = ssp_spi_sync(data->spi, bulktxbuf, + uRxLength+RECEIVEBUFFERSIZE, bulkrxbuf); + +#if DEBUG_SHOW_DATA + show_ssp_data(bulkrxbuf, + uRxLength + RECEIVEBUFFERSIZE, 2); +#endif + + startpos = ssp_spi_checkrecvstart(bulkrxbuf + txlen, + uRxLength + RECEIVEBUFFERSIZE - txlen) + + txlen; +#if DEBUG_SHOW_DATA + pr_info("[SSP]hb WOW pTxData[0]=0x%x startpos %d " + "uTxLength %d,uRxLen %d TxLen %d", pTxData[0], + startpos, uTxLength, uRxLength, txlen); +#endif + + if (startpos >= txlen && + (uRxLength + RECEIVEBUFFERSIZE - + startpos - uRxLength >= 0)) + memcpy(pRxData, bulkrxbuf + startpos, + uRxLength); + else /* timeout if receive within RECEIVEBUFFERSIZE */ + iRet = -1; + + kfree(bulktxbuf); + kfree(bulkrxbuf); + } + + if (iRet < 0) { + do_gettimeofday(&cur_time); + iDiffTime = (int)cur_time.tv_sec - iTimeTemp; + iTimeTemp = (int)cur_time.tv_sec; + if (iDiffTime >= 4) { + pr_err("[SSP]: %s - spi time out %d!\n", + __func__, iDiffTime); + break; + } + pr_err("[SSP]: %s - spi error %d! retry...\n", + __func__, iRet); + mdelay(1); + } else { +#if DEBUG_SHOW_DATA + show_ssp_data(pRxData, uRxLength, 1); +#endif + mutex_unlock(&data->comm_mutex); + + return SUCCESS; + } + txlen = 0; + } while (iRetries--); + mutex_unlock(&data->comm_mutex); + + return ERROR; +} + +int ssp_sleep_mode(struct ssp_data *data) +{ + char chRxBuf = 0; + char chTxBuf = MSG2SSP_AP_STATUS_SLEEP; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + /* send to AP_STATUS_SLEEP */ + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD fail %d\n", + __func__, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD "\ + "retry...\n", __func__); + iRet = ssp_read_data(data, &chTxBuf, 1, + &chRxBuf, 1, DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD\n", __func__); + + return SUCCESS; +} + +int ssp_resume_mode(struct ssp_data *data) +{ + char chRxBuf = 0; + char chTxBuf = MSG2SSP_AP_STATUS_WAKEUP; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + /* send to MSG2SSP_AP_STATUS_WAKEUP */ + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD fail %d\n", + __func__, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD "\ + "retry...\n", __func__); + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD\n", __func__); + + return SUCCESS; +} + +int ssp_ap_suspend(struct ssp_data *data) +{ + char chRxBuf = 0; + char chTxBuf = MSG2SSP_AP_STATUS_SUSPEND; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + /* send to AP_STATUS_SLEEP */ + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD fail %d\n", + __func__, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD "\ + "retry...\n", __func__); + iRet = ssp_read_data(data, &chTxBuf, 1, + &chRxBuf, 1, DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD\n", __func__); + + return SUCCESS; +} + +int ssp_ap_resume(struct ssp_data *data) +{ + char chRxBuf = 0; + char chTxBuf = MSG2SSP_AP_STATUS_RESUME; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + /* send to MSG2SSP_AP_STATUS_WAKEUP */ + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD fail %d\n", + __func__, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD "\ + "retry...\n", __func__); + iRet = ssp_read_data(data, &chTxBuf, 1, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_WAKEUP CMD\n", __func__); + + return SUCCESS; +} + +int ssp_send_cmd(struct ssp_data *data, char command) +{ + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + iRet = ssp_read_data(data, &command, 1, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - command 0x%x failed %d\n", + __func__, command, iRet); + return ERROR; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - command 0x%x retry...\n", + __func__, command); + iRet = ssp_read_data(data, &command, 1, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - command 0x%x\n", __func__, command); + + return SUCCESS; +} + +int send_instruction(struct ssp_data *data, u8 uInst, + u8 uSensorType, u8 *uSendBuf, u8 uLength) +{ + char chTxbuf[uLength + 4]; + char chRxbuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (data->fw_dl_state == FW_DL_STATE_DOWNLOADING) { + pr_err("[SSP] %s - Skip Inst! DL state = %d\n", + __func__, data->fw_dl_state); + return SUCCESS; + } else if ((!(data->uSensorState & (1 << uSensorType))) + && (uInst <= CHANGE_DELAY)) { + pr_err("[SSP]: %s - Bypass Inst Skip! - %u\n", + __func__, uSensorType); + return FAIL; + } + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + chTxbuf[0] = MSG2SSP_SSM; + chTxbuf[1] = (char)(uLength + 4); + + switch (uInst) { + case REMOVE_SENSOR: + chTxbuf[2] = MSG2SSP_INST_BYPASS_SENSOR_REMOVE; + break; + case ADD_SENSOR: + chTxbuf[2] = MSG2SSP_INST_BYPASS_SENSOR_ADD; + break; + case CHANGE_DELAY: + chTxbuf[2] = MSG2SSP_INST_CHANGE_DELAY; + break; + case GO_SLEEP: + chTxbuf[2] = MSG2SSP_AP_STATUS_SLEEP; + break; + case FACTORY_MODE: + chTxbuf[2] = MSG2SSP_INST_SENSOR_SELFTEST; + break; + case REMOVE_LIBRARY: + chTxbuf[2] = MSG2SSP_INST_LIBRARY_REMOVE; + break; + case ADD_LIBRARY: + chTxbuf[2] = MSG2SSP_INST_LIBRARY_ADD; + break; + case MSG2SSP_INST_LIB_NOTI: + if (uSendBuf[0] == MSG2SSP_AP_STATUS_WAKEUP) { + iRet = ssp_resume_mode(data); + enable_debug_timer(data); + } else if (uSendBuf[0] == MSG2SSP_AP_STATUS_SLEEP) { + disable_debug_timer(data); + iRet = ssp_sleep_mode(data); + } else { + pr_err("[SSP]: %s -Wrong POWER_NOTI 0x%x\n", __func__, + uSendBuf[0]); + return ERROR; + } + return iRet; + default: + chTxbuf[2] = uInst; + break; + } + + chTxbuf[3] = uSensorType; + memcpy(&chTxbuf[4], uSendBuf, uLength); + + iRet = ssp_read_data(data, &(chTxbuf[0]), uLength + 4, &chRxbuf, 1, + DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Instruction CMD Fail %d\n", __func__, iRet); + return ERROR; + } else if (chRxbuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - Instruction CMD retry...\n", + __func__); + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + iRet = ssp_read_data(data, &(chTxbuf[0]), + uLength + 4, &chRxbuf, 1, DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxbuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return FAIL; + } + } + + data->uInstFailCnt = 0; + ssp_dbg("[SSP]: %s - Inst = 0x%x, Sensor Type = 0x%x, data = %u\n", + __func__, chTxbuf[2], chTxbuf[3], chTxbuf[4]); + return SUCCESS; +} + +int get_chipid(struct ssp_data *data) +{ + int iRet; + char sendbuf[2]; + char recvbuf; + sendbuf[0] = MSG2SSP_AP_WHOAMI; + sendbuf[1] = '\0'; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + /* read chip id */ +#if 1 + iRet = ssp_read_data(data, sendbuf, 2, &recvbuf, 1, DEFAULT_RETRIES); + + if (iRet == SUCCESS) + return recvbuf; + else + pr_err("[SSP]: %s - ssp_read_data fail %d\n", __func__, iRet); + + return ERROR; +#else + mutex_lock(&data->comm_mutex); + + iRet = ssp_spi_sync(data->spi, sendbuf, 1, NULL); + pr_err("[SSP]hb get_chipid ssp_spi_sync return for send %d", iRet); + + iRet = ssp_spi_sync(data->spi, NULL, 1, recvbuf); + pr_err("[SSP]hb get_chipid ssp_spi_sync return for recv %d", iRet); + iRet = recvbuf[0]; + pr_err("[SSP]hb get_chipid ssp_spi_sync recved %d", iRet); + + mutex_unlock(&data->comm_mutex); +#endif +} + +int set_sensor_position(struct ssp_data *data) +{ + char chTxBuf[5] = { 0, }; + char chRxData = 0; + int iRet = 0; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + chTxBuf[0] = MSG2SSP_AP_SENSOR_FORMATION; + + /* Please refer to ssp_get_positions on the file + * board-universal_5410-sensor.c */ + chTxBuf[1] = data->accel_position; + chTxBuf[2] = data->accel_position; + chTxBuf[3] = data->mag_position; + chTxBuf[4] = 0; + + pr_info("[SSP] Sensor Posision A : %u, G : %u, M: %u, P: %u\n", + chTxBuf[1], chTxBuf[2], chTxBuf[3], chTxBuf[4]); + + iRet = ssp_read_data(data, chTxBuf, 5, &chRxData, 1, DEFAULT_RETRIES); + if ((chRxData != MSG_ACK) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - spi fail %d\n", __func__, iRet); + iRet = ERROR; + } + + return iRet; +} + +void set_proximity_threshold(struct ssp_data *data, + unsigned char uData1, unsigned char uData2) +{ + char chTxBuf[3] = { 0, }; + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0 || + data->fw_dl_state == FW_DL_STATE_DOWNLOADING) { + pr_info("[SSP] : %s, skip DL state = %d\n", __func__, + data->fw_dl_state); + return; + } else if (!(data->uSensorState & (1 << PROXIMITY_SENSOR))) { + pr_info("[SSP] : %s, skip uSensorState = 0x%x\n", __func__, + data->uSensorState); + return; + } + + chTxBuf[0] = MSG2SSP_AP_SENSOR_PROXTHRESHOLD; + chTxBuf[1] = uData1; + chTxBuf[2] = uData2; + + iRet = ssp_read_data(data, chTxBuf, 3, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - SENSOR_PROXTHRESHOLD CMD fail %d\n", + __func__, iRet); + return; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_PROXTHRESHOLD "\ + "CMD retry...\n", __func__); + iRet = ssp_read_data(data, chTxBuf, 3, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return; + } + } + + data->uInstFailCnt = 0; + pr_info("[SSP]: Proximity Threshold - %u, %u\n", uData1, uData2); +} + +void set_proximity_barcode_enable(struct ssp_data *data, bool bEnable) +{ + char chTxBuf[2] = { 0, }; + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0) + return; + + chTxBuf[0] = MSG2SSP_AP_SENSOR_BARCODE_EMUL; + chTxBuf[1] = bEnable; + + data->bBarcodeEnabled = bEnable; + + iRet = ssp_read_data(data, chTxBuf, 2, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - SENSOR_BARCODE_EMUL CMD fail %d\n", + __func__, iRet); + return; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_BARCODE_EMUL "\ + "CMD retry...\n", __func__); + iRet = ssp_read_data(data, chTxBuf, 2, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return; + } + } + + data->uInstFailCnt = 0; + pr_info("[SSP] Proximity Barcode En : %u\n", bEnable); +} + +void set_gesture_current(struct ssp_data *data, unsigned char uData1) +{ + char chTxBuf[2] = { 0, }; + char chRxBuf = 0; + int iRet = 0, iRetries = DEFAULT_RETRIES; + + if (waiting_wakeup_mcu(data) < 0 || + data->fw_dl_state == FW_DL_STATE_DOWNLOADING) { + pr_info("[SSP] : %s, skip DL state = %d\n", __func__, + data->fw_dl_state); + return; + } + + chTxBuf[0] = MSG2SSP_AP_SENSOR_GESTURE_CURRENT; + chTxBuf[1] = uData1; + + iRet = ssp_read_data(data, chTxBuf, 2, &chRxBuf, 1, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - SENSOR_GESTURE_CURRENT CMD fail %d\n", + __func__, iRet); + return; + } else if (chRxBuf != MSG_ACK) { + while (iRetries--) { + mdelay(10); + pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_GESTURE_CURRENT "\ + "CMD retry...\n", __func__); + iRet = ssp_read_data(data, chTxBuf, 2, &chRxBuf, 1, + DEFAULT_RETRIES); + if ((iRet == SUCCESS) && (chRxBuf == MSG_ACK)) + break; + } + + if (iRetries < 0) { + data->uInstFailCnt++; + return; + } + } + + data->uInstFailCnt = 0; + pr_info("[SSP]: Gesture Current Setting - %u\n", uData1); +} + +unsigned int get_sensor_scanning_info(struct ssp_data *data) +{ + char chTxBuf = MSG2SSP_AP_SENSOR_SCANNING; + char chRxData[2] = {0,}; + int iRet = 0; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + iRet = ssp_read_data(data, &chTxBuf, 1, chRxData, 2, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - spi failed %d\n", __func__, iRet); + return 0; + } + return ((unsigned int)chRxData[0] << 8) | chRxData[1]; +} + +unsigned int get_firmware_rev(struct ssp_data *data) +{ + char chTxData = MSG2SSP_AP_FIRMWARE_REV; + char chRxBuf[3] = { 0, }; + unsigned int uRev = 99999; + int iRet; + + if (waiting_wakeup_mcu(data) < 0) + return ERROR; + + iRet = ssp_read_data(data, &chTxData, 1, chRxBuf, 3, DEFAULT_RETRIES); + if (iRet != SUCCESS) + pr_err("[SSP]: %s - spi fail %d\n", __func__, iRet); + else + uRev = ((unsigned int)chRxBuf[0] << 16) + | ((unsigned int)chRxBuf[1] << 8) | chRxBuf[2]; + return uRev; +} + +int get_fuserom_data(struct ssp_data *data) +{ + char chTxBuf[2] = { 0, }; + char chRxBuf[2] = { 0, }; + int iRet = 0; + unsigned int uLength = 0; + + if (waiting_init_mcu(data) < 0) + return ERROR; + + chTxBuf[0] = MSG2SSP_AP_STT; + chTxBuf[1] = MSG2SSP_AP_FUSEROM; + + /* chRxBuf is Two Byte because msg is large */ + iRet = ssp_read_data(data, chTxBuf, 2, chRxBuf, 2, DEFAULT_RETRIES); + uLength = ((unsigned int)chRxBuf[0] << 8) + (unsigned int)chRxBuf[1]; + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_AP_STT - spi fail %d\n", + __func__, iRet); + goto err_read_fuserom; + } else if (uLength == 0) { + pr_err("[SSP]: %s - No ready data. length = %u\n", + __func__, uLength); + goto err_read_fuserom; + } else { + if (data->iLibraryLength != 0) + kfree(data->pchLibraryBuf); + + data->iLibraryLength = (int)uLength; + data->pchLibraryBuf = + kzalloc((data->iLibraryLength * sizeof(char)), GFP_KERNEL); + + chTxBuf[0] = MSG2SSP_SRM; + iRet = ssp_read_data(data, chTxBuf, 1, data->pchLibraryBuf, + (u16)data->iLibraryLength, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Fail to receive SSP data %d\n", + __func__, iRet); + kfree(data->pchLibraryBuf); + data->iLibraryLength = 0; + goto err_read_fuserom; + } + } + + data->uFuseRomData[0] = data->pchLibraryBuf[0]; + data->uFuseRomData[1] = data->pchLibraryBuf[1]; + data->uFuseRomData[2] = data->pchLibraryBuf[2]; + + pr_info("[SSP] FUSE ROM Data %d , %d, %d\n", data->uFuseRomData[0], + data->uFuseRomData[1], data->uFuseRomData[2]); + + data->iLibraryLength = 0; + kfree(data->pchLibraryBuf); + return SUCCESS; + +err_read_fuserom: + data->uFuseRomData[0] = 0; + data->uFuseRomData[1] = 0; + data->uFuseRomData[2] = 0; + + return FAIL; +} + +static int ssp_receive_msg(struct ssp_data *data, u8 uLength) +{ + char chTxBuf = 0; + char *pchRcvDataFrame = NULL; /* SSP-AP Massage data buffer */ + int iRet = 0; + + if (uLength > 0) { + pchRcvDataFrame = kzalloc((uLength * sizeof(char)), GFP_KERNEL); + if (pchRcvDataFrame == NULL) { + pr_err("[SSP]: %s - fail to allocate memory for data\n", + __func__); + iRet = -ENOMEM; + return iRet; + } + chTxBuf = MSG2SSP_SRM; + iRet = ssp_read_data(data, &chTxBuf, 1, pchRcvDataFrame, + (u16)uLength, 0); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Fail to receive data %d\n", + __func__, iRet); + kfree(pchRcvDataFrame); + return ERROR; + } + } else { + pr_err("[SSP]: %s - No ready data. length = %d\n", + __func__, uLength); + return FAIL; + } + + parse_dataframe(data, pchRcvDataFrame, uLength); + + kfree(pchRcvDataFrame); + return uLength; +} + +int select_irq_msg(struct ssp_data *data) +{ + u8 chLength = 0; + char chTxBuf = 0; + char chRxBuf[2] = { 0, }; + int iRet = 0; + + chTxBuf = MSG2SSP_SSD; + iRet = ssp_read_data(data, &chTxBuf, 1, chRxBuf, 2, 4); + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - MSG2SSP_SSD error %d\n", __func__, iRet); + return ERROR; + } else { + if (chRxBuf[0] == MSG2SSP_RTS) { + chLength = (u8)chRxBuf[1]; + ssp_receive_msg(data, chLength); + data->uSsdFailCnt = 0; + } +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + else if (chRxBuf[0] == MSG2SSP_STT) { + pr_info("%s: MSG2SSP_STT irq", __func__); + iRet = ssp_sensorhub_handle_large_data(data, + (u8)chRxBuf[1]); + if (iRet < 0) { + pr_err("%s: ssp sensorhub large data err(%d)", + __func__, iRet); + } + data->uSsdFailCnt = 0; + } +#endif + else if (chRxBuf[0] == MSG2SSP_NO_DATA) { + pr_info("%s: MSG2SSP_NODATA irq [0]: 0x%x, [1]: 0x%x\n", + __func__, chRxBuf[0], chRxBuf[1]); + } else { + pr_err("[SSP]: %s - MSG2SSP_SSD Data fail "\ + "[0]: 0x%x, [1]: 0x%x\n", __func__, + chRxBuf[0], chRxBuf[1]); + if ((chRxBuf[0] == 0) && (chRxBuf[1] == 0)) + data->uSsdFailCnt++; + } + } + return SUCCESS; +} diff --git a/drivers/sensorhub/stm/ssp_data.c b/drivers/sensorhub/stm/ssp_data.c new file mode 100755 index 00000000000..c1960829bcc --- /dev/null +++ b/drivers/sensorhub/stm/ssp_data.c @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/* SSP -> AP Instruction */ +#define MSG2AP_INST_BYPASS_DATA 0x37 +#define MSG2AP_INST_LIBRARY_DATA 0x01 +#define MSG2AP_INST_SELFTEST_DATA 0x02 +#define MSG2AP_INST_DEBUG_DATA 0x03 + +/* Factory data length */ +#define ACCEL_FACTORY_DATA_LENGTH 1 +#define GYRO_FACTORY_DATA_LENGTH 36 +#define MAGNETIC_FACTORY_DATA_LENGTH 26 +#define PRESSURE_FACTORY_DATA_LENGTH 1 +#define MCU_FACTORY_DATA_LENGTH 5 +#define GYRO_TEMP_FACTORY_DATA_LENGTH 2 +#define GYRO_DPS_FACTORY_DATA_LENGTH 1 +#define TEMPHUMIDITY_FACTORY_DATA_LENGTH 1 +#define MCU_SLEEP_FACTORY_DATA_LENGTH FACTORY_DATA_MAX +#define GESTURE_FACTORY_DATA_LENGTH 4 + +/*************************************************************************/ +/* SSP parsing the dataframe */ +/*************************************************************************/ + +static void get_3axis_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + s16 iTemp = 0; + + iTemp = (s16)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->x = iTemp; + + iTemp = (s16)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->y = iTemp; + + iTemp = (s16)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->z = iTemp; +} + +static void get_light_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + s16 iTemp = 0; + + iTemp = (s16)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->r = iTemp; + + iTemp = (s16)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->g = iTemp; + + iTemp = (s16)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->b = iTemp; + + iTemp = (s16)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->w = iTemp; +} + +static void get_pressure_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + int iTemp = 0; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 16; + sensorsdata->pressure[0] = iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + sensorsdata->pressure[0] += iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->pressure[0] += iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += (int)pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->pressure[1] = (s16)iTemp; +} + +static void get_gesture_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + int iTemp; + int i = 0; + for (i=0; i<9; i++) { + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->data[i] = (s16)iTemp; + } +} + +static void get_proximity_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + sensorsdata->prox[0] = (u8)pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->prox[1] = (u8)pchRcvDataFrame[(*iDataIdx)++]; +} + +static void get_proximity_rawdata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + sensorsdata->prox[0] = (u8)pchRcvDataFrame[(*iDataIdx)++]; +} + +static void get_geomagnetic_rawdata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + int iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->x = (s16)iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->y = (s16)iTemp; + + iTemp = (int)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->z = (s16)iTemp; + +} + +static void get_factory_data(struct ssp_data *data, int iSensorData, + char *pchRcvDataFrame, int *iDataIdx) +{ + int iIdx, iTotalLenth = 0; + unsigned int uTemp = 0; + + switch (iSensorData) { + case ACCELEROMETER_FACTORY: + uTemp = (1 << ACCELEROMETER_FACTORY); + iTotalLenth = ACCEL_FACTORY_DATA_LENGTH; + break; + case GYROSCOPE_FACTORY: + uTemp = (1 << GYROSCOPE_FACTORY); + iTotalLenth = GYRO_FACTORY_DATA_LENGTH; + break; + case GEOMAGNETIC_FACTORY: + uTemp = (1 << GEOMAGNETIC_FACTORY); + iTotalLenth = MAGNETIC_FACTORY_DATA_LENGTH; + break; + case PRESSURE_FACTORY: + uTemp = (1 << PRESSURE_FACTORY); + iTotalLenth = PRESSURE_FACTORY_DATA_LENGTH; + break; + case MCU_FACTORY: + uTemp = (1 << MCU_FACTORY); + iTotalLenth = MCU_FACTORY_DATA_LENGTH; + break; + case GYROSCOPE_TEMP_FACTORY: + uTemp = (1 << GYROSCOPE_TEMP_FACTORY); + iTotalLenth = GYRO_TEMP_FACTORY_DATA_LENGTH; + break; + case GYROSCOPE_DPS_FACTORY: + uTemp = (1 << GYROSCOPE_DPS_FACTORY); + iTotalLenth = GYRO_DPS_FACTORY_DATA_LENGTH; + break; + case MCU_SLEEP_FACTORY: + uTemp = (1 << MCU_SLEEP_FACTORY); + iTotalLenth = MCU_SLEEP_FACTORY_DATA_LENGTH; + break; + case GESTURE_FACTORY: + uTemp = (1 << GESTURE_FACTORY); + iTotalLenth = GESTURE_FACTORY_DATA_LENGTH; + break; + case TEMPHUMIDITY_CRC_FACTORY: + uTemp = (1 << TEMPHUMIDITY_CRC_FACTORY); + iTotalLenth = TEMPHUMIDITY_FACTORY_DATA_LENGTH; + break; + } + + ssp_dbg("[SSP]: %s - Factory test data %d\n", __func__, iSensorData); + for (iIdx = 0; iIdx < iTotalLenth; iIdx++) + data->uFactorydata[iIdx] = (u8)pchRcvDataFrame[(*iDataIdx)++]; + + data->uFactorydataReady = uTemp; +} + +static void get_temp_humidity_sensordata(char *pchRcvDataFrame, int *iDataIdx, + struct sensor_value *sensorsdata) +{ + s16 iTemp = 0; + + /* Temperature */ + iTemp = (s16)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->data[0] = iTemp; + /* Humidity */ + iTemp = (s16)pchRcvDataFrame[(*iDataIdx)++]; + iTemp <<= 8; + iTemp += pchRcvDataFrame[(*iDataIdx)++]; + sensorsdata->data[1] = iTemp; +} + +int parse_dataframe(struct ssp_data *data, char *pchRcvDataFrame, int iLength) +{ + int iDataIdx, iSensorData; + struct sensor_value *sensorsdata; + + sensorsdata = kzalloc(sizeof(*sensorsdata), GFP_KERNEL); + if (sensorsdata == NULL) + return ERROR; + + for (iDataIdx = 0; iDataIdx < iLength;) { + if (pchRcvDataFrame[iDataIdx] == MSG2AP_INST_BYPASS_DATA) { + iDataIdx++; + iSensorData = pchRcvDataFrame[iDataIdx++]; + if ((iSensorData < 0) || + (iSensorData >= (SENSOR_MAX - 1))) { + pr_err("[SSP]: %s - Mcu data frame1 error %d\n", + __func__, iSensorData); + kfree(sensorsdata); + return ERROR; + } + + data->get_sensor_data[iSensorData](pchRcvDataFrame, + &iDataIdx, sensorsdata); + data->report_sensor_data[iSensorData](data, + sensorsdata); + } else if (pchRcvDataFrame[iDataIdx] == + MSG2AP_INST_SELFTEST_DATA) { + iDataIdx++; + iSensorData = pchRcvDataFrame[iDataIdx++]; + if ((iSensorData < 0) || + (iSensorData >= SENSOR_FACTORY_MAX)) { + pr_err("[SSP]: %s - Mcu data frame2 error %d\n", + __func__, iSensorData); + kfree(sensorsdata); + return ERROR; + } + get_factory_data(data, iSensorData, pchRcvDataFrame, + &iDataIdx); + } else if (pchRcvDataFrame[iDataIdx] == + MSG2AP_INST_DEBUG_DATA) { + iSensorData + = print_mcu_debug(pchRcvDataFrame + iDataIdx+1, + &iDataIdx, iLength); + if (iSensorData) { + pr_err("[SSP]: %s - Mcu data frame3 error %d\n", + __func__, iSensorData); + kfree(sensorsdata); + return ERROR; + } +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + } else if (pchRcvDataFrame[iDataIdx] == + MSG2AP_INST_LIBRARY_DATA) { + ssp_sensorhub_handle_data(data, + pchRcvDataFrame, iDataIdx, iLength); + break; +#endif + } else + iDataIdx++; + } + kfree(sensorsdata); + return SUCCESS; +} + +void initialize_function_pointer(struct ssp_data *data) +{ + data->get_sensor_data[ACCELEROMETER_SENSOR] = get_3axis_sensordata; + data->get_sensor_data[GYROSCOPE_SENSOR] = get_3axis_sensordata; + data->get_sensor_data[GEOMAGNETIC_SENSOR] = get_3axis_sensordata; + data->get_sensor_data[PRESSURE_SENSOR] = get_pressure_sensordata; + data->get_sensor_data[GESTURE_SENSOR] = get_gesture_sensordata; + data->get_sensor_data[PROXIMITY_SENSOR] = get_proximity_sensordata; + data->get_sensor_data[PROXIMITY_RAW] = get_proximity_rawdata; + data->get_sensor_data[LIGHT_SENSOR] = get_light_sensordata; + data->get_sensor_data[TEMPERATURE_HUMIDITY_SENSOR] = + get_temp_humidity_sensordata; + data->get_sensor_data[GEOMAGNETIC_RAW] = get_geomagnetic_rawdata; + + data->report_sensor_data[ACCELEROMETER_SENSOR] = report_acc_data; + data->report_sensor_data[GYROSCOPE_SENSOR] = report_gyro_data; + data->report_sensor_data[GEOMAGNETIC_SENSOR] = report_mag_data; + data->report_sensor_data[PRESSURE_SENSOR] = report_pressure_data; + data->report_sensor_data[GESTURE_SENSOR] = report_gesture_data; + data->report_sensor_data[PROXIMITY_SENSOR] = report_prox_data; + data->report_sensor_data[PROXIMITY_RAW] = report_prox_raw_data; + data->report_sensor_data[LIGHT_SENSOR] = report_light_data; + data->report_sensor_data[TEMPERATURE_HUMIDITY_SENSOR] = + report_temp_humidity_data; + data->report_sensor_data[GEOMAGNETIC_RAW] = report_geomagnetic_raw_data; +} diff --git a/drivers/sensorhub/stm/ssp_debug.c b/drivers/sensorhub/stm/ssp_debug.c new file mode 100755 index 00000000000..007e1839f8d --- /dev/null +++ b/drivers/sensorhub/stm/ssp_debug.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +#define SSP_DEBUG_TIMER_SEC (10 * HZ) + +#define LIMIT_RESET_CNT 20 +#define LIMIT_SSD_FAIL_CNT 3 +#define LIMIT_INSTRUCTION_FAIL_CNT 1 +#define LIMIT_IRQ_FAIL_CNT 2 +#define LIMIT_TIMEOUT_CNT 5 + +/*************************************************************************/ +/* SSP Debug timer function */ +/*************************************************************************/ + +int print_mcu_debug(char *pchRcvDataFrame, int *pDataIdx, + int iRcvDataFrameLength) +{ + int iLength = pchRcvDataFrame[0]; + + if (iLength >= iRcvDataFrameLength - *pDataIdx - 1 || iLength <= 0) { + ssp_dbg("[SSP]: MSG From MCU - invalid debug length(%d/%d)\n", + iLength, iRcvDataFrameLength); + return iLength ? iLength : ERROR; + } + + pchRcvDataFrame[iLength] = 0; + *pDataIdx += iLength + 2; + ssp_dbg("[SSP]: MSG From MCU - %s\n", pchRcvDataFrame + 1); + + return 0; +} + +void reset_mcu(struct ssp_data *data) +{ + ssp_enable(data, false); + + toggle_mcu_reset(data); + msleep(SSP_SW_RESET_TIME); + + if (initialize_mcu(data) < 0) + return; + + ssp_enable(data, true); + sync_sensor_state(data); + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_RESET); +#endif +} + +void sync_sensor_state(struct ssp_data *data) +{ + unsigned char uBuf[2] = {0,}; + unsigned int uSensorCnt; + int iRet = 0; + proximity_open_calibration(data); + iRet = set_hw_offset(data); + if (iRet < 0) { + pr_err("[SSP]: %s - set_hw_offset failed\n", __func__); + } + + udelay(10); + + for (uSensorCnt = 0; uSensorCnt < (SENSOR_MAX - 1); uSensorCnt++) { + if (atomic_read(&data->aSensorEnable) & (1 << uSensorCnt)) { + uBuf[1] = (u8)get_msdelay(data->adDelayBuf[uSensorCnt]); + uBuf[0] = (u8)get_delay_cmd(uBuf[1]); + send_instruction(data, ADD_SENSOR, uSensorCnt, uBuf, 2); + udelay(10); + } + } + + if (data->bProximityRawEnabled == true) { + uBuf[0] = 1; + uBuf[1] = 20; + send_instruction(data, ADD_SENSOR, PROXIMITY_RAW, uBuf, 2); + } +} + +static void print_sensordata(struct ssp_data *data, unsigned int uSensor) +{ + switch (uSensor) { + case ACCELEROMETER_SENSOR: + case GYROSCOPE_SENSOR: + case GEOMAGNETIC_SENSOR: + ssp_dbg(" %u : %d, %d, %d (%ums)\n", uSensor, + data->buf[uSensor].x, data->buf[uSensor].y, + data->buf[uSensor].z, + get_msdelay(data->adDelayBuf[uSensor])); + break; + case PRESSURE_SENSOR: + ssp_dbg(" %u : %d, %d (%ums)\n", uSensor, + data->buf[uSensor].pressure[0], + data->buf[uSensor].pressure[1], + get_msdelay(data->adDelayBuf[uSensor])); + break; + case GESTURE_SENSOR: + ssp_dbg(" %u : %d %d %d %d (%ums)\n", uSensor, + data->buf[uSensor].data[0], data->buf[uSensor].data[1], + data->buf[uSensor].data[2], data->buf[uSensor].data[3], + get_msdelay(data->adDelayBuf[uSensor])); + break; + case TEMPERATURE_HUMIDITY_SENSOR: + ssp_dbg(" %u : %d %d %d(%ums)\n", uSensor, + data->buf[uSensor].data[0], data->buf[uSensor].data[1], + data->buf[uSensor].data[2], get_msdelay(data->adDelayBuf[uSensor])); + break; + case LIGHT_SENSOR: + ssp_dbg(" %u : %u, %u, %u, %u (%ums)\n", uSensor, + data->buf[uSensor].r, data->buf[uSensor].g, + data->buf[uSensor].b, data->buf[uSensor].w, + get_msdelay(data->adDelayBuf[uSensor])); + break; + case PROXIMITY_SENSOR: + ssp_dbg(" %u : %d %d(%ums)\n", uSensor, + data->buf[uSensor].prox[0], data->buf[uSensor].prox[1], + get_msdelay(data->adDelayBuf[uSensor])); + break; + default: + ssp_dbg("Wrong sensorCnt: %u\n", uSensor); + break; + } +} + +static void debug_work_func(struct work_struct *work) +{ + unsigned int uSensorCnt; + struct ssp_data *data = container_of(work, struct ssp_data, work_debug); + + ssp_dbg("[SSP]: %s(%u) - Sensor state: 0x%x, RC: %u, MS: %u\n", + __func__, data->uIrqCnt, data->uSensorState, data->uResetCnt, + data->uMissSensorCnt); + + if (data->fw_dl_state >= FW_DL_STATE_DOWNLOADING && + data->fw_dl_state < FW_DL_STATE_DONE) { + pr_info("[SSP] : %s firmware downloading state = %d\n", + __func__, data->fw_dl_state); + return; + } else if (data->fw_dl_state == FW_DL_STATE_FAIL) { + pr_err("[SSP] : %s firmware download failed = %d\n", + __func__, data->fw_dl_state); + return; + } + + for (uSensorCnt = 0; uSensorCnt < (SENSOR_MAX - 1); uSensorCnt++) + if (atomic_read(&data->aSensorEnable) & (1 << uSensorCnt)) + print_sensordata(data, uSensorCnt); + + if ((atomic_read(&data->aSensorEnable) & SSP_BYPASS_SENSORS_EN_ALL)\ + && (data->uIrqCnt == 0)) + data->uIrqFailCnt++; + else + data->uIrqFailCnt = 0; + + if (((data->uSsdFailCnt >= LIMIT_SSD_FAIL_CNT) + || (data->uInstFailCnt >= LIMIT_INSTRUCTION_FAIL_CNT) + || (data->uIrqFailCnt >= LIMIT_IRQ_FAIL_CNT) + || ((data->uTimeOutCnt + data->uBusyCnt) > LIMIT_TIMEOUT_CNT)) + && (data->bSspShutdown == false)) { + + if (data->uResetCnt < LIMIT_RESET_CNT) { + pr_info("[SSP] : %s - uSsdFailCnt(%u), uInstFailCnt(%u),"\ + "uIrqFailCnt(%u), uTimeOutCnt(%u), uBusyCnt(%u)\n", + __func__, data->uSsdFailCnt, data->uInstFailCnt, data->uIrqFailCnt, + data->uTimeOutCnt, data->uBusyCnt); + reset_mcu(data); + data->uResetCnt++; + } else + ssp_enable(data, false); + + data->uSsdFailCnt = 0; + data->uInstFailCnt = 0; + data->uTimeOutCnt = 0; + data->uBusyCnt = 0; + data->uIrqFailCnt = 0; + } + + data->uIrqCnt = 0; +} + +static void debug_timer_func(unsigned long ptr) +{ + struct ssp_data *data = (struct ssp_data *)ptr; + + queue_work(data->debug_wq, &data->work_debug); + mod_timer(&data->debug_timer, + round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC)); +} + +void enable_debug_timer(struct ssp_data *data) +{ + mod_timer(&data->debug_timer, + round_jiffies_up(jiffies + SSP_DEBUG_TIMER_SEC)); +} + +void disable_debug_timer(struct ssp_data *data) +{ + del_timer_sync(&data->debug_timer); + cancel_work_sync(&data->work_debug); +} + +int initialize_debug_timer(struct ssp_data *data) +{ + setup_timer(&data->debug_timer, debug_timer_func, (unsigned long)data); + + data->debug_wq = create_singlethread_workqueue("ssp_debug_wq"); + if (!data->debug_wq) + return ERROR; + + INIT_WORK(&data->work_debug, debug_work_func); + return SUCCESS; +} diff --git a/drivers/sensorhub/stm/ssp_dev.c b/drivers/sensorhub/stm/ssp_dev.c new file mode 100755 index 00000000000..e7ee067434f --- /dev/null +++ b/drivers/sensorhub/stm/ssp_dev.c @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/* ssp mcu device ID */ +#define DEVICE_ID 0x55 + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ssp_early_suspend(struct early_suspend *handler); +static void ssp_late_resume(struct early_suspend *handler); +#endif + +void ssp_enable(struct ssp_data *data, bool enable) +{ + pr_info("%s, enable = %d, old enable = %d\n", + __func__, enable, data->bSspShutdown); + + if (enable && data->bSspShutdown) { + data->bSspShutdown = false; + enable_irq(data->iIrq); + enable_irq_wake(data->iIrq); + } else if (!enable && !data->bSspShutdown) { + data->bSspShutdown = true; + disable_irq(data->iIrq); + disable_irq_wake(data->iIrq); + } else + pr_err("%s, error / enable = %d, old enable = %d\n", + __func__, enable, data->bSspShutdown); +} +/************************************************************************/ +/* interrupt happened due to transition/change of SSP MCU */ +/************************************************************************/ + +static irqreturn_t sensordata_irq_thread_fn(int iIrq, void *dev_id) +{ + struct ssp_data *data = dev_id; + + select_irq_msg(data); + data->uIrqCnt++; + + return IRQ_HANDLED; +} + +/*************************************************************************/ +/* initialize sensor hub */ +/*************************************************************************/ + +static void initialize_variable(struct ssp_data *data) +{ + int iSensorIndex; + + for (iSensorIndex = 0; iSensorIndex < SENSOR_MAX; iSensorIndex++) { + data->adDelayBuf[iSensorIndex] = DEFUALT_POLLING_DELAY; + data->aiCheckStatus[iSensorIndex] = INITIALIZATION_STATE; + } + + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + atomic_set(&data->aSensorEnable, 0); + data->iLibraryLength = 0; + data->uSensorState = 0; + data->uFactorydataReady = 0; + data->uFactoryProxAvg[0] = 0; + + data->uResetCnt = 0; + data->uInstFailCnt = 0; + data->uTimeOutCnt = 0; + data->uSsdFailCnt = 0; + data->uBusyCnt = 0; + data->uIrqCnt = 0; + data->uIrqFailCnt = 0; + data->uMissSensorCnt = 0; + + data->bCheckSuspend = false; + data->bSspShutdown = true; + data->bDebugEnabled = false; + data->bProximityRawEnabled = false; + data->bGeomagneticRawEnabled = false; + data->bMcuIRQTestSuccessed = false; + data->bBarcodeEnabled = false; + data->bAccelAlert = false; + + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + + data->gyrocal.x = 0; + data->gyrocal.y = 0; + data->gyrocal.z = 0; + + data->magoffset.x = 0; + data->magoffset.y = 0; + data->magoffset.z = 0; + + data->iPressureCal = 0; + data->uProxCanc = 0; + data->uProxHiThresh = 0; + data->uProxLoThresh = 0; + data->uGyroDps = GYROSCOPE_DPS500; + data->uIr_Current = DEFUALT_IR_CURRENT; + + data->mcu_device = NULL; + data->acc_device = NULL; + data->gyro_device = NULL; + data->mag_device = NULL; + data->prs_device = NULL; + data->prox_device = NULL; + data->light_device = NULL; + data->ges_device = NULL; + + initialize_function_pointer(data); +} + +int initialize_mcu(struct ssp_data *data) +{ + int iRet = 0; + + iRet = get_chipid(data); + pr_info("[SSP] MCU device ID = %d, reading ID = %d\n", DEVICE_ID, iRet); + if (iRet != DEVICE_ID) { + if (iRet < 0) { + pr_err("[SSP]: %s - MCU is not working : 0x%x\n", + __func__, iRet); + } else { + pr_err("[SSP]: %s - MCU identification failed\n", + __func__); + iRet = -ENODEV; + } + goto out; + } + + iRet = set_sensor_position(data); + if (iRet < 0) { + pr_err("[SSP]: %s - set_sensor_position failed\n", __func__); + goto out; + } + + data->uSensorState = get_sensor_scanning_info(data); + if (data->uSensorState == 0) { + pr_err("[SSP]: %s - get_sensor_scanning_info failed\n", + __func__); + iRet = ERROR; + goto out; + } + + iRet = SUCCESS; +out: + return iRet; +} + +static int initialize_irq(struct ssp_data *data) +{ + int iRet, iIrq; + + iRet = gpio_request(data->spi->irq, "mpu_ap_int"); + if (iRet < 0) { + pr_err("[SSP]: %s - gpio %d request failed (%d)\n", + __func__, data->spi->irq, iRet); + return iRet; + } + + iRet = gpio_direction_input(data->spi->irq); + if (iRet < 0) { + pr_err("[SSP]: %s - failed to set gpio %d as input (%d)\n", + __func__, data->spi->irq, iRet); + goto err_irq_direction_input; + } + + iIrq = gpio_to_irq(data->spi->irq); + + pr_info("[SSP]: requesting IRQ %d, %d\n", iIrq, data->spi->irq); + iRet = request_threaded_irq(iIrq, NULL, sensordata_irq_thread_fn, + IRQF_TRIGGER_FALLING, "SSP_Int", data); + if (iRet < 0) { + pr_err("[SSP]: %s - request_irq(%d) failed for gpio %d (%d)\n", + __func__, iIrq, iIrq, iRet); + goto err_request_irq; + } + + /* start with interrupts disabled */ + data->iIrq = iIrq; + disable_irq(data->iIrq); + return 0; + +err_request_irq: +err_irq_direction_input: + gpio_free(data->spi->irq); + return iRet; +} + +static void work_function_firmware_update(struct work_struct *work) +{ + struct ssp_data *data = container_of((struct delayed_work *)work, + struct ssp_data, work_firmware); + int iRet = 0; + + pr_info("[SSP] : %s\n", __func__); + + iRet = forced_to_download_binary(data, KERNEL_BINARY); + if (iRet < 0) { + ssp_dbg("[SSP]: %s - forced_to_download_binary failed!\n", + __func__); + return; + } + + data->uCurFirmRev = get_firmware_rev(data); + pr_info("[SSP] MCU Firm Rev : New = %8u\n", + data->uCurFirmRev); +} + +static int ssp_probe(struct spi_device *spi) +{ + int iRet = 0; + struct ssp_data *data; + struct ssp_platform_data *pdata = spi->dev.platform_data; + + pr_info("\n#####################################################\n"); + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (data == NULL || pdata == NULL) { + pr_err("[SSP]: %s - failed to allocate memory for data\n", + __func__); + iRet = -ENOMEM; + goto exit; + } + + data->wakeup_mcu = pdata->wakeup_mcu; + data->check_mcu_ready = pdata->check_mcu_ready; + data->check_mcu_busy = pdata->check_mcu_busy; + data->set_mcu_reset = pdata->set_mcu_reset; + + if ((data->wakeup_mcu == NULL) + || (data->check_mcu_ready == NULL) + || (data->check_mcu_busy == NULL) + || (data->set_mcu_reset == NULL)) { + pr_err("[SSP]: %s - function callback is null\n", __func__); + iRet = -EIO; + goto exit; + } + + /* AP system_rev */ + if (pdata->check_ap_rev) + data->ap_rev = pdata->check_ap_rev(); + else + data->ap_rev = 0; + + /* Get sensor positions */ + if (pdata->get_positions) + pdata->get_positions(&data->accel_position, + &data->mag_position); + else { + data->accel_position = 0; + data->mag_position = 0; + } + +#ifdef CONFIG_SENSORS_SSP_SHTC1 + /* Get pdata for cp thermister */ + if (pdata->cp_thm_adc_table) { + data->cp_thm_adc_channel = pdata->cp_thm_adc_channel; + data->cp_thm_adc_arr_size= pdata->cp_thm_adc_arr_size; + data->cp_thm_adc_table = pdata->cp_thm_adc_table; + } + mutex_init(&data->cp_temp_adc_lock); +#endif + + mutex_init(&data->comm_mutex); + + if (spi_setup(spi)) { + pr_err("failed to setup spi for ssp_spi\n"); + goto err_setup; + } + + data->bProbeIsDone = false; + data->fw_dl_state = FW_DL_STATE_NONE; + data->spi = spi; + spi_set_drvdata(spi, data); + + INIT_DELAYED_WORK(&data->work_firmware, work_function_firmware_update); + /* check boot loader binary */ + data->fw_dl_state = check_fwbl(data); + + initialize_variable(data); + + if (data->fw_dl_state == FW_DL_STATE_NONE) { + iRet = initialize_mcu(data); + if (iRet == ERROR) { + data->uResetCnt++; + toggle_mcu_reset(data); + msleep(SSP_SW_RESET_TIME); + initialize_mcu(data); + } else if (iRet < ERROR) { + pr_err("[SSP]: %s - initialize_mcu failed\n", __func__); + goto err_read_reg; + } + } + + wake_lock_init(&data->ssp_wake_lock, + WAKE_LOCK_SUSPEND, "ssp_wake_lock"); + + iRet = initialize_input_dev(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create input device\n", __func__); + goto err_input_register_device; + } + + iRet = initialize_debug_timer(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create workqueue\n", __func__); + goto err_create_workqueue; + } + + iRet = initialize_irq(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create irq\n", __func__); + goto err_setup_irq; + } + + iRet = initialize_sysfs(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create sysfs\n", __func__); + goto err_sysfs_create; + } + + iRet = initialize_event_symlink(data); + if (iRet < 0) { + pr_err("[SSP]: %s - could not create symlink\n", __func__); + goto err_symlink_create; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.suspend = ssp_early_suspend; + data->early_suspend.resume = ssp_late_resume; + register_early_suspend(&data->early_suspend); +#endif + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + /* init sensorhub device */ + iRet = ssp_sensorhub_initialize(data); + if (iRet < 0) { + pr_err("%s: ssp_sensorhub_initialize err(%d)", __func__, iRet); + ssp_sensorhub_remove(data); + } +#endif + + ssp_enable(data, true); + pr_info("[SSP]: %s - probe success!\n", __func__); + + enable_debug_timer(data); + + iRet = 0; + if (data->fw_dl_state == FW_DL_STATE_NEED_TO_SCHEDULE) { + pr_info("[SSP]: Firmware update is scheduled\n"); + schedule_delayed_work(&data->work_firmware, + msecs_to_jiffies(1000)); + data->fw_dl_state = FW_DL_STATE_SCHEDULED; + } else if (data->fw_dl_state == FW_DL_STATE_FAIL) { + data->bSspShutdown = true; + } + + data->bProbeIsDone = true; + + goto exit; + +err_symlink_create: + remove_sysfs(data); +err_sysfs_create: + free_irq(data->iIrq, data); + gpio_free(data->spi->irq); +err_setup_irq: + destroy_workqueue(data->debug_wq); +err_create_workqueue: + remove_input_dev(data); +err_input_register_device: + wake_lock_destroy(&data->ssp_wake_lock); +err_read_reg: +err_reset_null: +err_setup: +#ifdef CONFIG_SENSORS_SSP_SHTC1 + mutex_destroy(&data->cp_temp_adc_lock); +#endif + mutex_destroy(&data->comm_mutex); + kfree(data); + pr_err("[SSP]: %s - probe failed!\n", __func__); +exit: + pr_info("#####################################################\n\n"); + return iRet; +} + +static void ssp_shutdown(struct spi_device *spi) +{ + struct ssp_data *data = spi_get_drvdata(spi); + + func_dbg(); + if (data->bProbeIsDone == false) + goto exit; + + if (data->fw_dl_state >= FW_DL_STATE_SCHEDULED && + data->fw_dl_state < FW_DL_STATE_DONE) { + pr_err("%s, cancel_delayed_work_sync state = %d\n", + __func__, data->fw_dl_state); + cancel_delayed_work_sync(&data->work_firmware); + } + + ssp_enable(data, false); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&data->early_suspend); +#endif + + disable_debug_timer(data); + + free_irq(data->iIrq, data); + gpio_free(data->spi->irq); + + remove_sysfs(data); + remove_event_symlink(data); + remove_input_dev(data); + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + ssp_sensorhub_remove(data); +#endif + + del_timer_sync(&data->debug_timer); + cancel_work_sync(&data->work_debug); + destroy_workqueue(data->debug_wq); + wake_lock_destroy(&data->ssp_wake_lock); +#ifdef CONFIG_SENSORS_SSP_SHTC1 + mutex_destroy(&data->cp_temp_adc_lock); +#endif + toggle_mcu_reset(data); +exit: + kfree(data); +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void ssp_early_suspend(struct early_suspend *handler) +{ + struct ssp_data *data; + data = container_of(handler, struct ssp_data, early_suspend); + + func_dbg(); + disable_debug_timer(data); + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + /* give notice to user that AP goes to sleep */ + ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_SLEEP); + ssp_sleep_mode(data); +#else + if (atomic_read(&data->aSensorEnable) > 0) + ssp_sleep_mode(data); +#endif +} + +static void ssp_late_resume(struct early_suspend *handler) +{ + struct ssp_data *data; + data = container_of(handler, struct ssp_data, early_suspend); + + func_dbg(); + enable_debug_timer(data); + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + /* give notice to user that AP goes to sleep */ + ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_WAKEUP); + ssp_resume_mode(data); +#else + if (atomic_read(&data->aSensorEnable) > 0) + ssp_resume_mode(data); +#endif +} + +#else /* CONFIG_HAS_EARLYSUSPEND */ + +static int ssp_suspend(struct device *dev) +{ +#if 0 + struct spi_device *spi_dev = to_spi_device(dev); + struct ssp_data *data = spi_get_drvdata(spi_dev); + + if (ssp_send_cmd(data, MSG2SSP_AP_STATUS_SUSPEND) != SUCCESS) + pr_err("[SSP]: %s MSG2SSP_AP_STATUS_SUSPEND failed\n", + __func__); +#endif + func_dbg(); + + return 0; +} + +static int ssp_resume(struct device *dev) +{ +#if 0 + struct spi_device *spi_dev = to_spi_device(dev); + struct ssp_data *data = spi_get_drvdata(spi_dev); + + if (ssp_send_cmd(data, MSG2SSP_AP_STATUS_RESUME) != SUCCESS) + pr_err("[SSP]: %s MSG2SSP_AP_STATUS_RESUME failed\n", + __func__); +#endif + func_dbg(); + + return 0; +} + +static const struct dev_pm_ops ssp_pm_ops = { + .suspend = ssp_suspend, + .resume = ssp_resume +}; +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +static const struct spi_device_id ssp_id[] = { + {"ssp-spi", 0}, + {} +}; + +MODULE_DEVICE_TABLE(spi, ssp_id); + +static struct spi_driver ssp_driver = { + .probe = ssp_probe, + .shutdown = ssp_shutdown, + .id_table = ssp_id, + .driver = { +#ifndef CONFIG_HAS_EARLYSUSPEND + .pm = &ssp_pm_ops, +#endif + .bus = &spi_bus_type, + .owner = THIS_MODULE, + .name = "ssp-spi" + }, +}; + +static int __init ssp_stm_spi_init(void) +{ + int ret; + + pr_info("[SSP] %s\n", __func__); + ret = spi_register_driver(&ssp_driver); + + if (ret) + pr_err("[SSP]failed to register s5c73mc fw - %x\n", ret); + + return ret; +} + +static void __exit ssp_stm_spi_exit(void) +{ + spi_unregister_driver(&ssp_driver); +} + +module_init(ssp_stm_spi_init); +module_exit(ssp_stm_spi_exit); + +MODULE_DESCRIPTION("ssp spi driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/stm/ssp_firmware.c b/drivers/sensorhub/stm/ssp_firmware.c new file mode 100755 index 00000000000..3b077385f52 --- /dev/null +++ b/drivers/sensorhub/stm/ssp_firmware.c @@ -0,0 +1,709 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include + +#include "ssp.h" + +#define SSP_FIRMWARE_REVISION_STM 13061300 /*MCU L5, 6500*/ + +/* Bootload mode cmd */ +#define BL_FW_NAME "ssp_b.fw" +#define BL_UMS_FW_NAME "ssp_b.bin" +#define BL_CRASHED_FW_NAME "ssp_crashed.fw" + +#define BL_UMS_FW_PATH 255 + +#define APP_SLAVE_ADDR 0x18 +#define BOOTLOADER_SLAVE_ADDR 0x26 + +/* Bootloader mode status */ +#define BL_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ +#define BL_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ +#define BL_FRAME_CRC_CHECK 0x02 +#define BL_FRAME_CRC_FAIL 0x03 +#define BL_FRAME_CRC_PASS 0x04 +#define BL_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ +#define BL_BOOT_STATUS_MASK 0x3f + +/* Command to unlock bootloader */ +#define BL_UNLOCK_CMD_MSB 0xaa +#define BL_UNLOCK_CMD_LSB 0xdc + +/* STM */ +#define SSP_STM_DEBUG 0 + +#define SEND_ADDR_LEN 5 +#define BL_SPI_SOF 0x5A +#define BL_ACK 0x79 +#define BL_NACK 0x1F +#define DEF_ACK_CMD_RETRIES 3000 +#define STM_MAX_XFER_SIZE 256 +#define STM_MAX_BUFFER_SIZE 260 +#define STM_APP_ADDR 0x08000000 + +#define WMEM_COMMAND 0x31 /* Write Memory command */ +#define GO_COMMAND 0x21 /* GO command */ +#define EXT_ER_COMMAND 0x44 /* Erase Memory command */ + +#define XOR_WMEM_COMMAND 0xCE /* Write Memory command */ +#define XOR_GO_COMMAND 0xDE /* GO command */ +#define XOR_EXT_ER_COMMAND 0xBB /* Erase Memory command */ + +#define EXT_ER_DATA_LEN 3 + +struct stm32fwu_spi_cmd { + u8 cmd; + u8 xor_cmd; + u8 ack_pad; /* Send this when waiting for an ACK */ + u8 reserved; + int status; /* ACK or NACK (or error) */ + int timeout; /* This is number of retries */ + int ack_loops; +}; + +unsigned int get_module_rev(struct ssp_data *data) +{ + return SSP_FIRMWARE_REVISION_STM; +} + +void stm32_set_ss(unsigned int gpio, int enable) +{ + mdelay(1); + gpio_set_value(gpio, enable); + mdelay(1); +} + +static int stm32fwu_spi_wait_for_ack(struct spi_device *spi, + struct stm32fwu_spi_cmd *cmd, u8 dummy_bytes) +{ + struct spi_message m; + char tx_buf = 0x0; + char rx_buf = 0x0; + struct spi_transfer t = { + .tx_buf = &tx_buf, + .rx_buf = &rx_buf, + .len = 1, + .bits_per_word = 8, + }; + int i = 0; + int ret; + +#if SSP_STM_DEBUG + pr_info("[SSP] %s: dummy byte = 0x%02hhx\n", + __func__, dummy_bytes); +#endif + while (i < cmd->timeout) { + tx_buf = dummy_bytes; + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + ret = spi_sync(spi, &m); + if ((rx_buf == BL_ACK) || (rx_buf == BL_NACK)) { + cmd->ack_loops = i; + usleep_range(1000, 1100); + return (int)rx_buf; + } + usleep_range(1000, 1100); + i++; + } +#if SSP_STM_DEBUG + dev_err(&spi->dev, "%s: Timeout after %d loops\n", + __func__, cmd->timeout); +#endif + return -EIO; +} + +static int stm32fwu_spi_send_cmd(struct spi_device *spi, + struct stm32fwu_spi_cmd *cmd) +{ + u8 tx_buf[3] = {0,}; + u8 rx_buf[3] = {0,}; + u8 dummy_byte = 0; + struct spi_message m; + struct spi_transfer t = { + .tx_buf = tx_buf, + .rx_buf = rx_buf, + .len = 3, + .bits_per_word = 8, + }; + int ret; + + spi_message_init(&m); + + tx_buf[0] = BL_SPI_SOF; + tx_buf[1] = cmd->cmd; + tx_buf[2] = cmd->xor_cmd; + + spi_message_add_tail(&t, &m); + +#if SSP_STM_DEBUG + pr_info("[SSP] tx buffer for cmd is: 0x%02hx 0x%02hx 0x%02hx\n", + tx_buf[0], tx_buf[1], tx_buf[2]); +#endif + ret = spi_sync(spi, &m); + + if ((rx_buf[0] == BL_ACK) || (rx_buf[0] == BL_NACK)) { +#if SSP_STM_DEBUG + pr_info("Found Cmd Ack/NAK (0x%02hhX on first read\n", + rx_buf[0]); +#endif + cmd->ack_loops = 0; + return (int)rx_buf[0]; + } + + usleep_range(5000, 5500); + dummy_byte = cmd->ack_pad; + + /* check for ack/nack and loop until found */ + ret = stm32fwu_spi_wait_for_ack(spi, cmd, dummy_byte); + cmd->status = ret; + + if (ret != BL_ACK) { + pr_err("[SSP] %s: Got NAK or Error %d\n", __func__, ret); + return ret; + } +#if SSP_STM_DEBUG + pr_info("[SSP] Got 0x%02hX for ack after sending cmd 0x%02hX\n", + ret, cmd->cmd); +#endif + + return ret; +} + +static int stm32fwu_spi_write(struct spi_device *spi, + const u8 *buffer, ssize_t len) +{ + int ret; + u8 rx_buf[STM_MAX_BUFFER_SIZE] = {0,}; + struct spi_message m; + struct spi_transfer t = { + .tx_buf = buffer, + .rx_buf = rx_buf, + .len = len, + .bits_per_word = 8, + }; + + if (len > STM_MAX_BUFFER_SIZE) { + pr_err("[SSP] Can't send more than 256 bytes at a time\n"); + return -EINVAL; + } +#if SSP_STM_DEBUG + pr_info("[SSP] Writing %d bytes from buffer @ %p\n", len, buffer); +#endif + spi_message_init(&m); + spi_message_add_tail(&t, &m); + ret = spi_sync(spi, &m); +#if SSP_STM_DEBUG + pr_info("[SSP] %s: spi_sync() returned %d\n", __func__, ret); +#endif + + if (ret < 0) { + pr_err("[SSP] Error in %d spi_read()\n", ret); + return ret; + } + + return len; +} + +static int send_addr(struct spi_device *spi, u32 fw_addr, int send_short) +{ + int res; + int i = send_short; + int len = SEND_ADDR_LEN - send_short; + u8 header[SEND_ADDR_LEN]; + struct stm32fwu_spi_cmd dummy_cmd; + dummy_cmd.timeout = 1000; + + + header[0] = (u8)((fw_addr >> 24) & 0xFF); + header[1] = (u8)((fw_addr >> 16) & 0xFF); + header[2] = (u8)((fw_addr >> 8) & 0xFF); + header[3] = (u8)(fw_addr & 0xFF); + header[4] = header[0] ^ header[1] ^ header[2] ^ header[3]; + if ((i < 0) || (i > 1)) { + pr_err("[SSP] Send short flag must be 0 or 1.\n"); + return -EINVAL; + } + + res = stm32fwu_spi_write(spi, &header[i], len); + + if (res < len) { + pr_err("[SSP] Error in sending address. Res %d\n", res); + return ((res > 0) ? -EIO : res); + } +#if SSP_STM_DEBUG + pr_info("[SSP] send_addr(): wrote addr OK\n"); +#endif + res = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, 0x79); + if (res != BL_ACK) { + pr_err("[SSP] send_addr(): rcv_ack returned 0x%x\n", + res); + return res; + } + return 0; +} + +static int fw_write_stm(struct spi_device *spi, u32 fw_addr, + int len, const u8 *buffer) +{ + int res; + struct stm32fwu_spi_cmd cmd; + struct stm32fwu_spi_cmd dummy_cmd; + int i; + u8 xor = 0; + u8 send_buff[STM_MAX_BUFFER_SIZE] = {0,}; + + cmd.cmd = WMEM_COMMAND; + cmd.xor_cmd = XOR_WMEM_COMMAND; + cmd.timeout = 1000; + cmd.ack_pad = (u8)((fw_addr >> 24) & 0xFF); + dummy_cmd.timeout = 1000; + +#if SSP_STM_DEBUG + pr_info("[SSP] sending WMEM_COMMAND\n"); +#endif + + if (len > STM_MAX_XFER_SIZE) { + pr_err("[SSP] Can't send more than 256 bytes per " + "transaction\n"); + return -EINVAL; + } + + send_buff[0] = len - 1; + memcpy(&send_buff[1], buffer, len); + for (i = 0; i < (len + 1); i++) + xor ^= send_buff[i]; + + send_buff[len + 1] = xor; + + res = stm32fwu_spi_send_cmd(spi, &cmd); + if (res != BL_ACK) { + pr_err("[SSP] Error %d sending read_mem cmd\n", res); + return res; + } + + if (cmd.ack_loops > 0) + res = send_addr(spi, fw_addr, 1); + else + res = send_addr(spi, fw_addr, 0); + + if (res != 0) { + pr_err("[SSP] Error %d sending write_mem Address\n", res); + return res; + } + + res = stm32fwu_spi_write(spi, send_buff, len + 2); + if (res < len) { + pr_err("[SSP] Error writing to flash. res = %d\n", res); + return ((res > 0) ? -EIO : res); + } + + for (i = 0; i < 5; i++) { + res = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, 0x79); + if (res == BL_ACK) + return len; + + if (res == BL_NACK) { + pr_err("[SSP] Got NAK waiting for WRITE_MEM " + "to complete\n"); + return res; + } + } + pr_err("[SSP] timeout waiting for ACK for WRITE_MEM command\n"); + + return -ETIME; +} + +static int load_ums_fw_bootmode(struct spi_device *spi, const char *pFn) +{ + const u8 *buff = NULL; + int remaining; + char fw_path[BL_UMS_FW_PATH+1]; + unsigned int uPos = 0; + unsigned int fw_addr = STM_APP_ADDR; + int iRet = SUCCESS; + int block = STM_MAX_XFER_SIZE; + int count = 0; + int err_count = 0; + int retry_count = 0; + unsigned int uFSize = 0, uNRead = 0; + struct file *fp = NULL; + mm_segment_t old_fs = get_fs(); + + pr_info("[SSP] ssp_load_ums_fw start!!!\n"); + set_fs(get_ds()); + + snprintf(fw_path, BL_UMS_FW_PATH, "/sdcard/ssp/%s", pFn); + + fp = filp_open(fw_path, O_RDONLY, 0); + if (IS_ERR(fp)) { + iRet = ERROR; + pr_err("file %s open error:%d\n", fw_path, (s32)fp); + goto err_open; + } + + uFSize = (unsigned int)fp->f_path.dentry->d_inode->i_size; + pr_info("ssp_load_ums firmware size: %u\n", uFSize); + + buff = kzalloc((size_t)uFSize, GFP_KERNEL); + if (!buff) { + iRet = ERROR; + pr_err("fail to alloc buffer for fw\n"); + goto err_alloc; + } + + uNRead = (unsigned int)vfs_read(fp, (char __user *)buff, + (unsigned int)uFSize, &fp->f_pos); + if (uNRead != uFSize) { + iRet = ERROR; + pr_err("fail to read file %s (nread = %u)\n", fw_path, uNRead); + goto err_fw_size; + } + + remaining = (int)uFSize; + while (remaining > 0) { + if (block > remaining) + block = remaining; + + while (retry_count < 3) { + iRet = fw_write_stm(spi, fw_addr, block, buff + uPos); + if (iRet < block) { + pr_err("[SSP] Error writing to addr 0x%08X\n", + fw_addr); + if (iRet < 0) { + pr_err("[SSP] Erro was %d\n", iRet); + } else { + pr_err("[SSP] Incomplete write of %d " + "bytes\n", iRet); + iRet = -EIO; + } + retry_count++; + err_count++; + } else { + retry_count = 0; + break; + } + } + if (iRet < 0) + pr_err("[SSP] Writing MEM failed: %d, retry cont: %d\n", + iRet, err_count); + + remaining -= block; + uPos += block; + fw_addr += block; + if (count++ == 20) { + pr_info("[SSP] Updated %u bytes / %u bytes\n", uPos, + uFSize); + count = 0; + } + } + + pr_info("[SSP] Firmware download is success.(%d bytes, retry %d)\n", + uPos, err_count); + +out: +err_fw_size: + kfree(buff); +err_alloc: + filp_close(fp, NULL); +err_open: + set_fs(old_fs); + return iRet; +} + +static int fw_erase_stm(struct spi_device *spi) +{ + struct stm32fwu_spi_cmd cmd; + struct stm32fwu_spi_cmd dummy_cmd; + int ret; + char buff[EXT_ER_DATA_LEN] = {0xff, 0xff, 0x00}; + + cmd.cmd = EXT_ER_COMMAND; + cmd.xor_cmd = XOR_EXT_ER_COMMAND; + cmd.timeout = 1000; + cmd.ack_pad = 0xFF; + dummy_cmd.timeout = DEF_ACK_CMD_RETRIES; + + ret = stm32fwu_spi_send_cmd(spi, &cmd); + + if (ret < 0 || ret != BL_ACK) { + pr_err("[SSP] fw_erase failed\n"); + return -EIO; + } + if (cmd.ack_loops == 0) + ret = stm32fwu_spi_write(spi, buff, EXT_ER_DATA_LEN); + else + ret = stm32fwu_spi_write(spi, buff, EXT_ER_DATA_LEN-1); + +#if SSP_STM_DEBUG + pr_info("[SSP] %s: stm32fwu_spi_write(sync byte) returned %d\n", + __func__, ret); +#endif + + ret = stm32fwu_spi_wait_for_ack(spi, &dummy_cmd, 0x79); + +#if SSP_STM_DEBUG + pr_info("[SSP] %s: stm32fwu_spi_wait_for_ack returned %d (0x%x)\n", + __func__, ret, ret); +#endif + + return ret; + +} +static int load_kernel_fw_bootmode(struct spi_device *spi, const char *pFn) +{ + const struct firmware *fw = NULL; + int remaining; + unsigned int uPos = 0; + unsigned int fw_addr = STM_APP_ADDR; + int iRet = SUCCESS; + int block = STM_MAX_XFER_SIZE; + int count = 0; + int err_count = 0; + int retry_count = 0; + + pr_info("[SSP] ssp_load_fw start!!!\n"); + + iRet = request_firmware(&fw, pFn, &spi->dev); + if (iRet) { + pr_err("[SSP] Unable to open firmware %s\n", pFn); + return iRet; + } + + remaining = fw->size; + while (remaining > 0) { + if (block > remaining) + block = remaining; + + while (retry_count < 3) { + iRet = fw_write_stm(spi, fw_addr, block, + fw->data + uPos); + if (iRet < block) { + pr_err("[SSP] Error writing to addr 0x%08X\n", + fw_addr); + if (iRet < 0) { + pr_err("[SSP] Erro was %d\n", iRet); + } else { + pr_err("[SSP] Incomplete write of %d " + "bytes\n", iRet); + iRet = -EIO; + } + retry_count++; + err_count++; + } else { + retry_count = 0; + break; + } + } + if (iRet < 0) { + pr_err("[SSP] Writing MEM failed: %d, retry cont: %d\n", + iRet, err_count); + } + remaining -= block; + uPos += block; + fw_addr += block; + if (count++ == 20) { + pr_info("[SSP] Updated %u bytes / %u bytes\n", uPos, + fw->size); + count = 0; + } + } + + pr_info("[SSP] Firmware download is success.(%d bytes, retry %d)\n", + uPos, err_count); + +out: + release_firmware(fw); + return iRet; +} + +static void change_to_bootmode(struct ssp_data *data) +{ + int iCnt; + int ret; + char syncb = BL_SPI_SOF; + struct stm32fwu_spi_cmd dummy_cmd; + + dummy_cmd.timeout = DEF_ACK_CMD_RETRIES; + + data->set_mcu_reset(0); + mdelay(4); + data->set_mcu_reset(1); + usleep_range(45000, 47000); + + for (iCnt = 0; iCnt < 9; iCnt++) { + data->set_mcu_reset(0); + usleep_range(4000, 4200); + data->set_mcu_reset(1); + usleep_range(15000, 15500); + } + + ret = stm32fwu_spi_write(data->spi, &syncb, 1); +#if SSP_STM_DEBUG + pr_info("[SSP] stm32fwu_spi_write(sync byte) returned %d\n", ret); +#endif + ret = stm32fwu_spi_wait_for_ack(data->spi, &dummy_cmd, 0x79); +#if SSP_STM_DEBUG + pr_info("[SSP] stm32fwu_spi_wait_for_ack returned %d (0x%x)\n", + ret, ret); +#endif +} + +void toggle_mcu_reset(struct ssp_data *data) +{ + data->set_mcu_reset(0); + usleep_range(1000, 1200); + data->set_mcu_reset(1); + msleep(50); +} + +static int update_mcu_bin(struct ssp_data *data, int iBinType) +{ + int iRet = SUCCESS; + struct stm32fwu_spi_cmd cmd; + + cmd.cmd = GO_COMMAND; + cmd.xor_cmd = XOR_GO_COMMAND; + cmd.timeout = 1000; + cmd.ack_pad = (u8)((STM_APP_ADDR >> 24) & 0xFF); + + pr_info("[SSP] ssp_change_to_bootmode\n"); + + change_to_bootmode(data); + + iRet = fw_erase_stm(data->spi); + if (iRet < 0) { + pr_err("[SSP]: %s - fw_erase_stm %d\n", + __func__, iRet); + return iRet; + } + + /* After erase put bootmode again: debug */ + change_to_bootmode(data); + + switch (iBinType) { + case KERNEL_BINARY: + iRet = load_kernel_fw_bootmode(data->spi, + BL_FW_NAME); + break; + + case KERNEL_CRASHED_BINARY: + iRet = load_kernel_fw_bootmode(data->spi, + BL_CRASHED_FW_NAME); + break; + case UMS_BINARY: + iRet = load_ums_fw_bootmode(data->spi, + BL_UMS_FW_NAME); + break; + + default: + pr_err("[SSP] binary type error!!\n"); + } + + /* STM : GO USER ADDR */ + stm32fwu_spi_send_cmd(data->spi, &cmd); + if (cmd.ack_loops > 0) + send_addr(data->spi, STM_APP_ADDR, 1); + else + send_addr(data->spi, STM_APP_ADDR, 0); + + msleep(SSP_SW_RESET_TIME); + + return iRet; +} + +int forced_to_download_binary(struct ssp_data *data, int iBinType) +{ + int iRet = 0; + int retry = 3; + + ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__); + + ssp_enable(data, false); + + data->fw_dl_state = FW_DL_STATE_DOWNLOADING; + pr_info("[SSP] %s, DL state = %d\n", __func__, + data->fw_dl_state); + do { + pr_info("[SSP] %d try\n", 3 - retry); + iRet = update_mcu_bin(data, iBinType); + } while (retry -- > 0 && iRet < 0); + + if (iRet < 0) { + ssp_dbg("[SSP]: %s - update_mcu_bin failed!\n", __func__); + goto out; + } + + data->fw_dl_state = FW_DL_STATE_SYNC; + pr_info("[SSP] %s, DL state = %d\n", __func__, data->fw_dl_state); + iRet = initialize_mcu(data); + if (iRet < 0) { + iRet = ERROR; + ssp_dbg("[SSP]: %s - initialize_mcu failed!\n", __func__); + goto out; + } + + ssp_enable(data, true); + sync_sensor_state(data); + +#ifdef CONFIG_SENSORS_SSP_SENSORHUB + ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_RESET); +#endif + + data->fw_dl_state = FW_DL_STATE_DONE; + pr_info("[SSP] %s, DL state = %d\n", __func__, data->fw_dl_state); + + iRet = SUCCESS; +out: + return iRet; +} + +static unsigned int check_firmware_rev(struct ssp_data *data) +{ + char chTxData = MSG2SSP_AP_FIRMWARE_REV; + char chRxBuf[3] = {0,}; + unsigned int uRev = SSP_INVALID_REVISION; + int iRet; + + iRet = ssp_read_data(data, &chTxData, 1, chRxBuf, 3, DEFAULT_RETRIES); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - spi fail %d\n", __func__, iRet); + } else + uRev = ((unsigned int)chRxBuf[0] << 16) + | ((unsigned int)chRxBuf[1] << 8) | chRxBuf[2]; + return uRev; +} + +int check_fwbl(struct ssp_data *data) +{ + unsigned int fw_revision; + + fw_revision = SSP_FIRMWARE_REVISION_STM; + data->uCurFirmRev = check_firmware_rev(data); + + if (data->uCurFirmRev == SSP_INVALID_REVISION) { + pr_err("[SSP] SSP_INVALID_REVISION\n"); + return FW_DL_STATE_NEED_TO_SCHEDULE; + + } else { + pr_info("[SSP] MCU Firm Rev : Old = %8u, New = %8u\n", + data->uCurFirmRev, fw_revision); + + if (data->uCurFirmRev != fw_revision) + return FW_DL_STATE_NEED_TO_SCHEDULE; + } + + return FW_DL_STATE_NONE; +} diff --git a/drivers/sensorhub/stm/ssp_input.c b/drivers/sensorhub/stm/ssp_input.c new file mode 100755 index 00000000000..96c06c57e16 --- /dev/null +++ b/drivers/sensorhub/stm/ssp_input.c @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* SSP Kernel -> HAL input evnet function */ +/*************************************************************************/ +void convert_acc_data(s16 *iValue) +{ + if (*iValue > MAX_ACCEL_2G) + *iValue = ((MAX_ACCEL_4G - *iValue)) * (-1); +} + +void report_acc_data(struct ssp_data *data, struct sensor_value *accdata) +{ + convert_acc_data(&accdata->x); + convert_acc_data(&accdata->y); + convert_acc_data(&accdata->z); + + data->buf[ACCELEROMETER_SENSOR].x = accdata->x - data->accelcal.x; + data->buf[ACCELEROMETER_SENSOR].y = accdata->y - data->accelcal.y; + data->buf[ACCELEROMETER_SENSOR].z = accdata->z - data->accelcal.z; + + if (!(data->buf[ACCELEROMETER_SENSOR].x >> 15 == accdata->x >> 15) &&\ + !(data->accelcal.x >> 15 == accdata->x >> 15)) { + pr_debug("[SSP] : accel x is overflowed!\n"); + data->buf[ACCELEROMETER_SENSOR].x = + (data->buf[ACCELEROMETER_SENSOR].x > 0 ? MIN_ACCEL_2G : MAX_ACCEL_2G); + } + if (!(data->buf[ACCELEROMETER_SENSOR].y >> 15 == accdata->y >> 15) &&\ + !(data->accelcal.y >> 15 == accdata->y >> 15)) { + pr_debug("[SSP] : accel y is overflowed!\n"); + data->buf[ACCELEROMETER_SENSOR].y = + (data->buf[ACCELEROMETER_SENSOR].y > 0 ? MIN_ACCEL_2G : MAX_ACCEL_2G); + } + if (!(data->buf[ACCELEROMETER_SENSOR].z >> 15 == accdata->z >> 15) &&\ + !(data->accelcal.z >> 15 == accdata->z >> 15)) { + pr_debug("[SSP] : accel z is overflowed!\n"); + data->buf[ACCELEROMETER_SENSOR].z = + (data->buf[ACCELEROMETER_SENSOR].z > 0 ? MIN_ACCEL_2G : MAX_ACCEL_2G); + } + + input_report_rel(data->acc_input_dev, REL_X, + data->buf[ACCELEROMETER_SENSOR].x); + input_report_rel(data->acc_input_dev, REL_Y, + data->buf[ACCELEROMETER_SENSOR].y); + input_report_rel(data->acc_input_dev, REL_Z, + data->buf[ACCELEROMETER_SENSOR].z); + input_sync(data->acc_input_dev); +} + +void report_gyro_data(struct ssp_data *data, struct sensor_value *gyrodata) +{ + long lTemp[3] = {0,}; + + data->buf[GYROSCOPE_SENSOR].x = gyrodata->x - data->gyrocal.x; + data->buf[GYROSCOPE_SENSOR].y = gyrodata->y - data->gyrocal.y; + data->buf[GYROSCOPE_SENSOR].z = gyrodata->z - data->gyrocal.z; + + if (!(data->buf[GYROSCOPE_SENSOR].x >> 15 == gyrodata->x >> 15) &&\ + !(data->gyrocal.x >> 15 == gyrodata->x >> 15)) { + pr_debug("[SSP] : gyro x is overflowed!\n"); + data->buf[GYROSCOPE_SENSOR].x = + (data->buf[GYROSCOPE_SENSOR].x >= 0 ? MIN_GYRO : MAX_GYRO); + } + if (!(data->buf[GYROSCOPE_SENSOR].y >> 15 == gyrodata->y >> 15) &&\ + !(data->gyrocal.y >> 15 == gyrodata->y >> 15)) { + pr_debug("[SSP] : gyro y is overflowed!\n"); + data->buf[GYROSCOPE_SENSOR].y = + (data->buf[GYROSCOPE_SENSOR].y >= 0 ? MIN_GYRO : MAX_GYRO); + } + if (!(data->buf[GYROSCOPE_SENSOR].z >> 15 == gyrodata->z >> 15) &&\ + !(data->gyrocal.z >> 15 == gyrodata->z >> 15)) { + pr_debug("[SSP] : gyro z is overflowed!\n"); + data->buf[GYROSCOPE_SENSOR].z = + (data->buf[GYROSCOPE_SENSOR].z >= 0 ? MIN_GYRO : MAX_GYRO); + } + + if (data->uGyroDps == GYROSCOPE_DPS500) { + lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x; + lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y; + lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z; + } else if (data->uGyroDps == GYROSCOPE_DPS250) { + lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x >> 1; + lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y >> 1; + lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z >> 1; + } else if (data->uGyroDps == GYROSCOPE_DPS2000) { + lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x << 2; + lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y << 2; + lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z << 2; + } else { + lTemp[0] = (long)data->buf[GYROSCOPE_SENSOR].x; + lTemp[1] = (long)data->buf[GYROSCOPE_SENSOR].y; + lTemp[2] = (long)data->buf[GYROSCOPE_SENSOR].z; + } + + input_report_rel(data->gyro_input_dev, REL_RX, lTemp[0]); + input_report_rel(data->gyro_input_dev, REL_RY, lTemp[1]); + input_report_rel(data->gyro_input_dev, REL_RZ, lTemp[2]); + input_sync(data->gyro_input_dev); +} + +void report_mag_data(struct ssp_data *data, struct sensor_value *magdata) +{ + data->buf[GEOMAGNETIC_SENSOR].x = magdata->x; + data->buf[GEOMAGNETIC_SENSOR].y = magdata->y; + data->buf[GEOMAGNETIC_SENSOR].z = magdata->z; + + input_report_rel(data->mag_input_dev, REL_RX, + data->buf[GEOMAGNETIC_SENSOR].x); + input_report_rel(data->mag_input_dev, REL_RY, + data->buf[GEOMAGNETIC_SENSOR].y); + input_report_rel(data->mag_input_dev, REL_RZ, + data->buf[GEOMAGNETIC_SENSOR].z); + input_sync(data->mag_input_dev); +} + +void report_gesture_data(struct ssp_data *data, struct sensor_value *gesdata) +{ + data->buf[GESTURE_SENSOR].data[0] = gesdata->data[0]; + data->buf[GESTURE_SENSOR].data[1] = gesdata->data[1]; + data->buf[GESTURE_SENSOR].data[2] = gesdata->data[2]; + data->buf[GESTURE_SENSOR].data[3] = gesdata->data[3]; + data->buf[GESTURE_SENSOR].data[4] = data->uTempCount; + + data->buf[GESTURE_SENSOR].data[5] = gesdata->data[5]; /* a_delta */ + data->buf[GESTURE_SENSOR].data[6] = gesdata->data[6]; /* b_delta */ + data->buf[GESTURE_SENSOR].data[7] = gesdata->data[7]; /* c_delta */ + data->buf[GESTURE_SENSOR].data[8] = gesdata->data[8]; /* d_delta */ + + input_report_abs(data->gesture_input_dev, + ABS_RUDDER, data->buf[GESTURE_SENSOR].data[0]); + input_report_abs(data->gesture_input_dev, + ABS_WHEEL, data->buf[GESTURE_SENSOR].data[1]); + input_report_abs(data->gesture_input_dev, + ABS_GAS, data->buf[GESTURE_SENSOR].data[2]); + input_report_abs(data->gesture_input_dev, + ABS_BRAKE, data->buf[GESTURE_SENSOR].data[3]); + input_report_abs(data->gesture_input_dev, + ABS_THROTTLE, data->buf[GESTURE_SENSOR].data[4]); + input_report_abs(data->gesture_input_dev, + ABS_X, data->buf[GESTURE_SENSOR].data[5]); + input_report_abs(data->gesture_input_dev, + ABS_Y, data->buf[GESTURE_SENSOR].data[6]); + input_report_abs(data->gesture_input_dev, + ABS_Z, data->buf[GESTURE_SENSOR].data[7]); + input_report_abs(data->gesture_input_dev, + ABS_RX, data->buf[GESTURE_SENSOR].data[8]); + input_sync(data->gesture_input_dev); + + data->uTempCount++; + +} + +void report_pressure_data(struct ssp_data *data, struct sensor_value *predata) +{ + data->buf[PRESSURE_SENSOR].pressure[0] = + predata->pressure[0] - data->iPressureCal; + data->buf[PRESSURE_SENSOR].pressure[1] = predata->pressure[1]; + + /* pressure */ + input_report_rel(data->pressure_input_dev, REL_HWHEEL, + data->buf[PRESSURE_SENSOR].pressure[0]); + /* temperature */ + input_report_rel(data->pressure_input_dev, REL_WHEEL, + data->buf[PRESSURE_SENSOR].pressure[1]); + input_sync(data->pressure_input_dev); +} + +void report_light_data(struct ssp_data *data, struct sensor_value *lightdata) +{ + data->buf[LIGHT_SENSOR].r = lightdata->r; + data->buf[LIGHT_SENSOR].g = lightdata->g; + data->buf[LIGHT_SENSOR].b = lightdata->b; + data->buf[LIGHT_SENSOR].w = lightdata->w; + + input_report_rel(data->light_input_dev, REL_HWHEEL, + data->buf[LIGHT_SENSOR].r + 1); + input_report_rel(data->light_input_dev, REL_DIAL, + data->buf[LIGHT_SENSOR].g + 1); + input_report_rel(data->light_input_dev, REL_WHEEL, + data->buf[LIGHT_SENSOR].b + 1); + input_report_rel(data->light_input_dev, REL_MISC, + data->buf[LIGHT_SENSOR].w + 1); + input_sync(data->light_input_dev); +} + +void report_prox_data(struct ssp_data *data, struct sensor_value *proxdata) +{ + ssp_dbg("[SSP] Proximity Sensor Detect : %u, raw : %u\n", + proxdata->prox[0], proxdata->prox[1]); + + data->buf[PROXIMITY_SENSOR].prox[0] = proxdata->prox[0]; + data->buf[PROXIMITY_SENSOR].prox[1] = proxdata->prox[1]; + + input_report_abs(data->prox_input_dev, ABS_DISTANCE, + (!proxdata->prox[0])); + input_sync(data->prox_input_dev); + + wake_lock_timeout(&data->ssp_wake_lock, 3 * HZ); +} + +void report_prox_raw_data(struct ssp_data *data, + struct sensor_value *proxrawdata) +{ + if (data->uFactoryProxAvg[0]++ >= PROX_AVG_READ_NUM) { + data->uFactoryProxAvg[2] /= PROX_AVG_READ_NUM; + data->buf[PROXIMITY_RAW].prox[1] = (u8)data->uFactoryProxAvg[1]; + data->buf[PROXIMITY_RAW].prox[2] = (u8)data->uFactoryProxAvg[2]; + data->buf[PROXIMITY_RAW].prox[3] = (u8)data->uFactoryProxAvg[3]; + + data->uFactoryProxAvg[0] = 0; + data->uFactoryProxAvg[1] = 0; + data->uFactoryProxAvg[2] = 0; + data->uFactoryProxAvg[3] = 0; + } else { + data->uFactoryProxAvg[2] += proxrawdata->prox[0]; + + if (data->uFactoryProxAvg[0] == 1) + data->uFactoryProxAvg[1] = proxrawdata->prox[0]; + else if (proxrawdata->prox[0] < data->uFactoryProxAvg[1]) + data->uFactoryProxAvg[1] = proxrawdata->prox[0]; + + if (proxrawdata->prox[0] > data->uFactoryProxAvg[3]) + data->uFactoryProxAvg[3] = proxrawdata->prox[0]; + } + + data->buf[PROXIMITY_RAW].prox[0] = proxrawdata->prox[0]; +} + +void report_geomagnetic_raw_data(struct ssp_data *data, + struct sensor_value *magrawdata) +{ + data->buf[GEOMAGNETIC_RAW].x = magrawdata->x; + data->buf[GEOMAGNETIC_RAW].y = magrawdata->y; + data->buf[GEOMAGNETIC_RAW].z = magrawdata->z; +} + +void report_temp_humidity_data(struct ssp_data *data, + struct sensor_value *temp_humi_data) +{ + data->buf[TEMPERATURE_HUMIDITY_SENSOR].data[0] = + temp_humi_data->data[0]; + data->buf[TEMPERATURE_HUMIDITY_SENSOR].data[1] = + temp_humi_data->data[1]; + data->buf[TEMPERATURE_HUMIDITY_SENSOR].data[2] = + temp_humi_data->data[2]; + + /* Temperature */ + input_report_rel(data->temp_humi_input_dev, REL_HWHEEL, + data->buf[TEMPERATURE_HUMIDITY_SENSOR].data[0]); + /* Humidity */ + input_report_rel(data->temp_humi_input_dev, REL_DIAL, + data->buf[TEMPERATURE_HUMIDITY_SENSOR].data[1]); + + /* Compensation engine cmd */ + if (data->comp_engine_cmd != SHTC1_CMD_NONE) { + input_report_rel(data->temp_humi_input_dev, REL_WHEEL, + data->comp_engine_cmd); + data->comp_engine_cmd = SHTC1_CMD_NONE; + } + input_sync(data->temp_humi_input_dev); + if (data->buf[TEMPERATURE_HUMIDITY_SENSOR].data[2]) + wake_lock_timeout(&data->ssp_wake_lock, 2 * HZ); +} + +int initialize_event_symlink(struct ssp_data *data) +{ + int iRet = 0; + + iRet = sensors_create_symlink(&data->acc_input_dev->dev.kobj, + data->acc_input_dev->name); + if (iRet < 0) + goto iRet_acc_sysfs_create_link; + + iRet = sensors_create_symlink(&data->gyro_input_dev->dev.kobj, + data->gyro_input_dev->name); + if (iRet < 0) + goto iRet_gyro_sysfs_create_link; + + iRet = sensors_create_symlink(&data->pressure_input_dev->dev.kobj, + data->pressure_input_dev->name); + if (iRet < 0) + goto iRet_prs_sysfs_create_link; + + iRet = sensors_create_symlink(&data->gesture_input_dev->dev.kobj, + data->gesture_input_dev->name); + if (iRet < 0) + goto iRet_gesture_sysfs_create_link; + + iRet = sensors_create_symlink(&data->light_input_dev->dev.kobj, + data->light_input_dev->name); + if (iRet < 0) + goto iRet_light_sysfs_create_link; + + iRet = sensors_create_symlink(&data->prox_input_dev->dev.kobj, + data->prox_input_dev->name); + if (iRet < 0) + goto iRet_prox_sysfs_create_link; + + iRet = sensors_create_symlink(&data->temp_humi_input_dev->dev.kobj, + data->temp_humi_input_dev->name); + if (iRet < 0) + goto iRet_temp_humi_sysfs_create_link; + + iRet = sensors_create_symlink(&data->mag_input_dev->dev.kobj, + data->mag_input_dev->name); + if (iRet < 0) + goto iRet_mag_sysfs_create_link; + + return SUCCESS; +iRet_mag_sysfs_create_link: + sensors_remove_symlink(&data->temp_humi_input_dev->dev.kobj, + data->temp_humi_input_dev->name); +iRet_temp_humi_sysfs_create_link: + sensors_remove_symlink(&data->prox_input_dev->dev.kobj, + data->prox_input_dev->name); +iRet_prox_sysfs_create_link: + sensors_remove_symlink(&data->light_input_dev->dev.kobj, + data->light_input_dev->name); +iRet_light_sysfs_create_link: + sensors_remove_symlink(&data->gesture_input_dev->dev.kobj, + data->gesture_input_dev->name); +iRet_gesture_sysfs_create_link: + sensors_remove_symlink(&data->pressure_input_dev->dev.kobj, + data->pressure_input_dev->name); +iRet_prs_sysfs_create_link: + sensors_remove_symlink(&data->gyro_input_dev->dev.kobj, + data->gyro_input_dev->name); +iRet_gyro_sysfs_create_link: + sensors_remove_symlink(&data->acc_input_dev->dev.kobj, + data->acc_input_dev->name); +iRet_acc_sysfs_create_link: + pr_err("[SSP]: %s - could not create event symlink\n", __func__); + + return FAIL; +} + +void remove_event_symlink(struct ssp_data *data) +{ + sensors_remove_symlink(&data->acc_input_dev->dev.kobj, + data->acc_input_dev->name); + sensors_remove_symlink(&data->gyro_input_dev->dev.kobj, + data->gyro_input_dev->name); + sensors_remove_symlink(&data->pressure_input_dev->dev.kobj, + data->pressure_input_dev->name); + sensors_remove_symlink(&data->gesture_input_dev->dev.kobj, + data->gesture_input_dev->name); + sensors_remove_symlink(&data->light_input_dev->dev.kobj, + data->light_input_dev->name); + sensors_remove_symlink(&data->prox_input_dev->dev.kobj, + data->prox_input_dev->name); + sensors_remove_symlink(&data->temp_humi_input_dev->dev.kobj, + data->temp_humi_input_dev->name); + sensors_remove_symlink(&data->mag_input_dev->dev.kobj, + data->mag_input_dev->name); +} + +int initialize_input_dev(struct ssp_data *data) +{ + int iRet = 0; + struct input_dev *acc_input_dev, *gyro_input_dev, *pressure_input_dev, + *light_input_dev, *prox_input_dev, *temp_humi_input_dev, + *mag_input_dev, *gesture_input_dev; + + /* allocate input_device */ + acc_input_dev = input_allocate_device(); + if (acc_input_dev == NULL) + goto iRet_acc_input_free_device; + + gyro_input_dev = input_allocate_device(); + if (gyro_input_dev == NULL) + goto iRet_gyro_input_free_device; + + pressure_input_dev = input_allocate_device(); + if (pressure_input_dev == NULL) + goto iRet_pressure_input_free_device; + + gesture_input_dev = input_allocate_device(); + if (gesture_input_dev == NULL) + goto iRet_gesture_input_free_device; + + light_input_dev = input_allocate_device(); + if (light_input_dev == NULL) + goto iRet_light_input_free_device; + + prox_input_dev = input_allocate_device(); + if (prox_input_dev == NULL) + goto iRet_proximity_input_free_device; + + temp_humi_input_dev = input_allocate_device(); + if (temp_humi_input_dev == NULL) + goto iRet_temp_humidity_input_free_device; + + mag_input_dev = input_allocate_device(); + if (mag_input_dev == NULL) + goto iRet_mag_input_free_device; + + input_set_drvdata(acc_input_dev, data); + input_set_drvdata(gyro_input_dev, data); + input_set_drvdata(pressure_input_dev, data); + input_set_drvdata(gesture_input_dev, data); + input_set_drvdata(light_input_dev, data); + input_set_drvdata(prox_input_dev, data); + input_set_drvdata(temp_humi_input_dev, data); + input_set_drvdata(mag_input_dev, data); + + acc_input_dev->name = "accelerometer_sensor"; + gyro_input_dev->name = "gyro_sensor"; + pressure_input_dev->name = "pressure_sensor"; + gesture_input_dev->name = "gesture_sensor"; + light_input_dev->name = "light_sensor"; + prox_input_dev->name = "proximity_sensor"; + temp_humi_input_dev->name = "temp_humidity_sensor"; + mag_input_dev->name = "geomagnetic_sensor"; + + input_set_capability(acc_input_dev, EV_REL, REL_X); + input_set_capability(acc_input_dev, EV_REL, REL_Y); + input_set_capability(acc_input_dev, EV_REL, REL_Z); + + input_set_capability(gyro_input_dev, EV_REL, REL_RX); + input_set_capability(gyro_input_dev, EV_REL, REL_RY); + input_set_capability(gyro_input_dev, EV_REL, REL_RZ); + + input_set_capability(pressure_input_dev, EV_REL, REL_HWHEEL); + input_set_capability(pressure_input_dev, EV_REL, REL_DIAL); + input_set_capability(pressure_input_dev, EV_REL, REL_WHEEL); + + input_set_capability(gesture_input_dev, EV_ABS, ABS_RUDDER); + input_set_abs_params(gesture_input_dev, ABS_RUDDER, 0, 1024, 0, 0); + input_set_capability(gesture_input_dev, EV_ABS, ABS_WHEEL); + input_set_abs_params(gesture_input_dev, ABS_WHEEL, 0, 1024, 0, 0); + input_set_capability(gesture_input_dev, EV_ABS, ABS_GAS); + input_set_abs_params(gesture_input_dev, ABS_GAS, 0, 1024, 0, 0); + input_set_capability(gesture_input_dev, EV_ABS, ABS_BRAKE); + input_set_abs_params(gesture_input_dev, ABS_BRAKE, 0, 1024, 0, 0); + input_set_capability(gesture_input_dev, EV_ABS, ABS_THROTTLE); + input_set_abs_params(gesture_input_dev, ABS_THROTTLE, 0, 1024, 0, 0); + input_set_capability(gesture_input_dev, EV_ABS, ABS_X); + input_set_abs_params(gesture_input_dev, ABS_X, 0, 1024, 0, 0); + input_set_capability(gesture_input_dev, EV_ABS, ABS_Y); + input_set_abs_params(gesture_input_dev, ABS_Y, 0, 1024, 0, 0); + input_set_capability(gesture_input_dev, EV_ABS, ABS_Z); + input_set_abs_params(gesture_input_dev, ABS_Z, 0, 1024, 0, 0); + input_set_capability(gesture_input_dev, EV_ABS, ABS_RX); + input_set_abs_params(gesture_input_dev, ABS_RX, 0, 1024, 0, 0); + + input_set_capability(light_input_dev, EV_REL, REL_HWHEEL); + input_set_capability(light_input_dev, EV_REL, REL_DIAL); + input_set_capability(light_input_dev, EV_REL, REL_WHEEL); + input_set_capability(light_input_dev, EV_REL, REL_MISC); + + input_set_capability(prox_input_dev, EV_ABS, ABS_DISTANCE); + input_set_abs_params(prox_input_dev, ABS_DISTANCE, 0, 1, 0, 0); + + input_set_capability(temp_humi_input_dev, EV_REL, REL_HWHEEL); + input_set_capability(temp_humi_input_dev, EV_REL, REL_DIAL); + + input_set_capability(mag_input_dev, EV_REL, REL_RX); + input_set_capability(mag_input_dev, EV_REL, REL_RY); + input_set_capability(mag_input_dev, EV_REL, REL_RZ); + + /* register input_device */ + iRet = input_register_device(acc_input_dev); + if (iRet < 0) + goto iRet_acc_input_unreg_device; + + iRet = input_register_device(gyro_input_dev); + if (iRet < 0) { + input_free_device(gyro_input_dev); + input_free_device(pressure_input_dev); + input_free_device(gesture_input_dev); + input_free_device(light_input_dev); + input_free_device(prox_input_dev); + input_free_device(temp_humi_input_dev); + input_free_device(mag_input_dev); + goto iRet_gyro_input_unreg_device; + } + + iRet = input_register_device(pressure_input_dev); + if (iRet < 0) { + input_free_device(pressure_input_dev); + input_free_device(gesture_input_dev); + input_free_device(light_input_dev); + input_free_device(prox_input_dev); + input_free_device(temp_humi_input_dev); + input_free_device(mag_input_dev); + goto iRet_pressure_input_unreg_device; + } + + iRet = input_register_device(gesture_input_dev); + if (iRet < 0) { + input_free_device(gesture_input_dev); + input_free_device(light_input_dev); + input_free_device(prox_input_dev); + input_free_device(temp_humi_input_dev); + input_free_device(mag_input_dev); + goto iRet_gesture_input_unreg_device; + } + + iRet = input_register_device(light_input_dev); + if (iRet < 0) { + input_free_device(light_input_dev); + input_free_device(prox_input_dev); + input_free_device(temp_humi_input_dev); + input_free_device(mag_input_dev); + goto iRet_light_input_unreg_device; + } + + iRet = input_register_device(prox_input_dev); + if (iRet < 0) { + input_free_device(prox_input_dev); + input_free_device(temp_humi_input_dev); + input_free_device(mag_input_dev); + goto iRet_proximity_input_unreg_device; + } + + iRet = input_register_device(temp_humi_input_dev); + if (iRet < 0) { + input_free_device(temp_humi_input_dev); + input_free_device(mag_input_dev); + goto iRet_tmep_humi_input_unreg_device; + } + + iRet = input_register_device(mag_input_dev); + if (iRet < 0) { + input_free_device(mag_input_dev); + goto iRet_mag_input_unreg_device; + } + + data->acc_input_dev = acc_input_dev; + data->gyro_input_dev = gyro_input_dev; + data->pressure_input_dev = pressure_input_dev; + data->gesture_input_dev = gesture_input_dev; + data->light_input_dev = light_input_dev; + data->prox_input_dev = prox_input_dev; + data->temp_humi_input_dev = temp_humi_input_dev; + data->mag_input_dev = mag_input_dev; + + return SUCCESS; + +iRet_mag_input_unreg_device: + input_unregister_device(temp_humi_input_dev); +iRet_tmep_humi_input_unreg_device: + input_unregister_device(prox_input_dev); +iRet_proximity_input_unreg_device: + input_unregister_device(light_input_dev); +iRet_light_input_unreg_device: + input_unregister_device(pressure_input_dev); +iRet_pressure_input_unreg_device: + input_unregister_device(gyro_input_dev); +iRet_gesture_input_unreg_device: + input_unregister_device(gesture_input_dev); +iRet_gyro_input_unreg_device: + input_unregister_device(acc_input_dev); + return ERROR; +iRet_acc_input_unreg_device: + pr_err("[SSP]: %s - could not register input device\n", __func__); + input_free_device(mag_input_dev); +iRet_mag_input_free_device: + input_free_device(temp_humi_input_dev); +iRet_temp_humidity_input_free_device: + input_free_device(prox_input_dev); +iRet_proximity_input_free_device: + input_free_device(light_input_dev); +iRet_light_input_free_device: + input_free_device(pressure_input_dev); +iRet_gesture_input_free_device: + input_free_device(gesture_input_dev); +iRet_pressure_input_free_device: + input_free_device(gyro_input_dev); +iRet_gyro_input_free_device: + input_free_device(acc_input_dev); +iRet_acc_input_free_device: + pr_err("[SSP]: %s - could not allocate input device\n", __func__); + return ERROR; +} + +void remove_input_dev(struct ssp_data *data) +{ + input_unregister_device(data->acc_input_dev); + input_unregister_device(data->gyro_input_dev); + input_unregister_device(data->pressure_input_dev); + input_unregister_device(data->gesture_input_dev); + input_unregister_device(data->light_input_dev); + input_unregister_device(data->prox_input_dev); + input_unregister_device(data->temp_humi_input_dev); + input_unregister_device(data->mag_input_dev); +} diff --git a/drivers/sensorhub/stm/ssp_sensorhub.c b/drivers/sensorhub/stm/ssp_sensorhub.c new file mode 100755 index 00000000000..4a817e53043 --- /dev/null +++ b/drivers/sensorhub/stm/ssp_sensorhub.c @@ -0,0 +1,622 @@ +/* + * Copyright (C) 2013, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ssp.h" + +static int ssp_sensorhub_print_data(const char *func_name, + const char *data, int length) +{ + char buf[6]; + char *log_str; + int log_size = strlen(func_name) + 2 + sizeof(buf) * length + 1; + int i; + + log_str = kzalloc(log_size, GFP_KERNEL); + if (unlikely(!log_str)) { + sensorhub_err("allocate memory for data log err"); + return -ENOMEM; + } + + for (i = 0; i < length; i++) { + if (i == 0) { + strlcat(log_str, func_name, log_size); + strlcat(log_str, ": ", log_size); + } else { + strlcat(log_str, ", ", log_size); + } + snprintf(buf, sizeof(buf), "%d", (signed char)data[i]); + strlcat(log_str, buf, log_size); + } + + pr_info("%s", log_str); + kfree(log_str); + return log_size; +} + +static ssize_t ssp_sensorhub_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + struct ssp_sensorhub_data *hub_data + = container_of(file->private_data, + struct ssp_sensorhub_data, sensorhub_device); + unsigned char instruction; + int ret = 0; + + if (unlikely(count < 2)) { + sensorhub_err("library data length err(%d)", count); + return -EINVAL; + } + + ssp_sensorhub_print_data(__func__, buf, count); + + if (unlikely(hub_data->ssp_data->bSspShutdown)) { + sensorhub_err("stop sending library data(shutdown)"); + return -EBUSY; + } + + if (buf[0] == MSG2SSP_INST_LIBRARY_REMOVE) + instruction = REMOVE_LIBRARY; + else if (buf[0] == MSG2SSP_INST_LIBRARY_ADD) + instruction = ADD_LIBRARY; +/* else if (buf[0] == MSG2SSP_INST_LIB_NOTI) { + if (buf[2] == MSG2SSP_AP_STATUS_WAKEUP) { + ret = ssp_send_cmd(hub_data->ssp_data, MSG2SSP_AP_STATUS_WAKEUP); + enable_debug_timer(hub_data->ssp_data); + if (ret != SUCCESS) + pr_err("[SSP] : %s MSG2SSP_AP_STATUS_WAKEUP failed(%d)\n", + __func__, ret); + } else if (buf[2] == MSG2SSP_AP_STATUS_SLEEP) { + disable_debug_timer(hub_data->ssp_data); + ret = ssp_send_cmd(hub_data->ssp_data, MSG2SSP_AP_STATUS_SLEEP); + if (ret != SUCCESS) + pr_err("[SSP] : %s MSG2SSP_AP_STATUS_SLEEP failed(%d)\n", + __func__, ret); + } else if (buf[2] == MSG2SSP_AP_STATUS_POW_CONNECTED) { + ret = ssp_send_cmd(hub_data->ssp_data, MSG2SSP_AP_STATUS_POW_CONNECTED); + if (ret != SUCCESS) + pr_err("[SSP] : %s MSG2SSP_AP_STATUS_POW_CONNECTED failed(%d)\n", + __func__, ret); + } else if (buf[2] == MSG2SSP_AP_STATUS_POW_DISCONNECTED) { + ret = ssp_send_cmd(hub_data->ssp_data, MSG2SSP_AP_STATUS_POW_DISCONNECTED); + if (ret != SUCCESS) + pr_err("[SSP] : %s MSG2SSP_AP_STATUS_POW_DISCONNECTED failed(%d)\n", + __func__, ret); + } else if (buf[2] == MSG2SSP_AP_STATUS_CALL_IDLE) { + ret = ssp_send_cmd(hub_data->ssp_data, MSG2SSP_AP_STATUS_CALL_IDLE); + if (ret != SUCCESS) + pr_err("[SSP] : %s MSG2SSP_AP_STATUS_CALL_IDLE failed(%d)\n", + __func__, ret); + } else if (buf[2] == MSG2SSP_AP_STATUS_CALL_ACTIVE) { + ret = ssp_send_cmd(hub_data->ssp_data, MSG2SSP_AP_STATUS_CALL_ACTIVE); + if (ret != SUCCESS) + pr_err("[SSP] : %s MSG2SSP_AP_STATUS_CALL_ACTIVE failed(%d)\n", + __func__, ret); + } else + pr_err("[SSP] : %s wrong MSG2SSP_INST_LIB_NOTI(%d)\n", + __func__, buf[0]); + return count; + } */else + instruction = buf[0]; + + ret = send_instruction(hub_data->ssp_data, instruction, + (unsigned char)buf[1], (unsigned char *)(buf+2), count-2); + if (unlikely(ret <= 0)) { + sensorhub_err("send library data err(%d)", ret); + /* i2c transfer fail */ + if (ret == ERROR) + return -EIO; + /* i2c transfer done but no ack from MCU */ + else if (ret == FAIL) + return -EAGAIN; + } + + return count; +} + +static ssize_t ssp_sensorhub_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct ssp_sensorhub_data *hub_data + = container_of(file->private_data, + struct ssp_sensorhub_data, sensorhub_device); + int retries = MAX_DATA_COPY_TRY; + int ret = 0; + + if (unlikely(list_empty(&hub_data->events_head.list))) { + sensorhub_info("no library data"); + return 0; + } + + while (retries--) { + ret = copy_to_user(buf, + hub_data->first_event->library_data, + hub_data->first_event->library_length); + if (likely(!ret)) + break; + } + if (unlikely(ret)) { + sensorhub_err("read library data err(%d)", ret); + return -ret; + } + + ssp_sensorhub_print_data(__func__, + hub_data->first_event->library_data, + hub_data->first_event->library_length); + + complete(&hub_data->sensorhub_completion); + return hub_data->first_event->library_length; +} + +static long ssp_sensorhub_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ssp_sensorhub_data *hub_data + = container_of(file->private_data, + struct ssp_sensorhub_data, sensorhub_device); + void __user *argp = (void __user *)arg; + int retries = MAX_DATA_COPY_TRY; + int length = hub_data->large_library_length; + int ret = 0; + + switch (cmd) { + case IOCTL_READ_LARGE_CONTEXT_DATA: + if (unlikely(!hub_data->large_library_length + || !hub_data->large_library_data)) { + sensorhub_info("no large library data"); + return 0; + } + + while (retries--) { + ret = copy_to_user(argp, + hub_data->large_library_data, + hub_data->large_library_length); + if (likely(!ret)) + break; + } + if (unlikely(ret)) { + sensorhub_err("read large library data err(%d)", ret); + return -ret; + } + + ssp_sensorhub_print_data(__func__, + hub_data->large_library_data, + hub_data->large_library_length); + + kfree(hub_data->large_library_data); + hub_data->large_library_length = 0; + break; + + default: + sensorhub_err("ioctl cmd err(%d)", cmd); + return -EINVAL; + } + + return length; +} + +static struct file_operations ssp_sensorhub_fops = { + .owner = THIS_MODULE, + .open = nonseekable_open, + .write = ssp_sensorhub_write, + .read = ssp_sensorhub_read, + .unlocked_ioctl = ssp_sensorhub_ioctl, +}; + +void ssp_sensorhub_report_notice(struct ssp_data *ssp_data, char notice) +{ + struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; + + input_report_rel(hub_data->sensorhub_input_dev, NOTICE, notice); + input_sync(hub_data->sensorhub_input_dev); + + if (notice == MSG2SSP_AP_STATUS_WAKEUP) + sensorhub_info("wake up"); + else if (notice == MSG2SSP_AP_STATUS_SLEEP) + sensorhub_info("sleep"); + else if (notice == MSG2SSP_AP_STATUS_RESET) + sensorhub_info("reset"); + else + sensorhub_err("invalid notice(0x%x)", notice); +} + +static void ssp_sensorhub_report_length( + struct ssp_sensorhub_data *hub_data, int length) +{ + input_report_rel(hub_data->sensorhub_input_dev, DATA, length); + input_sync(hub_data->sensorhub_input_dev); + wake_lock_timeout(&hub_data->sensorhub_wake_lock, WAKE_LOCK_TIMEOUT); +} + +static void ssp_sensorhub_report_large_length( + struct ssp_sensorhub_data *hub_data, int length) +{ + input_report_rel(hub_data->sensorhub_input_dev, LARGE_DATA, length); + input_sync(hub_data->sensorhub_input_dev); + wake_lock_timeout(&hub_data->sensorhub_wake_lock, WAKE_LOCK_TIMEOUT); +} + +static int ssp_sensorhub_list(struct ssp_sensorhub_data *hub_data, + char *dataframe, int start, int end) +{ + struct list_head *list; + int length = end - start; + int events = 0; + + if (unlikely(length <= 0)) { + sensorhub_err("library length err(%d)", length); + return -EINVAL; + } + + ssp_sensorhub_print_data(__func__, dataframe+start, length); + + /* how many events in the list? */ + list_for_each(list, &hub_data->events_head.list) + events++; + + /* overwrite new event if list is full */ + if (unlikely(events >= LIST_SIZE)) { + sensorhub_info("list is full... overwrite new event"); + spin_lock_bh(&hub_data->sensorhub_lock); + list_del(&hub_data->first_event->list); + hub_data->first_event + = list_first_entry(&hub_data->events_head.list, + struct sensorhub_event, list); + spin_unlock_bh(&hub_data->sensorhub_lock); + } + + /* allocate memory for new event */ + kfree(hub_data->events[hub_data->event_number].library_data); + hub_data->events[hub_data->event_number].library_data + = kzalloc(length * sizeof(char), GFP_KERNEL); + if (unlikely(!hub_data->events[hub_data->event_number].library_data)) { + sensorhub_err("allocate memory for library err"); + return -ENOMEM; + } + + /* copy new event into memory */ + memcpy(hub_data->events[hub_data->event_number].library_data, + dataframe+start, length); + hub_data->events[hub_data->event_number].library_length = length; + + /* add new event into the end of list */ + spin_lock_bh(&hub_data->sensorhub_lock); + list_add_tail(&hub_data->events[hub_data->event_number].list, + &hub_data->events_head.list); + spin_unlock_bh(&hub_data->sensorhub_lock); + + /* not to overflow max list capacity */ + if (hub_data->event_number++ >= LIST_SIZE - 1) + hub_data->event_number = 0; + + return events + (events >= LIST_SIZE ? 0 : 1); +} + +static int ssp_sensorhub_thread(void *arg) +{ + struct ssp_sensorhub_data *hub_data = (struct ssp_sensorhub_data *)arg; + int ret = 0; + + while (likely(!kthread_should_stop())) { + /* run thread if list is not empty */ + wait_event_interruptible(hub_data->sensorhub_wq, + kthread_should_stop() || + !list_empty(&hub_data->events_head.list)); + + /* exit thread if kthread should stop */ + if (unlikely(kthread_should_stop())) { + sensorhub_info("kthread_stop()"); + break; + } + + /* get ready new event if the previous transfer has succeeded */ + if (likely(!hub_data->transferring)) { + spin_lock_bh(&hub_data->sensorhub_lock); + /* first in first out */ + hub_data->first_event + = list_first_entry(&hub_data->events_head.list, + struct sensorhub_event, list); + hub_data->transferring = true; + spin_unlock_bh(&hub_data->sensorhub_lock); + } + + /* report sensorhub event length to user */ + ssp_sensorhub_report_length(hub_data, + hub_data->first_event->library_length); + + /* wait until transfer finished */ + ret = wait_for_completion_timeout( + &hub_data->sensorhub_completion, COMPLETION_TIMEOUT); + if (likely(ret > 0)) + hub_data->transferring = false; + else if (unlikely(ret == 0)) + sensorhub_err("wait timed out"); + else + sensorhub_err("wait for completion err(%d)", ret); + + /* remove first event in the list if transfer succeeded */ + if (likely(!hub_data->transferring)) { + struct list_head *list; + int events = 0; + + /* remove first event from the list */ + spin_lock_bh(&hub_data->sensorhub_lock); + list_del(&hub_data->first_event->list); + spin_unlock_bh(&hub_data->sensorhub_lock); + + /* how many events remain in the list after removing? */ + list_for_each(list, &hub_data->events_head.list) + events++; + if (unlikely(events)) + sensorhub_info("%d events remain", events); + } + } + + return 0; +} + +int ssp_sensorhub_handle_data(struct ssp_data *ssp_data, char *dataframe, + int start, int end) +{ + struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; + + /* add new sensorhub event into list */ + int ret = ssp_sensorhub_list(hub_data, dataframe, start, end); + wake_up(&hub_data->sensorhub_wq); + + return ret; +} + +static int ssp_sensorhub_receive_large_data(struct ssp_sensorhub_data *hub_data, + unsigned char sub_cmd) +{ + char send_data[2] = { 0, }; + char receive_data[5] = { 0, }; + char *msg_data; /* Nth msg data */ + static int pos; /* large_library_data current position */ + int total_length = 0; /* total length */ + int msg_length = 0; /* Nth msg length */ + int total_msg_number; /* total msg number */ + int msg_number; /* current msg number */ + int ret = 0; + + send_data[0] = MSG2SSP_STT; + send_data[1] = sub_cmd; + sensorhub_info("sub_cmd = 0x%x", sub_cmd); + + /* receive_data[0-1] : total length + * receive_data[2] >> 4 : total msg number + * receive_data[2] & 0x0F : current msg number */ + ret = ssp_read_data(hub_data->ssp_data, send_data, 2, + receive_data, 5, 3); + if (unlikely(ret < 0)) { + sensorhub_err("MSG2SSP_STT spi err(%d)", ret); + return ret; + } + + /* get total length */ + total_length = ((unsigned int)receive_data[0] << 8) + + (unsigned int)receive_data[1]; + sensorhub_info("total length = %d", total_length); + + total_msg_number = (int)(receive_data[2] >> 4); + msg_number = (int)(receive_data[2] & 0x0F); + + /* if this is the first msg */ + if (msg_number <= 1) { + /* empty previous large_library_data */ + if (hub_data->large_library_length != 0) + kfree(hub_data->large_library_data); + + /* allocate new memory for large_library_data */ + hub_data->large_library_data + = kzalloc((total_length * sizeof(char)), GFP_KERNEL); + if (unlikely(!hub_data->large_library_data)) { + sensorhub_err("allocate memory for large library err"); + return -ENOMEM; + } + hub_data->large_library_length = total_length; + } + + /* get the Nth msg length */ + msg_length = ((unsigned int)receive_data[3] << 8) + + (unsigned int)receive_data[4]; + sensorhub_info("%dth msg length = %d", msg_number, msg_length); + + /* receive the Nth msg data */ + send_data[0] = MSG2SSP_SRM; + msg_data = kzalloc((msg_length * sizeof(char)), GFP_KERNEL); + if (unlikely(!msg_data)) { + sensorhub_err("allocate memory for msg data err"); + return -ENOMEM; + } + + ret = ssp_read_data(hub_data->ssp_data, send_data, 1, + msg_data, msg_length, 0); + if (unlikely(ret < 0)) { + sensorhub_err("receive %dth msg err(%d)", msg_number, ret); + kfree(msg_data); + return ret; + } + + /* copy the Nth msg data into large_library_data */ + memcpy(&hub_data->large_library_data[pos], + &msg_data[0], msg_length * sizeof(char)); + kfree(msg_data); + pos += msg_length; + + if (msg_number < total_msg_number) { + /* still receiving msg data */ + sensorhub_info("current msg length = %d(%d/%d)", + msg_length, msg_number, total_msg_number); + } else { + /* finish receiving msg data */ + sensorhub_info("total msg length = %d(%d/%d)", + pos, msg_number, total_msg_number); + pos = 0; + } + + return msg_number; +} + +int ssp_sensorhub_handle_large_data(struct ssp_data *ssp_data, + unsigned char sub_cmd) +{ + struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; + static bool err; + static int current_msg_number = 1; + int total_msg_number = (int)(sub_cmd >> 4); + int msg_number = (int)(sub_cmd & 0x0F); + int ret; + + /* skip the rest transfer if error occurs */ + if (unlikely(err)) { + if (msg_number <= 1) { + current_msg_number = 1; + err = false; + } else { + return -EIO; + } + } + + /* next msg is the right one? */ + if (current_msg_number++ != msg_number) { + sensorhub_err("next msg should be %dth but %dth", + current_msg_number - 1, msg_number); + sensorhub_err("skip the rest %d msg transfer", + total_msg_number - msg_number); + err = true; + return -EINVAL; + } + + /* receive large library data */ + ret = ssp_sensorhub_receive_large_data(hub_data, sub_cmd); + if (unlikely(ret < 0)) { + sensorhub_err("receive large msg err(%d/%d)(%d)", + msg_number, total_msg_number, ret); + sensorhub_err("skip the rest %d msg transfer", + total_msg_number - msg_number); + err = true; + return ret; + } + + /* finally ready to go to user */ + if (msg_number >= total_msg_number) { + ssp_sensorhub_report_large_length(hub_data, + hub_data->large_library_length); + current_msg_number = 1; + } + + return ret; +} + +int ssp_sensorhub_initialize(struct ssp_data *ssp_data) +{ + struct ssp_sensorhub_data *hub_data; + int ret; + + /* allocate memory for sensorhub data */ + hub_data = kzalloc(sizeof(*hub_data), GFP_KERNEL); + if (!hub_data) { + sensorhub_err("allocate memory for sensorhub data err"); + ret = -ENOMEM; + goto exit; + } + hub_data->ssp_data = ssp_data; + ssp_data->hub_data = hub_data; + + /* init wakelock, list, waitqueue, completion and spinlock */ + wake_lock_init(&hub_data->sensorhub_wake_lock, WAKE_LOCK_SUSPEND, + "ssp_sensorhub_wake_lock"); + INIT_LIST_HEAD(&hub_data->events_head.list); + init_waitqueue_head(&hub_data->sensorhub_wq); + init_completion(&hub_data->sensorhub_completion); + spin_lock_init(&hub_data->sensorhub_lock); + + /* allocate sensorhub input device */ + hub_data->sensorhub_input_dev = input_allocate_device(); + if (!hub_data->sensorhub_input_dev) { + sensorhub_err("allocate sensorhub input device err"); + ret = -ENOMEM; + goto err_input_allocate_device_sensorhub; + } + + /* set sensorhub input device */ + input_set_drvdata(hub_data->sensorhub_input_dev, hub_data); + hub_data->sensorhub_input_dev->name = "ssp_context"; + input_set_capability(hub_data->sensorhub_input_dev, EV_REL, DATA); + input_set_capability(hub_data->sensorhub_input_dev, EV_REL, LARGE_DATA); + input_set_capability(hub_data->sensorhub_input_dev, EV_REL, NOTICE); + + /* register sensorhub input device */ + ret = input_register_device(hub_data->sensorhub_input_dev); + if (ret < 0) { + sensorhub_err("register sensorhub input device err(%d)", ret); + input_free_device(hub_data->sensorhub_input_dev); + goto err_input_register_device_sensorhub; + } + + /* register sensorhub misc device */ + hub_data->sensorhub_device.minor = MISC_DYNAMIC_MINOR; + hub_data->sensorhub_device.name = "ssp_sensorhub"; + hub_data->sensorhub_device.fops = &ssp_sensorhub_fops; + + ret = misc_register(&hub_data->sensorhub_device); + if (ret < 0) { + sensorhub_err("register sensorhub misc device err(%d)", ret); + goto err_misc_register; + } + + /* create and run sensorhub thread */ + hub_data->sensorhub_task = kthread_run(ssp_sensorhub_thread, + (void *)hub_data, "ssp_sensorhub_thread"); + if (IS_ERR(hub_data->sensorhub_task)) { + ret = PTR_ERR(hub_data->sensorhub_task); + goto err_kthread_create; + } + + return 0; + +err_kthread_create: + misc_deregister(&hub_data->sensorhub_device); +err_misc_register: + input_unregister_device(hub_data->sensorhub_input_dev); +err_input_register_device_sensorhub: +err_input_allocate_device_sensorhub: + complete_all(&hub_data->sensorhub_completion); + wake_lock_destroy(&hub_data->sensorhub_wake_lock); + kfree(hub_data); +exit: + return ret; +} + +void ssp_sensorhub_remove(struct ssp_data *ssp_data) +{ + struct ssp_sensorhub_data *hub_data = ssp_data->hub_data; + + ssp_sensorhub_fops.write = NULL; + ssp_sensorhub_fops.read = NULL; + ssp_sensorhub_fops.unlocked_ioctl = NULL; + + kthread_stop(hub_data->sensorhub_task); + misc_deregister(&hub_data->sensorhub_device); + input_unregister_device(hub_data->sensorhub_input_dev); + complete_all(&hub_data->sensorhub_completion); + wake_lock_destroy(&hub_data->sensorhub_wake_lock); + kfree(hub_data); +} + +MODULE_DESCRIPTION("Seamless Sensor Platform(SSP) sensorhub driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/stm/ssp_sensorhub.h b/drivers/sensorhub/stm/ssp_sensorhub.h new file mode 100755 index 00000000000..d1c31bf85f7 --- /dev/null +++ b/drivers/sensorhub/stm/ssp_sensorhub.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __SSP_SENSORHUB__ +#define __SSP_SENSORHUB__ + +#include +#include +#include +#include +#include "ssp.h" + +#define LIST_SIZE 5 +#define MAX_DATA_COPY_TRY 2 +#define WAKE_LOCK_TIMEOUT (3*HZ) +#define COMPLETION_TIMEOUT (2*HZ) +#define DATA REL_RX +#define LARGE_DATA REL_RY +#define NOTICE REL_RZ + +#define SENSORHUB_IOCTL_MAGIC 'S' +#define IOCTL_READ_LARGE_CONTEXT_DATA _IOR(SENSORHUB_IOCTL_MAGIC, 3, char *) + +#define sensorhub_info(str, args...) pr_info("%s: " str, __func__, ##args) +#define sensorhub_debug(str, args...) pr_debug("%s: " str, __func__, ##args) +#define sensorhub_err(str, args...) pr_err("%s: " str, __func__, ##args) + + +struct sensorhub_event { + char *library_data; + int library_length; + struct list_head list; +}; + +struct ssp_sensorhub_data { + struct ssp_data *ssp_data; + struct input_dev *sensorhub_input_dev; + struct miscdevice sensorhub_device; + struct wake_lock sensorhub_wake_lock; + struct completion sensorhub_completion; + struct task_struct *sensorhub_task; + struct sensorhub_event events_head; + struct sensorhub_event events[LIST_SIZE]; + struct sensorhub_event *first_event; + bool transferring; + char *large_library_data; + int large_library_length; + int event_number; + wait_queue_head_t sensorhub_wq; + spinlock_t sensorhub_lock; +}; + +void ssp_sensorhub_report_notice(struct ssp_data *ssp_data, char notice); +int ssp_sensorhub_handle_data(struct ssp_data *ssp_data, char *dataframe, + int start, int end); +int ssp_sensorhub_handle_large_data(struct ssp_data *ssp_data, u8 sub_cmd); +int ssp_sensorhub_initialize(struct ssp_data *ssp_data); +void ssp_sensorhub_remove(struct ssp_data *ssp_data); + +#endif diff --git a/drivers/sensorhub/stm/ssp_spi.c b/drivers/sensorhub/stm/ssp_spi.c new file mode 100755 index 00000000000..469a95bfa73 --- /dev/null +++ b/drivers/sensorhub/stm/ssp_spi.c @@ -0,0 +1,255 @@ +/* + * driver for Android SensorHub SPI + * + * Copyright (c) 2013, Samsung Electronics. All rights reserved + * + * 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 the GNU General Public License + * for more details. + */ + +#include +#include +#include +#include + +#if defined(DEBUG_SSP_SPI) +#define ssp_log(fmt, arg...) \ + do { \ + printk(KERN_ERR "[%s:%d] " fmt , \ + __func__, __LINE__, ##arg); \ + } \ + while (0) +#else +#define ssp_log(fmt, arg...) +#endif + + +/* If AP can't change the endian to BIG */ +/* for s5c73m ISP, this option must is required.*/ +/* This option depends on SPI_DMA_MODE */ +/* in camera driver file*/ +/*#define CHANGE_ENDIAN */ + + +int ssp_spi_write_sync(struct spi_device *spi, const u8 *addr, const int len) +{ + int ret; +#if defined(CHANGE_ENDIAN) + u8 buf[8] = {0}; +#endif + + struct spi_message msg; + + struct spi_transfer xfer = { + .len = len, +#if !defined(CHANGE_ENDIAN) + .tx_buf = addr, + /*QCTK ALRAN QUP_CONFIG 0-4 bits BIG ENDIAN*/ + .bits_per_word = 8, +#else + .tx_buf = buf, +#endif + }; + +#if defined(CHANGE_ENDIAN) + buf[0] = addr[3]; + buf[1] = addr[2]; + buf[2] = addr[1]; + buf[3] = addr[0]; + buf[4] = addr[7]; + buf[5] = addr[6]; + buf[6] = addr[5]; + buf[7] = addr[4]; +#endif + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + ret = spi_sync(spi, &msg); + + if (ret < 0) + ssp_log("error %d\n", ret); + + return ret; +} + + +int ssp_spi_read_sync(struct spi_device *spi, u8 *in_buf, size_t len) +{ + int ret; + u8 read_out_buf[2]; + + struct spi_message msg; + struct spi_transfer xfer = { + .tx_buf = read_out_buf, + .rx_buf = in_buf, + .len = len, + .cs_change = 0, + }; + + spi_message_init(&msg); + + spi_message_add_tail(&xfer, &msg); + + ret = spi_sync(spi, &msg); + + if (ret < 0) + ssp_log("%s - error %d\n", + __func__, ret); + + return ret; +} + + +int ssp_spi_sync(struct spi_device *spi, u8 *out_buf, + size_t out_len, u8 *in_buf) +{ + int ret; + + struct spi_message msg; + struct spi_transfer xfer = { + .tx_buf = out_buf, + .rx_buf = in_buf, + .len = out_len, + .cs_change = 0, + }; + + spi_message_init(&msg); + + spi_message_add_tail(&xfer, &msg); + + ret = spi_sync(spi, &msg); + ssp_log("%s - received %d\n", __func__, xfer.len); + + if (ret < 0) + ssp_log("%s - error %d\n", + __func__, ret); + + return ret; +} + +unsigned int g_flag_spirecv; +void ssp_spi_async_complete(void *context) +{ + g_flag_spirecv = 1; +} + +int ssp_spi_async(struct spi_device *spi, u8 *out_buf, + size_t out_len, u8 *in_buf) +{ + int ret; + + struct spi_message msg; + struct spi_transfer xfer = { + .tx_buf = out_buf, + .rx_buf = in_buf, + .len = out_len, + .cs_change = 0, + }; + + + spi_message_init(&msg); + + spi_message_add_tail(&xfer, &msg); + msg.complete = ssp_spi_async_complete; + + ret = spi_async(spi, &msg); + + if (ret < 0) + ssp_log("%s - error %d\n", + __func__, ret); + + return ret; +} + + + + +int ssp_spi_read(struct spi_device *spi, u8 *buf, size_t len, const int rxSize) +{ + int k; + int ret = 0; + u8 temp_buf[4] = {0}; + u32 count = len/rxSize; + u32 extra = len%rxSize; + + for (k = 0; k < count; k++) { + ret = ssp_spi_read_sync(spi, &buf[rxSize*k], rxSize); + if (ret < 0) { + ssp_log("%s - error %d\n", + __func__, ret); + return -EINVAL; + } + } + + if (extra != 0) { + ret = ssp_spi_read_sync(spi, &buf[rxSize*k], extra); + if (ret < 0) { + ssp_log("%s - error %d\n", + __func__, ret); + return -EINVAL; + } + } + + for (k = 0; k < len-3; k += 4) { + memcpy(temp_buf, (char *)&buf[k], sizeof(temp_buf)); + buf[k] = temp_buf[3]; + buf[k+1] = temp_buf[2]; + buf[k+2] = temp_buf[1]; + buf[k+3] = temp_buf[0]; + } + + return 0; +} + +int ssp_spi_write(struct spi_device *spi, const u8 *addr, + const int len, const int txSize) +{ + int i, j = 0; + int ret = 0; + u8 paddingData[8]; + u32 count = len/txSize; + u32 extra = len%txSize; + ssp_log("Entered\n"); + ssp_log("count = %d extra = %d\n", count, extra); + + memset(paddingData, 0, sizeof(paddingData)); + + for (i = 0 ; i < count ; i++) { + ret = ssp_spi_write_sync(spi, &addr[j], txSize); + j += txSize; + if (ret < 0) { + ssp_log("failed to write ssp_spi_write_sync\n"); + goto exit_err; + } + ssp_log("Delay!!!\n"); + msleep(50); + } + + if (extra) { + ret = ssp_spi_write_sync(spi, &addr[j], extra); + if (ret < 0) { + ssp_log("failed to write ssp_spi_write_sync\n"); + goto exit_err; + } + } + + for (i = 0; i < 4; i++) { + memset(paddingData, 0, sizeof(paddingData)); + ret = ssp_spi_write_sync(spi, paddingData, 8); + if (ret < 0) { + ssp_log("failed to write ssp_spi_write_sync\n"); + goto exit_err; + } + } + ssp_log("Finish!!\n"); +exit_err: + return ret; +} + diff --git a/drivers/sensorhub/stm/ssp_sysfs.c b/drivers/sensorhub/stm/ssp_sysfs.c new file mode 100755 index 00000000000..273d4c95d11 --- /dev/null +++ b/drivers/sensorhub/stm/ssp_sysfs.c @@ -0,0 +1,600 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* SSP data delay function */ +/*************************************************************************/ + +unsigned int get_msdelay(int64_t dDelayRate) +{ + if (dDelayRate <= SENSOR_NS_DELAY_FASTEST) + return SENSOR_MS_DELAY_FASTEST; + else if (dDelayRate <= SENSOR_NS_DELAY_GAME) + return SENSOR_MS_DELAY_GAME; + else if (dDelayRate <= SENSOR_NS_DELAY_UI) + return SENSOR_MS_DELAY_UI; + else + return SENSOR_MS_DELAY_NORMAL; +} + +unsigned int get_delay_cmd(u8 uDelayRate) +{ + if (uDelayRate <= SENSOR_MS_DELAY_FASTEST) + return SENSOR_CMD_DELAY_FASTEST; + else if (uDelayRate <= SENSOR_MS_DELAY_GAME) + return SENSOR_CMD_DELAY_GAME; + else if (uDelayRate <= SENSOR_MS_DELAY_UI) + return SENSOR_CMD_DELAY_UI; + else + return SENSOR_CMD_DELAY_NORMAL; +} + +static void change_sensor_delay(struct ssp_data *data, + int iSensorType, int64_t dNewDelay) +{ + u8 uBuf[2]; + unsigned int uNewEnable = 0; + int64_t dTempDelay = data->adDelayBuf[iSensorType]; + + if (!(atomic_read(&data->aSensorEnable) & (1 << iSensorType))) { + data->aiCheckStatus[iSensorType] = NO_SENSOR_STATE; + return; + } + + data->adDelayBuf[iSensorType] = dNewDelay; + + switch (data->aiCheckStatus[iSensorType]) { + case ADD_SENSOR_STATE: + ssp_dbg("[SSP]: %s - add %u, New = %lldns\n", + __func__, 1 << iSensorType, dNewDelay); + + uBuf[1] = (u8)get_msdelay(dNewDelay); + uBuf[0] = (u8)get_delay_cmd(uBuf[1]); + + if (send_instruction(data, ADD_SENSOR, iSensorType, uBuf, 2) + != SUCCESS) { + uNewEnable = + (unsigned int)atomic_read(&data->aSensorEnable) + & (~(unsigned int)(1 << iSensorType)); + atomic_set(&data->aSensorEnable, uNewEnable); + + data->aiCheckStatus[iSensorType] = NO_SENSOR_STATE; + data->uMissSensorCnt++; + break; + } + + data->aiCheckStatus[iSensorType] = RUNNING_SENSOR_STATE; + + if (iSensorType == PROXIMITY_SENSOR) { + proximity_open_lcd_ldi(data); + proximity_open_calibration(data); + + input_report_abs(data->prox_input_dev, ABS_DISTANCE, 1); + input_sync(data->prox_input_dev); + } + break; + case RUNNING_SENSOR_STATE: + if (get_msdelay(dTempDelay) + == get_msdelay(data->adDelayBuf[iSensorType])) + break; + + ssp_dbg("[SSP]: %s - Change %u, New = %lldns\n", + __func__, 1 << iSensorType, dNewDelay); + + uBuf[1] = (u8)get_msdelay(dNewDelay); + uBuf[0] = (u8)get_delay_cmd(uBuf[1]); + send_instruction(data, CHANGE_DELAY, iSensorType, uBuf, 2); + + break; + default: + data->aiCheckStatus[iSensorType] = ADD_SENSOR_STATE; + } +} + +/*************************************************************************/ +/* SSP data enable function */ +/*************************************************************************/ + +static int ssp_remove_sensor(struct ssp_data *data, + unsigned int uChangedSensor, unsigned int uNewEnable) +{ + u8 uBuf[2]; + int iRet = 0; + int64_t dSensorDelay = data->adDelayBuf[uChangedSensor]; + + ssp_dbg("[SSP]: %s - remove sensor = %d, current state = %d\n", + __func__, (1 << uChangedSensor), uNewEnable); + + data->adDelayBuf[uChangedSensor] = DEFUALT_POLLING_DELAY; + + if (data->aiCheckStatus[uChangedSensor] == INITIALIZATION_STATE) { + data->aiCheckStatus[uChangedSensor] = NO_SENSOR_STATE; + if (uChangedSensor == ACCELEROMETER_SENSOR) + accel_open_calibration(data); + else if (uChangedSensor == GYROSCOPE_SENSOR) + gyro_open_calibration(data); + else if (uChangedSensor == PRESSURE_SENSOR) + pressure_open_calibration(data); + else if (uChangedSensor == PROXIMITY_SENSOR) { + proximity_open_lcd_ldi(data); + proximity_open_calibration(data); + } else if (uChangedSensor == GEOMAGNETIC_SENSOR) { + iRet = mag_open_hwoffset(data); + if (iRet < 0) + pr_err("[SSP]: %s - mag_open_hw_offset" + " failed, %d\n", __func__, iRet); + + iRet = set_hw_offset(data); + if (iRet < 0) { + pr_err("[SSP]: %s - set_hw_offset failed\n", + __func__); + } + } + return 0; + } else if (uChangedSensor == ORIENTATION_SENSOR) { + if (!(atomic_read(&data->aSensorEnable) + & (1 << ACCELEROMETER_SENSOR))) { + uChangedSensor = ACCELEROMETER_SENSOR; + } else { + change_sensor_delay(data, ACCELEROMETER_SENSOR, + data->adDelayBuf[ACCELEROMETER_SENSOR]); + return 0; + } + } else if (uChangedSensor == ACCELEROMETER_SENSOR) { + if (atomic_read(&data->aSensorEnable) + & (1 << ORIENTATION_SENSOR)) { + change_sensor_delay(data, ORIENTATION_SENSOR, + data->adDelayBuf[ORIENTATION_SENSOR]); + return 0; + } + } else if (uChangedSensor == GEOMAGNETIC_SENSOR) { + if (mag_store_hwoffset(data)) + pr_err("mag_store_hwoffset success\n"); + } + + if (atomic_read(&data->aSensorEnable) & (1 << uChangedSensor)) { + uBuf[1] = (u8)get_msdelay(dSensorDelay); + uBuf[0] = (u8)get_delay_cmd(uBuf[1]); + + send_instruction(data, REMOVE_SENSOR, uChangedSensor, uBuf, 2); + } + data->aiCheckStatus[uChangedSensor] = NO_SENSOR_STATE; + return 0; +} + +/*************************************************************************/ +/* ssp Sysfs */ +/*************************************************************************/ + +static ssize_t show_sensors_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + ssp_dbg("[SSP]: %s - cur_enable = %d\n", __func__, + atomic_read(&data->aSensorEnable)); + + return sprintf(buf, "%9u\n", atomic_read(&data->aSensorEnable)); +} + +static ssize_t set_sensors_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dTemp; + unsigned int uNewEnable = 0, uChangedSensor = 0; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dTemp) < 0) + return -EINVAL; + + uNewEnable = (unsigned int)dTemp; + ssp_dbg("[SSP]: %s - new_enable = %u, old_enable = %u\n", __func__, + uNewEnable, atomic_read(&data->aSensorEnable)); + + if (uNewEnable == atomic_read(&data->aSensorEnable)) + return size; + + for (uChangedSensor = 0; uChangedSensor < SENSOR_MAX; uChangedSensor++) + if ((atomic_read(&data->aSensorEnable) & (1 << uChangedSensor)) + != (uNewEnable & (1 << uChangedSensor))) { + + if (!(uNewEnable & (1 << uChangedSensor))) + ssp_remove_sensor(data, uChangedSensor, + uNewEnable); + break; + } + + atomic_set(&data->aSensorEnable, uNewEnable); + + return size; +} + +static ssize_t show_acc_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[ACCELEROMETER_SENSOR]); +} + +static ssize_t set_acc_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -EINVAL; + + if ((atomic_read(&data->aSensorEnable) & (1 << ORIENTATION_SENSOR)) && + (data->adDelayBuf[ORIENTATION_SENSOR] < dNewDelay)) + data->adDelayBuf[ACCELEROMETER_SENSOR] = dNewDelay; + else + change_sensor_delay(data, ACCELEROMETER_SENSOR, dNewDelay); + + return size; +} +/* +static ssize_t show_ori_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[ORIENTATION_SENSOR]); +} + +static ssize_t set_ori_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -1; + + if (data->aiCheckStatus[ACCELEROMETER_SENSOR] == NO_SENSOR_STATE) { + data->aiCheckStatus[ACCELEROMETER_SENSOR] = ADD_SENSOR_STATE; + change_sensor_delay(data, ORIENTATION_SENSOR, dNewDelay); + } else if (data->aiCheckStatus[ACCELEROMETER_SENSOR] == + RUNNING_SENSOR_STATE) { + if (dNewDelay < data->adDelayBuf[ACCELEROMETER_SENSOR]) + change_sensor_delay(data, + ORIENTATION_SENSOR, dNewDelay); + else + data->adDelayBuf[ORIENTATION_SENSOR] = dNewDelay; + } + return size; +} +*/ +static ssize_t show_gyro_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[GYROSCOPE_SENSOR]); +} + +static ssize_t set_gyro_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -EINVAL; + + change_sensor_delay(data, GYROSCOPE_SENSOR, dNewDelay); + return size; +} + +static ssize_t show_mag_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[GEOMAGNETIC_SENSOR]); +} + +static ssize_t set_mag_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -EINVAL; + + change_sensor_delay(data, GEOMAGNETIC_SENSOR, dNewDelay); + + return size; +} + +static ssize_t show_pressure_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[PRESSURE_SENSOR]); +} + +static ssize_t set_pressure_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -EINVAL; + + change_sensor_delay(data, PRESSURE_SENSOR, dNewDelay); + return size; +} + +static ssize_t show_gesture_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[GESTURE_SENSOR]); +} + +static ssize_t set_gesture_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -EINVAL; + + change_sensor_delay(data, GESTURE_SENSOR, dNewDelay); + + return size; +} + +static ssize_t show_light_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[LIGHT_SENSOR]); +} + +static ssize_t set_light_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -EINVAL; + + change_sensor_delay(data, LIGHT_SENSOR, dNewDelay); + return size; +} + +static ssize_t show_prox_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", data->adDelayBuf[PROXIMITY_SENSOR]); +} + +static ssize_t set_prox_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -EINVAL; + + change_sensor_delay(data, PROXIMITY_SENSOR, dNewDelay); + return size; +} + +static ssize_t show_temp_humi_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%lld\n", + data->adDelayBuf[TEMPERATURE_HUMIDITY_SENSOR]); +} + +static ssize_t set_temp_humi_delay(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int64_t dNewDelay; + struct ssp_data *data = dev_get_drvdata(dev); + + if (kstrtoll(buf, 10, &dNewDelay) < 0) + return -EINVAL; + + change_sensor_delay(data, TEMPERATURE_HUMIDITY_SENSOR, dNewDelay); + return size; +} + +static DEVICE_ATTR(mcu_rev, S_IRUGO, mcu_revision_show, NULL); +static DEVICE_ATTR(mcu_name, S_IRUGO, mcu_model_name_show, NULL); +static DEVICE_ATTR(mcu_update, S_IRUGO, mcu_update_kernel_bin_show, NULL); +static DEVICE_ATTR(mcu_update2, S_IRUGO, + mcu_update_kernel_crashed_bin_show, NULL); +static DEVICE_ATTR(mcu_update_ums, S_IRUGO, mcu_update_ums_bin_show, NULL); +static DEVICE_ATTR(mcu_reset, S_IRUGO, mcu_reset_show, NULL); + +static DEVICE_ATTR(mcu_test, S_IRUGO | S_IWUSR | S_IWGRP, + mcu_factorytest_show, mcu_factorytest_store); +static DEVICE_ATTR(mcu_sleep_test, S_IRUGO | S_IWUSR | S_IWGRP, + mcu_sleep_factorytest_show, mcu_sleep_factorytest_store); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, + show_sensors_enable, set_sensors_enable); + +static struct device_attribute dev_attr_accel_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_acc_delay, set_acc_delay); +static struct device_attribute dev_attr_gyro_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_gyro_delay, set_gyro_delay); +static struct device_attribute dev_attr_mag_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_mag_delay, set_mag_delay); +static struct device_attribute dev_attr_pressure_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_pressure_delay, set_pressure_delay); +static struct device_attribute dev_attr_gesture_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_gesture_delay, set_gesture_delay); +static struct device_attribute dev_attr_light_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_light_delay, set_light_delay); +static struct device_attribute dev_attr_prox_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_prox_delay, set_prox_delay); +static struct device_attribute dev_attr_temp_humi_poll_delay + = __ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, + show_temp_humi_delay, set_temp_humi_delay); + +static struct device_attribute *mcu_attrs[] = { + &dev_attr_enable, + &dev_attr_mcu_rev, + &dev_attr_mcu_name, + &dev_attr_mcu_test, + &dev_attr_mcu_reset, + &dev_attr_mcu_update, + &dev_attr_mcu_update2, + &dev_attr_mcu_update_ums, + &dev_attr_mcu_sleep_test, + NULL, +}; + +static void initialize_mcu_factorytest(struct ssp_data *data) +{ + sensors_register(data->mcu_device, data, mcu_attrs, "ssp_sensor"); +} + +static void remove_mcu_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->mcu_device, mcu_attrs); +} + +int initialize_sysfs(struct ssp_data *data) +{ + if (device_create_file(&data->acc_input_dev->dev, + &dev_attr_accel_poll_delay)) + goto err_acc_input_dev; + + if (device_create_file(&data->gyro_input_dev->dev, + &dev_attr_gyro_poll_delay)) + goto err_gyro_input_dev; + + if (device_create_file(&data->pressure_input_dev->dev, + &dev_attr_pressure_poll_delay)) + goto err_pressure_input_dev; + + if (device_create_file(&data->gesture_input_dev->dev, + &dev_attr_gesture_poll_delay)) + goto err_gesture_input_dev; + + if (device_create_file(&data->light_input_dev->dev, + &dev_attr_light_poll_delay)) + goto err_light_input_dev; + + if (device_create_file(&data->prox_input_dev->dev, + &dev_attr_prox_poll_delay)) + goto err_prox_input_dev; + + if (device_create_file(&data->temp_humi_input_dev->dev, + &dev_attr_temp_humi_poll_delay)) + goto err_temp_humi_input_dev; + + if (device_create_file(&data->mag_input_dev->dev, + &dev_attr_mag_poll_delay)) + goto err_mag_input_dev; + + initialize_accel_factorytest(data); + initialize_gyro_factorytest(data); + initialize_prox_factorytest(data); + initialize_light_factorytest(data); + initialize_pressure_factorytest(data); + initialize_magnetic_factorytest(data); + initialize_mcu_factorytest(data); +#ifdef CONFIG_SENSORS_SSP_MAX88920 + initialize_gesture_factorytest(data); +#endif +#ifdef CONFIG_SENSORS_SSP_SHTC1 + initialize_temphumidity_factorytest(data); +#endif + return SUCCESS; +err_mag_input_dev: + device_remove_file(&data->temp_humi_input_dev->dev, + &dev_attr_temp_humi_poll_delay); +err_temp_humi_input_dev: + device_remove_file(&data->prox_input_dev->dev, + &dev_attr_prox_poll_delay); +err_prox_input_dev: + device_remove_file(&data->light_input_dev->dev, + &dev_attr_light_poll_delay); +err_light_input_dev: + device_remove_file(&data->pressure_input_dev->dev, + &dev_attr_pressure_poll_delay); +err_pressure_input_dev: + device_remove_file(&data->gyro_input_dev->dev, + &dev_attr_gyro_poll_delay); +err_gesture_input_dev: + device_remove_file(&data->gesture_input_dev->dev, + &dev_attr_gesture_poll_delay); +err_gyro_input_dev: + device_remove_file(&data->acc_input_dev->dev, + &dev_attr_accel_poll_delay); +err_acc_input_dev: + return ERROR; +} + +void remove_sysfs(struct ssp_data *data) +{ + device_remove_file(&data->acc_input_dev->dev, + &dev_attr_accel_poll_delay); + device_remove_file(&data->gyro_input_dev->dev, + &dev_attr_gyro_poll_delay); + device_remove_file(&data->pressure_input_dev->dev, + &dev_attr_pressure_poll_delay); + device_remove_file(&data->gesture_input_dev->dev, + &dev_attr_gesture_poll_delay); + device_remove_file(&data->light_input_dev->dev, + &dev_attr_light_poll_delay); + device_remove_file(&data->prox_input_dev->dev, + &dev_attr_prox_poll_delay); + device_remove_file(&data->temp_humi_input_dev->dev, + &dev_attr_temp_humi_poll_delay); + device_remove_file(&data->mag_input_dev->dev, + &dev_attr_mag_poll_delay); + remove_accel_factorytest(data); + remove_gyro_factorytest(data); + remove_prox_factorytest(data); + remove_light_factorytest(data); + remove_pressure_factorytest(data); + remove_magnetic_factorytest(data); + remove_mcu_factorytest(data); +#ifdef CONFIG_SENSORS_SSP_MAX88920 + remove_gesture_factorytest(data); +#endif +#ifdef CONFIG_SENSORS_SSP_SHTC1 + remove_temphumidity_factorytest(data); +#endif + destroy_sensor_class(); +} -- cgit v1.2.3