aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/sensorhub/Kconfig126
-rw-r--r--drivers/sensorhub/Makefile18
-rwxr-xr-xdrivers/sensorhub/atmel/Kconfig144
-rwxr-xr-xdrivers/sensorhub/atmel/Makefile21
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/accel_lsm330.c (renamed from drivers/sensorhub/accel_lsm330.c)4
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/gyro_lsm330.c (renamed from drivers/sensorhub/gyro_lsm330.c)0
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/light_cm36651.c (renamed from drivers/sensorhub/light_cm36651.c)0
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/magnetic_ak8963c.c (renamed from drivers/sensorhub/magnetic_ak8963c.c)0
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/mcu_at32uc3l0128.c (renamed from drivers/sensorhub/mcu_at32uc3l0128.c)93
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/pressure_bmp182.c (renamed from drivers/sensorhub/pressure_bmp182.c)0
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/prox_cm36651.c (renamed from drivers/sensorhub/prox_cm36651.c)8
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/sensors_core.c (renamed from drivers/sensorhub/sensors_core.c)0
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/ssp.h (renamed from drivers/sensorhub/ssp.h)43
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/ssp_ak8963c.c (renamed from drivers/sensorhub/ssp_ak8963c.c)0
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/ssp_data.c (renamed from drivers/sensorhub/ssp_data.c)13
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/ssp_debug.c (renamed from drivers/sensorhub/ssp_debug.c)60
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/ssp_dev.c (renamed from drivers/sensorhub/ssp_dev.c)133
-rwxr-xr-xdrivers/sensorhub/atmel/ssp_firmware.c495
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/ssp_i2c.c (renamed from drivers/sensorhub/ssp_i2c.c)173
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/ssp_input.c (renamed from drivers/sensorhub/ssp_input.c)0
-rwxr-xr-xdrivers/sensorhub/atmel/ssp_sensorhub.c566
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/ssp_sensorhub.h (renamed from drivers/sensorhub/ssp_sensorhub.h)47
-rwxr-xr-x[-rw-r--r--]drivers/sensorhub/atmel/ssp_sysfs.c (renamed from drivers/sensorhub/ssp_sysfs.c)49
-rw-r--r--drivers/sensorhub/ssp_firmware.c305
-rw-r--r--drivers/sensorhub/ssp_sensorhub.c574
-rwxr-xr-xdrivers/sensorhub/stm/Kconfig142
-rwxr-xr-xdrivers/sensorhub/stm/Makefile23
-rwxr-xr-xdrivers/sensorhub/stm/factory/accel_mpu6500.c311
-rwxr-xr-xdrivers/sensorhub/stm/factory/gesture_max88920.c147
-rwxr-xr-xdrivers/sensorhub/stm/factory/gyro_mpu6500.c674
-rwxr-xr-xdrivers/sensorhub/stm/factory/light_cm3320.c77
-rwxr-xr-xdrivers/sensorhub/stm/factory/magnetic_yas532.c456
-rwxr-xr-xdrivers/sensorhub/stm/factory/mcu_atuc128l5har.c282
-rwxr-xr-xdrivers/sensorhub/stm/factory/mcu_stm32f401.c282
-rwxr-xr-xdrivers/sensorhub/stm/factory/pressure_bmp182.c197
-rwxr-xr-xdrivers/sensorhub/stm/factory/prox_max88920.c457
-rwxr-xr-xdrivers/sensorhub/stm/factory/temphumidity_shtc1.c291
-rwxr-xr-xdrivers/sensorhub/stm/sensors_core.c173
-rwxr-xr-xdrivers/sensorhub/stm/ssp.h547
-rwxr-xr-xdrivers/sensorhub/stm/ssp_comm.c898
-rwxr-xr-xdrivers/sensorhub/stm/ssp_data.c317
-rwxr-xr-xdrivers/sensorhub/stm/ssp_debug.c226
-rwxr-xr-xdrivers/sensorhub/stm/ssp_dev.c566
-rwxr-xr-xdrivers/sensorhub/stm/ssp_firmware.c709
-rwxr-xr-xdrivers/sensorhub/stm/ssp_input.c601
-rwxr-xr-xdrivers/sensorhub/stm/ssp_sensorhub.c622
-rwxr-xr-xdrivers/sensorhub/stm/ssp_sensorhub.h72
-rwxr-xr-xdrivers/sensorhub/stm/ssp_spi.c255
-rwxr-xr-xdrivers/sensorhub/stm/ssp_sysfs.c600
49 files changed, 10525 insertions, 1272 deletions
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/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/accel_lsm330.c b/drivers/sensorhub/atmel/accel_lsm330.c
index 1f236636e0a..53aef948fab 100644..100755
--- a/drivers/sensorhub/accel_lsm330.c
+++ b/drivers/sensorhub/atmel/accel_lsm330.c
@@ -179,7 +179,7 @@ static ssize_t accel_calibration_show(struct device *dev,
iRet = accel_open_calibration(data);
if (iRet < 0)
- pr_err("[SSP]: %s - calibration open failed\n", __func__);
+ 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);
@@ -196,7 +196,7 @@ static ssize_t accel_calibration_store(struct device *dev,
int64_t dEnable;
struct ssp_data *data = dev_get_drvdata(dev);
- iRet = strict_strtoll(buf, 10, &dEnable);
+ iRet = kstrtoll(buf, 10, &dEnable);
if (iRet < 0)
return iRet;
diff --git a/drivers/sensorhub/gyro_lsm330.c b/drivers/sensorhub/atmel/gyro_lsm330.c
index 0a3a473f107..0a3a473f107 100644..100755
--- a/drivers/sensorhub/gyro_lsm330.c
+++ b/drivers/sensorhub/atmel/gyro_lsm330.c
diff --git a/drivers/sensorhub/light_cm36651.c b/drivers/sensorhub/atmel/light_cm36651.c
index 68081e44deb..68081e44deb 100644..100755
--- a/drivers/sensorhub/light_cm36651.c
+++ b/drivers/sensorhub/atmel/light_cm36651.c
diff --git a/drivers/sensorhub/magnetic_ak8963c.c b/drivers/sensorhub/atmel/magnetic_ak8963c.c
index ccd1723bdae..ccd1723bdae 100644..100755
--- a/drivers/sensorhub/magnetic_ak8963c.c
+++ b/drivers/sensorhub/atmel/magnetic_ak8963c.c
diff --git a/drivers/sensorhub/mcu_at32uc3l0128.c b/drivers/sensorhub/atmel/mcu_at32uc3l0128.c
index 0f63a8dd70d..9c2fa7d29d8 100644..100755
--- a/drivers/sensorhub/mcu_at32uc3l0128.c
+++ b/drivers/sensorhub/atmel/mcu_at32uc3l0128.c
@@ -18,14 +18,14 @@
/* factory Sysfs */
/*************************************************************************/
-#define MODEL_NAME "AT32UC3L0128"
+#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(),
+ return sprintf(buf, "AT0112%u,AT0112%u\n", get_module_rev(),
data->uCurFirmRev);
}
@@ -35,7 +35,7 @@ ssize_t mcu_model_name_show(struct device *dev,
return sprintf(buf, "%s\n", MODEL_NAME);
}
-ssize_t mcu_update_show(struct device *dev,
+ssize_t mcu_update_kernel_bin_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bSuccess = false;
@@ -44,39 +44,22 @@ ssize_t mcu_update_show(struct device *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 = forced_to_download_binary(data, UMS_BINARY);
+ if (iRet == SUCCESS) {
+ bSuccess = true;
+ goto out;
}
- 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:
+ 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_update2_show(struct device *dev,
+ssize_t mcu_update_kernel_crashed_bin_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool bSuccess = false;
@@ -85,35 +68,36 @@ ssize_t mcu_update2_show(struct device *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 = forced_to_download_binary(data, UMS_BINARY);
+ if (iRet == SUCCESS) {
+ bSuccess = true;
+ goto out;
}
- iRet = initialize_mcu(data);
- if (iRet < 0) {
- ssp_dbg("[SSP]: %s - initialize_mcu failed!\n", __func__);
- goto exit;
- }
+ 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"));
+}
- sync_sensor_state(data);
+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);
- enable_irq(data->iIrq);
- enable_irq_wake(data->iIrq);
+ ssp_dbg("[SSP]: %s - mcu binany update!\n", __func__);
-#ifdef CONFIG_SENSORS_SSP_SENSORHUB
- ssp_report_sensorhub_notice(data, MSG2SSP_AP_STATUS_RESET);
-#endif
+ iRet = forced_to_download_binary(data, UMS_BINARY);
+ if (iRet == SUCCESS)
+ bSuccess = true;
+ else
+ bSuccess = false;
- bSuccess = true;
-exit:
return sprintf(buf, "%s\n", (bSuccess ? "OK" : "NG"));
}
@@ -230,7 +214,6 @@ ssize_t mcu_sleep_factorytest_show(struct device *dev,
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",
diff --git a/drivers/sensorhub/pressure_bmp182.c b/drivers/sensorhub/atmel/pressure_bmp182.c
index d5896f32bc2..d5896f32bc2 100644..100755
--- a/drivers/sensorhub/pressure_bmp182.c
+++ b/drivers/sensorhub/atmel/pressure_bmp182.c
diff --git a/drivers/sensorhub/prox_cm36651.c b/drivers/sensorhub/atmel/prox_cm36651.c
index a7f91a79f37..797261dbd96 100644..100755
--- a/drivers/sensorhub/prox_cm36651.c
+++ b/drivers/sensorhub/atmel/prox_cm36651.c
@@ -68,7 +68,7 @@ static ssize_t proximity_avg_store(struct device *dev,
int64_t dEnable;
struct ssp_data *data = dev_get_drvdata(dev);
- iRet = strict_strtoll(buf, 10, &dEnable);
+ iRet = kstrtoll(buf, 10, &dEnable);
if (iRet < 0)
return iRet;
@@ -228,7 +228,7 @@ static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD)
set_fs(KERNEL_DS);
cancel_filp = filp_open(CANCELATION_FILE_PATH,
- O_CREAT | O_TRUNC | O_WRONLY, 0666);
+ 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);
@@ -331,7 +331,7 @@ static ssize_t barcode_emul_enable_store(struct device *dev,
int64_t dEnable;
struct ssp_data *data = dev_get_drvdata(dev);
- iRet = strict_strtoll(buf, 10, &dEnable);
+ iRet = kstrtoll(buf, 10, &dEnable);
if (iRet < 0)
return iRet;
@@ -346,6 +346,7 @@ static ssize_t barcode_emul_enable_store(struct device *dev,
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,
@@ -359,6 +360,7 @@ 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,
diff --git a/drivers/sensorhub/sensors_core.c b/drivers/sensorhub/atmel/sensors_core.c
index f968df82610..f968df82610 100644..100755
--- a/drivers/sensorhub/sensors_core.c
+++ b/drivers/sensorhub/atmel/sensors_core.c
diff --git a/drivers/sensorhub/ssp.h b/drivers/sensorhub/atmel/ssp.h
index 33534f5300a..904286884d6 100644..100755
--- a/drivers/sensorhub/ssp.h
+++ b/drivers/sensorhub/atmel/ssp.h
@@ -67,6 +67,13 @@
#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 */
@@ -129,6 +136,9 @@ enum {
#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
@@ -146,11 +156,13 @@ enum {
#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 {
@@ -190,6 +202,17 @@ enum {
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 {
@@ -236,6 +259,7 @@ struct ssp_data {
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;
@@ -259,6 +283,7 @@ struct ssp_data {
int iIrq;
int iLibraryLength;
int aiCheckStatus[SENSOR_MAX];
+ int fw_dl_state;
unsigned int uIrqFailCnt;
unsigned int uSsdFailCnt;
@@ -324,14 +349,11 @@ 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 *);
+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_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 *);
@@ -344,6 +366,7 @@ 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 *);
@@ -357,7 +380,7 @@ 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 *);
+int print_mcu_debug(char *, int *, int);
unsigned int get_module_rev(void);
void reset_mcu(struct ssp_data *);
void convert_acc_data(s16 *);
@@ -366,8 +389,12 @@ int sensors_register(struct device *, void *,
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_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 *,
diff --git a/drivers/sensorhub/ssp_ak8963c.c b/drivers/sensorhub/atmel/ssp_ak8963c.c
index 00a4f7dffca..00a4f7dffca 100644..100755
--- a/drivers/sensorhub/ssp_ak8963c.c
+++ b/drivers/sensorhub/atmel/ssp_ak8963c.c
diff --git a/drivers/sensorhub/ssp_data.c b/drivers/sensorhub/atmel/ssp_data.c
index 1be865c7d17..09d5c099ac6 100644..100755
--- a/drivers/sensorhub/ssp_data.c
+++ b/drivers/sensorhub/atmel/ssp_data.c
@@ -230,12 +230,19 @@ int parse_dataframe(struct ssp_data *data, char *pchRcvDataFrame, int iLength)
&iDataIdx);
} else if (pchRcvDataFrame[iDataIdx] ==
MSG2AP_INST_DEBUG_DATA) {
- print_mcu_debug(pchRcvDataFrame + iDataIdx + 1,
- &iDataIdx);
+ 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_handle_sensorhub_data(data,
+ ssp_sensorhub_handle_data(data,
pchRcvDataFrame, iDataIdx, iLength);
break;
#endif
diff --git a/drivers/sensorhub/ssp_debug.c b/drivers/sensorhub/atmel/ssp_debug.c
index 6c9460634d7..1e127675b7b 100644..100755
--- a/drivers/sensorhub/ssp_debug.c
+++ b/drivers/sensorhub/atmel/ssp_debug.c
@@ -26,37 +26,49 @@
/* SSP Debug timer function */
/*************************************************************************/
-void print_mcu_debug(char *pchRcvDataFrame, int *pDataIdx)
+int print_mcu_debug(char *pchRcvDataFrame, int *pDataIdx,
+ int iRcvDataFrameLength)
{
- int iLength;
+ int iLength = pchRcvDataFrame[0];
- iLength = pchRcvDataFrame[0];
- pchRcvDataFrame[iLength] = 0;
- *pDataIdx = *pDataIdx + iLength + 2;
+ 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)
{
- data->bSspShutdown = true;
- disable_irq(data->iIrq);
- disable_irq_wake(data->iIrq);
+ 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)
- data->bSspShutdown = true;
+ return;
- sync_sensor_state(data);
+ if (data->bSspShutdown == true) {
+ data->bSspShutdown = false;
+ enable_irq(data->iIrq);
+ enable_irq_wake(data->iIrq);
+ }
- enable_irq(data->iIrq);
- enable_irq_wake(data->iIrq);
+ sync_sensor_state(data);
#ifdef CONFIG_SENSORS_SSP_SENSORHUB
- ssp_report_sensorhub_notice(data, MSG2SSP_AP_STATUS_RESET);
+ ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_RESET);
#endif
}
@@ -134,21 +146,37 @@ static void debug_work_func(struct work_struct *work)
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)
+ 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->uTimeOutCnt + data->uBusyCnt) > LIMIT_TIMEOUT_CNT))
+ && (data->bSspShutdown == false)) {
if (data->uResetCnt < LIMIT_RESET_CNT) {
reset_mcu(data);
data->uResetCnt++;
} else {
- data->bSspShutdown = true;
+ if (data->bSspShutdown == false) {
+ data->bSspShutdown = true;
+ disable_irq_wake(data->iIrq);
+ disable_irq(data->iIrq);
+ }
}
data->uSsdFailCnt = 0;
diff --git a/drivers/sensorhub/ssp_dev.c b/drivers/sensorhub/atmel/ssp_dev.c
index 64932f13d5b..852358b6f61 100644..100755
--- a/drivers/sensorhub/ssp_dev.c
+++ b/drivers/sensorhub/atmel/ssp_dev.c
@@ -104,6 +104,7 @@ 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) {
@@ -115,29 +116,31 @@ int initialize_mcu(struct ssp_data *data)
__func__);
iRet = -ENODEV;
}
- return iRet;
+ goto out;
}
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;
+ goto out;
}
data->uSensorState = get_sensor_scanning_info(data);
if (data->uSensorState == 0) {
pr_err("[SSP]: %s - get_sensor_scanning_info failed\n",
__func__);
- return FAIL;
+ iRet = ERROR;
+ goto out;
}
- return SUCCESS;
+ 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)
@@ -154,7 +157,7 @@ static int initialize_irq(struct ssp_data *data)
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);
+ __func__, data->client->irq, iRet);
goto err_irq_direction_input;
}
@@ -165,7 +168,7 @@ static int initialize_irq(struct ssp_data *data)
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);
+ __func__, iIrq, iIrq, iRet);
goto err_request_irq;
}
@@ -180,6 +183,25 @@ err_irq_direction_input:
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)
{
@@ -201,6 +223,7 @@ static int ssp_probe(struct i2c_client *client,
goto exit;
}
+ data->fw_dl_state = FW_DL_STATE_NONE;
data->client = client;
i2c_set_clientdata(client, data);
@@ -221,16 +244,24 @@ static int ssp_probe(struct i2c_client *client,
}
pr_info("\n#####################################################\n");
+ INIT_DELAYED_WORK(&data->work_firmware, work_function_firmware_update);
/* check boot loader binary */
- check_fwbl(data);
+ data->fw_dl_state = 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;
+ 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,
@@ -280,13 +311,14 @@ static int ssp_probe(struct i2c_client *client,
#ifdef CONFIG_SENSORS_SSP_SENSORHUB
/* init sensorhub device */
- iRet = ssp_initialize_sensorhub(data);
+ iRet = ssp_sensorhub_initialize(data);
if (iRet < 0) {
- pr_err("%s: ssp_initialize_sensorhub err(%d)", __func__, iRet);
- ssp_remove_sensorhub(data);
+ 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__);
@@ -294,6 +326,15 @@ static int ssp_probe(struct i2c_client *client,
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:
@@ -323,16 +364,25 @@ static void ssp_shutdown(struct i2c_client *client)
struct ssp_data *data = i2c_get_clientdata(client);
func_dbg();
- data->bSspShutdown = true;
+
+ 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);
+ }
- disable_irq_wake(data->iIrq);
- disable_irq(data->iIrq);
free_irq(data->iIrq, data);
gpio_free(data->client->irq);
@@ -341,7 +391,7 @@ static void ssp_shutdown(struct i2c_client *client)
remove_input_dev(data);
#ifdef CONFIG_SENSORS_SSP_SENSORHUB
- ssp_remove_sensorhub(data);
+ ssp_sensorhub_remove(data);
#endif
misc_deregister(&data->akmd_device);
@@ -365,14 +415,9 @@ static void ssp_early_suspend(struct early_suspend *handler)
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
+ ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_SLEEP);
+ ssp_send_status_cmd(data, MSG2SSP_AP_STATUS_SLEEP);
data->bCheckSuspend = true;
}
@@ -387,17 +432,12 @@ static void ssp_late_resume(struct early_suspend *handler)
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
+ ssp_sensorhub_report_notice(data, MSG2SSP_AP_STATUS_WAKEUP);
+ ssp_send_status_cmd(data, MSG2SSP_AP_STATUS_WAKEUP);
}
-#else /* CONFIG_HAS_EARLYSUSPEND */
+#endif /* CONFIG_HAS_EARLYSUSPEND */
static int ssp_suspend(struct device *dev)
{
@@ -405,12 +445,9 @@ static int ssp_suspend(struct device *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);
+ ssp_send_status_cmd(data, MSG2SSP_AP_STATUS_SUSPEND);
- data->bCheckSuspend = true;
return 0;
}
@@ -420,12 +457,8 @@ static int ssp_resume(struct device *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);
+ ssp_send_status_cmd(data, MSG2SSP_AP_STATUS_RESUME);
return 0;
}
@@ -435,8 +468,6 @@ static const struct dev_pm_ops ssp_pm_ops = {
.resume = ssp_resume
};
-#endif /* CONFIG_HAS_EARLYSUSPEND */
-
static const struct i2c_device_id ssp_id[] = {
{"ssp", 0},
{}
@@ -449,9 +480,7 @@ static struct i2c_driver ssp_driver = {
.shutdown = ssp_shutdown,
.id_table = ssp_id,
.driver = {
-#ifndef CONFIG_HAS_EARLYSUSPEND
.pm = &ssp_pm_ops,
-#endif
.owner = THIS_MODULE,
.name = "ssp"
},
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/ssp_i2c.c b/drivers/sensorhub/atmel/ssp_i2c.c
index 695ad8dae34..e78b24f0833 100644..100755
--- a/drivers/sensorhub/ssp_i2c.c
+++ b/drivers/sensorhub/atmel/ssp_i2c.c
@@ -33,7 +33,7 @@ int waiting_wakeup_mcu(struct ssp_data *data)
iDelaycnt = 0;
data->wakeup_mcu();
- while (data->check_mcu_ready() && (iDelaycnt++ < LIMIT_DELAY_CNT)
+ while (!data->check_mcu_ready() && (iDelaycnt++ < LIMIT_DELAY_CNT)
&& (data->bSspShutdown == false))
mdelay(5);
@@ -45,7 +45,36 @@ int waiting_wakeup_mcu(struct ssp_data *data)
}
if (data->bSspShutdown == true)
- return FAIL;
+ 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;
}
@@ -90,31 +119,30 @@ int ssp_i2c_read(struct ssp_data *data, char *pTxData, u16 uTxLength,
} else {
return SUCCESS;
}
- } while (--iRetries);
+ } while (--iRetries > 0);
return ERROR;
}
-int ssp_sleep_mode(struct ssp_data *data)
+int ssp_send_status_cmd(struct ssp_data *data, char chTxBuf)
{
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 */
+ /* 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_SLEEP CMD fail %d\n",
- __func__, iRet);
+ 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--) {
+ while (--iRetries > 0) {
mdelay(10);
- pr_err("[SSP]: %s - MSG2SSP_AP_STATUS_SLEEP CMD "
- "retry...\n", __func__);
+ 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))
@@ -128,45 +156,7 @@ int ssp_sleep_mode(struct ssp_data *data)
}
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__);
+ ssp_dbg("[SSP]: %s - MSG2SSP_AP_STATUS_CMD(0x%x)\n", __func__, chTxBuf);
return SUCCESS;
}
@@ -174,11 +164,15 @@ int ssp_resume_mode(struct ssp_data *data)
int send_instruction(struct ssp_data *data, u8 uInst,
u8 uSensorType, u8 *uSendBuf, u8 uLength)
{
- char chTxbuf[uLength + 3];
+ char chTxbuf[uLength + 4];
char chRxbuf = 0;
int iRet = 0, iRetries = DEFAULT_RETRIES;
- if ((!(data->uSensorState & (1 << uSensorType)))
+ 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);
@@ -194,51 +188,52 @@ int send_instruction(struct ssp_data *data, u8 uInst,
return ERROR;
chTxbuf[0] = MSG2SSP_SSM;
+ chTxbuf[1] = (char)(uLength + 4);
switch (uInst) {
case REMOVE_SENSOR:
- chTxbuf[1] = MSG2SSP_INST_BYPASS_SENSOR_REMOVE;
+ chTxbuf[2] = MSG2SSP_INST_BYPASS_SENSOR_REMOVE;
break;
case ADD_SENSOR:
- chTxbuf[1] = MSG2SSP_INST_BYPASS_SENSOR_ADD;
+ chTxbuf[2] = MSG2SSP_INST_BYPASS_SENSOR_ADD;
break;
case CHANGE_DELAY:
- chTxbuf[1] = MSG2SSP_INST_CHANGE_DELAY;
+ chTxbuf[2] = MSG2SSP_INST_CHANGE_DELAY;
break;
case GO_SLEEP:
- chTxbuf[1] = MSG2SSP_AP_STATUS_SLEEP;
+ chTxbuf[2] = MSG2SSP_AP_STATUS_SLEEP;
break;
case FACTORY_MODE:
- chTxbuf[1] = MSG2SSP_INST_SENSOR_SELFTEST;
+ chTxbuf[2] = MSG2SSP_INST_SENSOR_SELFTEST;
break;
case REMOVE_LIBRARY:
- chTxbuf[1] = MSG2SSP_INST_LIBRARY_REMOVE;
+ chTxbuf[2] = MSG2SSP_INST_LIBRARY_REMOVE;
break;
case ADD_LIBRARY:
- chTxbuf[1] = MSG2SSP_INST_LIBRARY_ADD;
+ chTxbuf[2] = MSG2SSP_INST_LIBRARY_ADD;
break;
default:
- chTxbuf[1] = uInst;
+ chTxbuf[2] = uInst;
break;
}
- chTxbuf[2] = uSensorType;
- memcpy(&chTxbuf[3], uSendBuf, uLength);
+ chTxbuf[3] = uSensorType;
+ memcpy(&chTxbuf[4], uSendBuf, uLength);
- iRet = ssp_i2c_read(data, &(chTxbuf[0]), uLength + 3, &chRxbuf, 1,
+ 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--) {
+ 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 + 3, &chRxbuf, 1, DEFAULT_RETRIES);
+ uLength + 4, &chRxbuf, 1, DEFAULT_RETRIES);
if ((iRet == SUCCESS) && (chRxbuf == MSG_ACK))
break;
}
@@ -250,9 +245,8 @@ int send_instruction(struct ssp_data *data, u8 uInst,
}
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]);
+ ssp_dbg("[SSP]: %s - Inst = 0x%x, Sensor Type = 0x%x, " "data = %u\n",
+ __func__, chTxbuf[2], chTxbuf[3], chTxbuf[4]);
return SUCCESS;
}
@@ -260,7 +254,7 @@ int get_chipid(struct ssp_data *data)
{
int iRet;
- if (waiting_wakeup_mcu(data) < 0)
+ if (waiting_init_mcu(data) < 0)
return ERROR;
/* read chip id */
@@ -275,7 +269,7 @@ int set_sensor_position(struct ssp_data *data)
char chRxData = 0;
int iRet = 0;
- if (waiting_wakeup_mcu(data) < 0)
+ if (waiting_init_mcu(data) < 0)
return ERROR;
chTxBuf[0] = MSG2SSP_AP_SENSOR_FORMATION;
@@ -304,8 +298,16 @@ void set_proximity_threshold(struct ssp_data *data,
char chRxBuf = 0;
int iRet = 0, iRetries = DEFAULT_RETRIES;
- if (waiting_wakeup_mcu(data) < 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;
+ } 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;
@@ -317,7 +319,7 @@ void set_proximity_threshold(struct ssp_data *data,
__func__, iRet);
return;
} else if (chRxBuf != MSG_ACK) {
- while (iRetries--) {
+ while (--iRetries > 0) {
mdelay(10);
pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_PROXTHRESHOLD CMD"
" retry...\n", __func__);
@@ -344,7 +346,7 @@ void set_proximity_barcode_enable(struct ssp_data *data, bool bEnable)
int iRet = 0, iRetries = DEFAULT_RETRIES;
if (waiting_wakeup_mcu(data) < 0)
- return ;
+ return;
chTxBuf[0] = MSG2SSP_AP_SENSOR_BARCODE_EMUL;
chTxBuf[1] = bEnable;
@@ -357,7 +359,7 @@ void set_proximity_barcode_enable(struct ssp_data *data, bool bEnable)
__func__, iRet);
return;
} else if (chRxBuf != MSG_ACK) {
- while (iRetries--) {
+ while (--iRetries > 0) {
mdelay(10);
pr_err("[SSP]: %s - MSG2SSP_AP_SENSOR_BARCODE_EMUL CMD "
"retry...\n", __func__);
@@ -383,7 +385,7 @@ unsigned int get_sensor_scanning_info(struct ssp_data *data)
char chRxData[2] = {0,};
int iRet = 0;
- if (waiting_wakeup_mcu(data) < 0)
+ if (waiting_init_mcu(data) < 0)
return ERROR;
iRet = ssp_i2c_read(data, &chTxBuf, 1, chRxData, 2, DEFAULT_RETRIES);
@@ -398,7 +400,7 @@ unsigned int get_firmware_rev(struct ssp_data *data)
{
char chTxData = MSG2SSP_AP_FIRMWARE_REV;
char chRxBuf[3] = { 0, };
- unsigned int uRev = 99999;
+ unsigned int uRev = SSP_INVALID_REVISION;
int iRet;
if (waiting_wakeup_mcu(data) < 0)
@@ -420,7 +422,7 @@ int get_fuserom_data(struct ssp_data *data)
int iRet = 0;
unsigned int uLength = 0;
- if (waiting_wakeup_mcu(data) < 0)
+ if (waiting_init_mcu(data) < 0)
return ERROR;
chTxBuf[0] = MSG2SSP_AP_STT;
@@ -434,7 +436,7 @@ int get_fuserom_data(struct ssp_data *data)
pr_err("[SSP]: %s - MSG2SSP_AP_STT - i2c fail %d\n",
__func__, iRet);
goto err_read_fuserom;
- } else if (uLength <= 0) {
+ } else if (uLength == 0) {
pr_err("[SSP]: %s - No ready data. length = %u\n",
__func__, uLength);
goto err_read_fuserom;
@@ -485,6 +487,12 @@ static int ssp_receive_msg(struct ssp_data *data, u8 uLength)
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);
@@ -528,16 +536,19 @@ int select_irq_msg(struct ssp_data *data)
#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,
+ iRet = ssp_sensorhub_handle_large_data(data,
(u8)chRxBuf[1]);
if (iRet < 0) {
- pr_err("%s: ssp_handle_sensorhub_data(%d)",
+ pr_err("%s: ssp sensorhub large data err(%d)",
__func__, iRet);
}
data->uSsdFailCnt = 0;
}
#endif
- else {
+ 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]);
diff --git a/drivers/sensorhub/ssp_input.c b/drivers/sensorhub/atmel/ssp_input.c
index a7de8c60836..a7de8c60836 100644..100755
--- a/drivers/sensorhub/ssp_input.c
+++ b/drivers/sensorhub/atmel/ssp_input.c
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/ssp_sensorhub.h b/drivers/sensorhub/atmel/ssp_sensorhub.h
index 4ececf6b6ec..a0dedd2be08 100644..100755
--- a/drivers/sensorhub/ssp_sensorhub.h
+++ b/drivers/sensorhub/atmel/ssp_sensorhub.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved.
+ * 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
@@ -22,20 +22,25 @@
#include <linux/spinlock.h>
#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
+#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
-/* sensorhub ioctl command */
-#define SENSORHUB_IOCTL_MAGIC 'S'
-#define IOCTL_READ_CONTEXT_DATA _IOR(SENSORHUB_IOCTL_MAGIC, 3, char *)
+#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 length;
+ int library_length;
struct list_head list;
};
@@ -44,25 +49,23 @@ struct ssp_sensorhub_data {
struct input_dev *sensorhub_input_dev;
struct miscdevice sensorhub_device;
struct wake_lock sensorhub_wake_lock;
- struct completion transfer_done;
+ struct completion sensorhub_completion;
struct task_struct *sensorhub_task;
struct sensorhub_event events_head;
- struct sensorhub_event events[LIBRARY_MAX_NUM + 1];
+ struct sensorhub_event events[LIST_SIZE];
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;
+ int large_library_length;
+ int event_number;
+ wait_queue_head_t sensorhub_wq;
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,
+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_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);
+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/ssp_sysfs.c b/drivers/sensorhub/atmel/ssp_sysfs.c
index 1bc7f178d68..ad2074148f4 100644..100755
--- a/drivers/sensorhub/ssp_sysfs.c
+++ b/drivers/sensorhub/atmel/ssp_sysfs.c
@@ -189,7 +189,7 @@ static ssize_t set_sensors_enable(struct device *dev,
struct ssp_data *data = dev_get_drvdata(dev);
int iRet;
- if (strict_strtoll(buf, 10, &dTemp) < 0)
+ if (kstrtoll(buf, 10, &dTemp) < 0)
return -1;
uNewEnable = (unsigned int)dTemp;
@@ -197,9 +197,9 @@ static ssize_t set_sensors_enable(struct device *dev,
uNewEnable, atomic_read(&data->aSensorEnable));
if (uNewEnable == atomic_read(&data->aSensorEnable))
- return 0;
+ return size;
- for (uChangedSensor = 0; uChangedSensor < SENSOR_MAX; uChangedSensor++)
+ for (uChangedSensor = 0; uChangedSensor < SENSOR_MAX; uChangedSensor++) {
if ((atomic_read(&data->aSensorEnable) & (1 << uChangedSensor))
!= (uNewEnable & (1 << uChangedSensor))) {
@@ -223,6 +223,7 @@ static ssize_t set_sensors_enable(struct device *dev,
}
break;
}
+ }
atomic_set(&data->aSensorEnable, uNewEnable);
@@ -243,7 +244,7 @@ static ssize_t set_acc_delay(struct device *dev,
int64_t dNewDelay;
struct ssp_data *data = dev_get_drvdata(dev);
- if (strict_strtoll(buf, 10, &dNewDelay) < 0)
+ if (kstrtoll(buf, 10, &dNewDelay) < 0)
return -1;
if ((atomic_read(&data->aSensorEnable) & (1 << ORIENTATION_SENSOR)) &&
@@ -269,7 +270,7 @@ static ssize_t set_ori_delay(struct device *dev,
int64_t dNewDelay;
struct ssp_data *data = dev_get_drvdata(dev);
- if (strict_strtoll(buf, 10, &dNewDelay) < 0)
+ if (kstrtoll(buf, 10, &dNewDelay) < 0)
return -1;
if (data->aiCheckStatus[ACCELEROMETER_SENSOR] == NO_SENSOR_STATE) {
@@ -300,7 +301,7 @@ static ssize_t set_gyro_delay(struct device *dev,
int64_t dNewDelay;
struct ssp_data *data = dev_get_drvdata(dev);
- if (strict_strtoll(buf, 10, &dNewDelay) < 0)
+ if (kstrtoll(buf, 10, &dNewDelay) < 0)
return -1;
change_sensor_delay(data, GYROSCOPE_SENSOR, dNewDelay);
@@ -321,7 +322,7 @@ static ssize_t set_mag_delay(struct device *dev,
int64_t dNewDelay;
struct ssp_data *data = dev_get_drvdata(dev);
- if (strict_strtoll(buf, 10, &dNewDelay) < 0)
+ if (kstrtoll(buf, 10, &dNewDelay) < 0)
return -1;
change_sensor_delay(data, GEOMAGNETIC_SENSOR, dNewDelay);
@@ -343,7 +344,7 @@ static ssize_t set_pressure_delay(struct device *dev,
int64_t dNewDelay;
struct ssp_data *data = dev_get_drvdata(dev);
- if (strict_strtoll(buf, 10, &dNewDelay) < 0)
+ if (kstrtoll(buf, 10, &dNewDelay) < 0)
return -1;
change_sensor_delay(data, PRESSURE_SENSOR, dNewDelay);
@@ -364,7 +365,7 @@ static ssize_t set_light_delay(struct device *dev,
int64_t dNewDelay;
struct ssp_data *data = dev_get_drvdata(dev);
- if (strict_strtoll(buf, 10, &dNewDelay) < 0)
+ if (kstrtoll(buf, 10, &dNewDelay) < 0)
return -1;
change_sensor_delay(data, LIGHT_SENSOR, dNewDelay);
@@ -385,7 +386,7 @@ static ssize_t set_prox_delay(struct device *dev,
int64_t dNewDelay;
struct ssp_data *data = dev_get_drvdata(dev);
- if (strict_strtoll(buf, 10, &dNewDelay) < 0)
+ if (kstrtoll(buf, 10, &dNewDelay) < 0)
return -1;
change_sensor_delay(data, PROXIMITY_SENSOR, dNewDelay);
@@ -394,29 +395,36 @@ static ssize_t set_prox_delay(struct device *dev,
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_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(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,
+
+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 DEVICE_ATTR(light_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
+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 DEVICE_ATTR(prox_poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
+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[] = {
@@ -427,6 +435,7 @@ static struct device_attribute *mcu_attrs[] = {
&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,
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_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/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 <linux/kernel.h>
+#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 <linux/platform_device.h>
+#include <plat/adc.h>
+
+/*************************************************************************/
+/* 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 <ryun.park@samsung.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+
+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 <ryun.park@samsung.com>");
+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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/wakelock.h>
+#include <linux/miscdevice.h>
+#include <linux/ssp_platformdata.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/timer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#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 <mach/gpio.h>
+#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 <mach/gpio.h>
+
+#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 <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#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();
+}