Add samsung specific changes

This commit is contained in:
2025-08-11 14:29:00 +02:00
parent c66122e619
commit 4d134a1294
2688 changed files with 1127995 additions and 11475 deletions

403
drivers/adsp_factory/Kconfig Executable file
View File

@@ -0,0 +1,403 @@
#
# factory sensor drivers configuration
#
config ADSP_FACTORY
tristate "MSM ADSP factory driver"
help
This driver communicate with SSC DAEMON.
register each sensor device.
send selftest request using netlink.
receive test result using netlink.
config LSM6DSO_FACTORY
bool "factory test for SSC - LSM6DSO"
depends on ADSP_FACTORY
help
lsm6dso factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config LSM6DSL_FACTORY
bool "factory test for SSC - LSM6DSL"
depends on ADSP_FACTORY
help
lsm6dsl factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config LSM6DSV_FACTORY
bool "factory test for SSC - LSM6DSV"
depends on ADSP_FACTORY
help
lsm6dsv factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config SUPPORT_ACCEL_HIGHG
bool "support HIGH G ACCEL"
depends on ADSP_FACTORY
help
highg accel factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config AK09918_FACTORY
bool "factory test for SSC - ak09918"
depends on ADSP_FACTORY
help
ak09918 factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config SUPPORT_MAG_ABS_SUM
tristate "mag abs sum for SSC"
depends on AK09918_FACTORY
help
Support the mag abs sum check
check the mag abs sum value.
config LPS22HH_FACTORY
bool "factory test for SSC - lps22hh"
depends on ADSP_FACTORY
help
lps22hh factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config LPS22DF_FACTORY
bool "factory test for SSC - lps22df"
depends on ADSP_FACTORY
help
lps22df factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config PRESSURE_FACTORY
bool "factory test for SSC - pressure"
depends on ADSP_FACTORY
help
pressure factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config LIGHT_FACTORY
bool "factory test for SSC - light"
depends on ADSP_FACTORY
help
light factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config LIGHT_SUB_FACTORY
bool "factory test for SSC - light sub"
depends on ADSP_FACTORY
help
light sub factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config PROX_FACTORY
bool "factory test for SSC - prox"
depends on ADSP_FACTORY
help
prox factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config STK33610_FACTORY
bool "factory test for SSC - STK33610"
depends on ADSP_FACTORY
help
stk33610 factory driver.
provide sysfs for factory test.
request selftest through factory daemon to slpi.
receive test result through factory daemon from slpi.
config STK33610_SUB_FACTORY
bool "factory test for SSC - STK33610"
depends on ADSP_FACTORY
help
stk33610 factory driver.
provide sysfs for factory test.
request selftest through factory daemon to slpi.
receive test result through factory daemon from slpi.
config SUPPORT_LIGHT_CALIBRATION
bool "light cal for SSC"
depends on ADSP_FACTORY
help
light calibration feature.
provide sysfs for light calibration.
request light cal to adsp_factory.
receive cal value from adsp_factory.
config SUPPORT_PROX_CALIBRATION
bool "prox cal for SSC"
depends on ADSP_FACTORY
help
prox calibration feature.
provide sysfs for prox calibration.
request prox cal to adsp_factory.
receive cal value from adsp_factory.
config SUPPORT_CONTROL_PROX_LED_GPIO
bool "control prox led gpio for SSC"
depends on ADSP_FACTORY
help
Support to control prox led gpio.
config SUPPORT_PROX_POWER_ON_CAL
bool "Sensors support proximity sensor power on cal"
depends on ADSP_FACTORY
help
Support power on calibration for proximity sensor
make calibration process done as the device power up.
config SUPPORT_BRIGHTNESS_NOTIFY_FOR_LIGHT_SENSOR
bool "Sensors support brightness notify"
depends on ADSP_FACTORY
help
Support brightness notify for light sensor.
receive aor and brightness level from lcd driver.
config SUPPORT_PANEL_STATE_NOTIFY_FOR_LIGHT_SENSOR
bool "Sensors support panel state notify"
depends on ADSP_FACTORY
help
Support panel state notify for light sensor.
receive panel state from lcd driver.
config SUPPORT_DDI_COPR_FOR_LIGHT_SENSOR
bool "Sensors support ddi copr"
depends on ADSP_FACTORY
help
Support ddi copr for light sensor.
provide copr sysfs for factory and afc service.
DDI must be connected with sensor core
config SUPPORT_AP_COPR_FOR_LIGHT_SENSOR
bool "Sensors support ap copr"
depends on ADSP_FACTORY
help
Support ap copr for light sensor.
provide copr sysfs for factory and afc service.
The display driver must provide copr data as notify.
config SUPPORT_DUAL_DDI_COPR_FOR_LIGHT_SENSOR
bool "Sensors support dual ddi copr"
depends on ADSP_FACTORY
help
Support dual ddi copr for light sensor.
provide copr sysfs for factory and afc service.
DDI must be connected with sensor core
config SUPPORT_DUAL_6AXIS
bool "Sensors support dual 6axis"
depends on ADSP_FACTORY
help
Support the dual accel and gyro function.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config SUPPORT_TRIPLE_6AXIS
bool "Sensors support triple 6axis"
depends on ADSP_FACTORY
help
Support the triple accel and gyro function.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config SUPPORT_DUAL_MAG
bool "Sensors support dual magnetic sensors"
depends on ADSP_FACTORY
help
Support the dual mag function.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config SUPPORT_DUAL_OPTIC
bool "Sensors support dual optic"
depends on ADSP_FACTORY
help
Support the dual prox and light function.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config SUPPORT_VIRTUAL_OPTIC
bool "Sensors support virtual optic"
depends on ADSP_FACTORY
help
Support the virtual prox and light function.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config SUPPORT_DUAL_OPTIC_BUT_SUPPORT_SINGLE_PROX
bool "Sensors support virtual optic but support single prox"
depends on ADSP_FACTORY
help
Support the virtual prox and light function.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config SUPPORT_SENSOR_FLIP_MODEL
bool "Sensors support sensor flip model"
depends on ADSP_FACTORY
help
Support sensor flip model.
Separate the flip model from the factory test.
config SUPPORT_AK09973
bool "Support ak09973"
depends on ADSP_FACTORY
help
Support ak09973.
config SUPPORT_DHALL_SWITCH
bool "Support DHALL_SWITCH"
depends on ADSP_FACTORY
help
Support ak09973.
config SUPPORT_DEVICE_MODE
bool "Support device mode"
depends on ADSP_FACTORY
help
Support device mode.
config SUPPORT_SENSOR_FOLD
bool "Support fold state by sensor algorithm"
depends on ADSP_FACTORY
help
Support fold state by sensor algorithm.
config VEML3235_FACTORY
bool "factory test for SSC - veml3235"
depends on ADSP_FACTORY
help
veml3235 factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config VEML3235_SUB_FACTORY
bool "factory test for SSC - veml3235_sub"
depends on ADSP_FACTORY
help
veml3235_sub factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config VEML3328_FACTORY
bool "factory test for SSC - veml3328"
depends on ADSP_FACTORY
help
veml3328 factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config VEML3328_SUB_FACTORY
bool "factory test for SSC - veml3328_sub"
depends on ADSP_FACTORY
help
veml3328_sub factory driver.
provide sysfs for factory test.
request selftest to adsp_factory.
receive test result from adsp_factory.
config SUPPORT_LIGHT_SEAMLESS
bool "Support Light seamless"
depends on ADSP_FACTORY
help
Support Light seamless.
config BACKTAP_FACTORY
bool "factory test for SSC - Back Tap Sensor"
depends on ADSP_FACTORY
help
backtap factory driver.
provide sysfs for setting back tap peak threshold
config FLIP_COVER_DETECTOR_FACTORY
bool "factory test for SSC - Flip Cover Detector"
depends on ADSP_FACTORY
help
flip_cover_detector factory driver.
provide sysfs for cover status by nfc
config FLIP_COVER_DETECTOR_NOTIFIER
bool "flip cover detector notifier"
depends on FLIP_COVER_DETECTOR_FACTORY
default y
help
Support notifier for flip cover attach/detach events
config SSC_WAKEUP_DEBUG
bool "debug to ap wakeup due to SSC"
depends on SEC_SENSORS_SSC
help
debug to ap wakeup due to SSC event frequently
config SLPI_LOADING_FAILURE_DEBUG
bool "debug to slpi loading fail"
depends on SEC_SENSORS_SSC
help
debug to to slpi loading fail
config SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL
bool "support ref angle without digital hall"
depends on ADSP_FACTORY
help
support ref angle without digital hall
config SENSOR_FACTORY_KUNIT_FOR_ON_DEVICE
tristate "KUnit test for sensor factory kunit"
depends on SEC_KUNIT
depends on ADSP_FACTORY
config SENSOR_FACTORY_KUNIT_FOR_ONLY_UML
tristate "KUnit test for sensor factory kunit"
depends on SEC_KUNIT
depends on UML
depends on ADSP_FACTORY
config AK09973_DIGITAL_HALL_TEST_FOR_ON_DEVICE
tristate "KUnit test for ak09973_digital_hall_test"
depends on SEC_KUNIT
depends on SUPPORT_AK09973
help
TODO: Describe config fully.
If you run this test driver on device, SHOULD set this config as 'm' to build test driver modulraly.
config AK09973_DIGITAL_HALL_TEST_FOR_ONLY_UML
tristate "KUnit test for ak09973_digital_hall_test"
depends on SEC_KUNIT
depends on UML
depends on SUPPORT_AK09973
help
TODO: Describe config fully.
This CONFIG is recommended to set to y.
config SEC_SENSORS_RECOVERY
bool "recovery slpi or adsp for sensor"
depends on SEC_SENSORS_SSC
help
recovery to slpi or adsp for sensor

17
drivers/adsp_factory/Makefile Executable file
View File

@@ -0,0 +1,17 @@
obj-$(CONFIG_ADSP_FACTORY) += adsp_factory_module.o
adsp_factory_module-$(CONFIG_ADSP_FACTORY) := adsp_factory.o ssc_core.o
adsp_factory_module-$(CONFIG_LSM6DSO_FACTORY) += lsm6dso_accel.o lsm6dso_gyro.o
adsp_factory_module-$(CONFIG_SUPPORT_ACCEL_HIGHG) += accel_highg_factory.o
adsp_factory_module-$(CONFIG_AK09918_FACTORY) += ak09918_mag.o
adsp_factory_module-$(CONFIG_LPS22HH_FACTORY) += lps22hh_pressure.o
adsp_factory_module-$(CONFIG_PRESSURE_FACTORY) += pressure_factory.o
adsp_factory_module-$(CONFIG_LIGHT_FACTORY) += light_factory.o
adsp_factory_module-$(CONFIG_PROX_FACTORY) += prox_factory.o
adsp_factory_module-$(CONFIG_SUPPORT_DUAL_6AXIS) += lsm6dso_sub_accel.o lsm6dso_sub_gyro.o
adsp_factory_module-$(CONFIG_SUPPORT_TRIPLE_6AXIS) += sub2_accel.o sub2_gyro.o
adsp_factory_module-$(CONFIG_LSM6DSL_FACTORY) += lsm6dsl_accel.o lsm6dsl_gyro.o
adsp_factory_module-$(CONFIG_SUPPORT_AK09973) += ak09973_digital_hall.o
adsp_factory_module-$(CONFIG_FLIP_COVER_DETECTOR_FACTORY) += flip_cover_detector.o
adsp_factory_module-$(CONFIG_BACKTAP_FACTORY) += back_tap.o
adsp_factory_module-$(CONFIG_SUPPORT_DUAL_MAG) += mag_sub_factory.o
GCOV_PROFILE_ak09973_digital_hall.o := $(CONFIG_KUNIT)

View File

@@ -0,0 +1,400 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#if IS_ENABLED(CONFIG_SEC_DEBUG)
#include <linux/samsung/debug/sec_debug.h>
#endif
#if IS_ENABLED(CONFIG_LSM6DSV_FACTORY)
#define VENDOR "STM"
#define CHIP_ID "LSM6DSV256X"
#else
#define VENDOR "UNKNOWN"
#define CHIP_ID "UNKNOWN"
#endif
#define ACCEL_ST_TRY_CNT 3
#define ACCEL_FACTORY_CAL_CNT 20
#define ACCEL_RAW_DATA_CNT 3
#define MAX_ACCEL_1G 128 /*256G*/
struct accel_highg_data {
struct work_struct work_accel;
struct workqueue_struct *accel_wq;
struct adsp_data *dev_data;
bool is_complete_cal;
bool lpf_onoff;
bool st_complete;
int32_t raw_data[ACCEL_RAW_DATA_CNT];
int32_t avg_data[ACCEL_RAW_DATA_CNT];
};
static struct accel_highg_data *pdata;
static ssize_t accel_highg_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t accel_highg_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t sensor_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", "ADSP");
}
int get_accel_highg_cal_data(struct adsp_data *data, int32_t *cal_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_ACCEL_HIGHG, 0, MSG_TYPE_GET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_CAL_DATA] & 1 << MSG_ACCEL_HIGHG) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_CAL_DATA] &= ~(1 << MSG_ACCEL_HIGHG);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return 0;
}
if (data->msg_buf[MSG_ACCEL_HIGHG][3] != ACCEL_RAW_DATA_CNT) {
pr_err("[FACTORY] %s: Reading Bytes Num %d!!!\n",
__func__, data->msg_buf[MSG_ACCEL_HIGHG][3]);
return 0;
}
cal_data[0] = data->msg_buf[MSG_ACCEL_HIGHG][0];
cal_data[1] = data->msg_buf[MSG_ACCEL_HIGHG][1];
cal_data[2] = data->msg_buf[MSG_ACCEL_HIGHG][2];
pr_info("[FACTORY] %s: %d, %d, %d, %d\n", __func__,
cal_data[0], cal_data[1], cal_data[2],
data->msg_buf[MSG_ACCEL_HIGHG][3]);
return data->msg_buf[MSG_ACCEL_HIGHG][3];
}
void set_accel_highg_cal_data(struct adsp_data *data)
{
uint8_t cnt = 0;
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__, pdata->avg_data[0],
pdata->avg_data[1], pdata->avg_data[2]);
adsp_unicast(pdata->avg_data, sizeof(pdata->avg_data),
MSG_ACCEL_HIGHG, 0, MSG_TYPE_SET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_SET_CAL_DATA] & 1 << MSG_ACCEL_HIGHG) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_CAL_DATA] &= ~(1 << MSG_ACCEL_HIGHG);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else if (data->msg_buf[MSG_ACCEL_HIGHG][0] != ACCEL_RAW_DATA_CNT) {
pr_err("[FACTORY] %s: Write Bytes Num %d!!!\n",
__func__, data->msg_buf[MSG_ACCEL_HIGHG][0]);
}
}
static ssize_t accel_highg_calibration_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t cal_data[ACCEL_RAW_DATA_CNT] = {0, };
int ret = 0;
mutex_lock(&data->accel_factory_mutex);
ret = get_accel_highg_cal_data(data, cal_data);
mutex_unlock(&data->accel_factory_mutex);
if (ret > 0) {
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
cal_data[0], cal_data[1], cal_data[2]);
if (cal_data[0] == 0 && cal_data[1] == 0 && cal_data[2] == 0)
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n",
0, 0, 0, 0);
else
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n",
true, cal_data[0], cal_data[1], cal_data[2]);
} else {
pr_err("[FACTORY] %s: get_accel_cal_data fail\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n", 0, 0, 0, 0);
}
}
static ssize_t accel_highg_calibration_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
pdata->dev_data = data;
if (sysfs_streq(buf, "0")) {
mutex_lock(&data->accel_factory_mutex);
memset(pdata->avg_data, 0, sizeof(pdata->avg_data));
set_accel_highg_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
} else {
pdata->is_complete_cal = false;
queue_work(pdata->accel_wq, &pdata->work_accel);
while (pdata->is_complete_cal == false) {
pr_info("[FACTORY] %s: In factory cal\n", __func__);
msleep(20);
}
mutex_lock(&data->accel_factory_mutex);
set_accel_highg_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
}
return size;
}
static void accel_highg_work_func(struct work_struct *work)
{
struct accel_highg_data *data = container_of((struct work_struct *)work,
struct accel_highg_data, work_accel);
int i;
mutex_lock(&data->dev_data->accel_factory_mutex);
memset(pdata->avg_data, 0, sizeof(pdata->avg_data));
adsp_unicast(pdata->avg_data, sizeof(pdata->avg_data),
MSG_ACCEL_HIGHG, 0, MSG_TYPE_SET_CAL_DATA);
msleep(30); /* for init of bias */
for (i = 0; i < ACCEL_FACTORY_CAL_CNT; i++) {
msleep(20);
get_accel_highg_raw_data(pdata->raw_data);
pdata->avg_data[0] += pdata->raw_data[0];
pdata->avg_data[1] += pdata->raw_data[1];
pdata->avg_data[2] += pdata->raw_data[2];
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
pdata->raw_data[0], pdata->raw_data[1],
pdata->raw_data[2]);
}
for (i = 0; i < ACCEL_RAW_DATA_CNT; i++) {
pdata->avg_data[i] /= ACCEL_FACTORY_CAL_CNT;
pr_info("[FACTORY] %s: avg : %d\n",
__func__, pdata->avg_data[i]);
}
if (pdata->avg_data[2] > 0)
pdata->avg_data[2] -= MAX_ACCEL_1G;
else if (pdata->avg_data[2] < 0)
pdata->avg_data[2] += MAX_ACCEL_1G;
mutex_unlock(&data->dev_data->accel_factory_mutex);
pdata->is_complete_cal = true;
}
void accel_highg_cal_work_func(struct work_struct *work)
{
struct adsp_data *data = container_of((struct delayed_work *)work,
struct adsp_data, accel_highg_cal_work);
int ret = 0;
mutex_lock(&data->accel_factory_mutex);
ret = get_accel_highg_cal_data(data, pdata->avg_data);
mutex_unlock(&data->accel_factory_mutex);
if (ret > 0) {
pr_info("[FACTORY] %s: ret(%d) %d, %d, %d\n", __func__, ret,
pdata->avg_data[0],
pdata->avg_data[1],
pdata->avg_data[2]);
mutex_lock(&data->accel_factory_mutex);
set_accel_highg_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
} else {
pr_err("[FACTORY] %s: get_accel_cal_data fail (%d)\n",
__func__, ret);
}
}
static ssize_t accel_highg_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int retry = 0;
#if IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_REF_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#endif
pdata->st_complete = false;
RETRY_ACCEL_SELFTEST:
adsp_unicast(NULL, 0, MSG_ACCEL_HIGHG, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_ACCEL_HIGHG) &&
cnt++ < TIMEOUT_CNT)
msleep(26);
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_ACCEL_HIGHG);
#if IS_ENABLED(CONFIG_SEC_DEBUG) && defined(CONFIG_SEC_FACTORY)
if(sec_debug_is_enabled())
BUG_ON(cnt >= TIMEOUT_CNT);
#else
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
data->msg_buf[MSG_ACCEL_HIGHG][1] = -1;
}
#endif
pr_info("[FACTORY] %s : init = %d, result = %d, XYZ = %d, %d, %d, nXYZ = %d, %d, %d\n",
__func__, data->msg_buf[MSG_ACCEL_HIGHG][0],
data->msg_buf[MSG_ACCEL_HIGHG][1], data->msg_buf[MSG_ACCEL_HIGHG][2],
data->msg_buf[MSG_ACCEL_HIGHG][3], data->msg_buf[MSG_ACCEL_HIGHG][4],
data->msg_buf[MSG_ACCEL_HIGHG][5], data->msg_buf[MSG_ACCEL_HIGHG][6],
data->msg_buf[MSG_ACCEL_HIGHG][7]);
if (data->msg_buf[MSG_ACCEL_HIGHG][1] == 1) {
pr_info("[FACTORY] %s : Pass - result = %d, retry = %d\n",
__func__, data->msg_buf[MSG_ACCEL_HIGHG][1], retry);
} else {
data->msg_buf[MSG_ACCEL_HIGHG][1] = -5;
pr_err("[FACTORY] %s : Fail - result = %d, retry = %d\n",
__func__, data->msg_buf[MSG_ACCEL_HIGHG][1], retry);
if (retry < ACCEL_ST_TRY_CNT &&
data->msg_buf[MSG_ACCEL_HIGHG][2] == 0) {
retry++;
msleep(200);
cnt = 0;
pr_info("[FACTORY] %s: retry\n", __func__);
goto RETRY_ACCEL_SELFTEST;
}
}
pdata->st_complete = true;
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_ACCEL_HIGHG][1],
(int)abs(data->msg_buf[MSG_ACCEL_HIGHG][2]),
(int)abs(data->msg_buf[MSG_ACCEL_HIGHG][3]),
(int)abs(data->msg_buf[MSG_ACCEL_HIGHG][4]),
(int)abs(data->msg_buf[MSG_ACCEL_HIGHG][5]),
(int)abs(data->msg_buf[MSG_ACCEL_HIGHG][6]),
(int)abs(data->msg_buf[MSG_ACCEL_HIGHG][7]));
}
static ssize_t accel_highg_raw_data_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t raw_data[ACCEL_RAW_DATA_CNT] = {0, };
static int32_t prev_raw_data[ACCEL_RAW_DATA_CNT] = {0, };
int ret = 0;
#ifdef CONFIG_SEC_FACTORY
static int same_cnt = 0;
#endif
if (pdata->st_complete == false) {
pr_info("[FACTORY] %s: selftest is running\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
raw_data[0], raw_data[1], raw_data[2]);
}
mutex_lock(&data->accel_factory_mutex);
ret = get_accel_highg_raw_data(raw_data);
mutex_unlock(&data->accel_factory_mutex);
#ifdef CONFIG_SEC_FACTORY
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
raw_data[0], raw_data[1], raw_data[2]);
if (prev_raw_data[0] == raw_data[0] &&
prev_raw_data[1] == raw_data[1] &&
prev_raw_data[2] == raw_data[2]) {
same_cnt++;
pr_info("[FACTORY] %s: same_cnt %d\n", __func__, same_cnt);
#if IS_ENABLED(CONFIG_SEC_DEBUG)
if(sec_debug_is_enabled())
BUG_ON(same_cnt >= 20);
#endif
} else
same_cnt = 0;
#endif
if (!ret) {
memcpy(prev_raw_data, raw_data, sizeof(int32_t) * 3);
} else if (!pdata->lpf_onoff) {
pr_err("[FACTORY] %s: using prev data!!!\n", __func__);
memcpy(raw_data, prev_raw_data, sizeof(int32_t) * 3);
} else {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
}
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
raw_data[0], raw_data[1], raw_data[2]);
}
static DEVICE_ATTR(name, 0444, accel_highg_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, accel_highg_vendor_show, NULL);
static DEVICE_ATTR(type, 0444, sensor_type_show, NULL);
static DEVICE_ATTR(calibration, 0664,
accel_highg_calibration_show, accel_highg_calibration_store);
static DEVICE_ATTR(selftest, 0440,
accel_highg_selftest_show, NULL);
static DEVICE_ATTR(raw_data, 0444, accel_highg_raw_data_show, NULL);
static struct device_attribute *acc_attrs[] = {
&dev_attr_name,
&dev_attr_vendor,
&dev_attr_type,
&dev_attr_calibration,
&dev_attr_selftest,
&dev_attr_raw_data,
NULL,
};
void accel_highg_factory_init_work(struct adsp_data *data)
{
schedule_delayed_work(&data->accel_highg_cal_work, msecs_to_jiffies(8000));
}
EXPORT_SYMBOL(accel_highg_factory_init_work);
int __init accel_highg_factory_init(void)
{
adsp_factory_register(MSG_ACCEL_HIGHG, acc_attrs);
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
pdata->accel_wq = create_singlethread_workqueue("accel_high_wq");
INIT_WORK(&pdata->work_accel, accel_highg_work_func);
pdata->lpf_onoff = true;
pdata->st_complete = true;
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit accel_highg_factory_exit(void)
{
adsp_factory_unregister(MSG_ACCEL_HIGHG);
pr_info("[FACTORY] %s\n", __func__);
}

381
drivers/adsp_factory/adsp.h Executable file
View File

@@ -0,0 +1,381 @@
/*
* Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __ADSP_SENSOR_H__
#define __ADSP_SENSOR_H__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
//#include <linux/sensors.h>
#include <linux/adsp/adsp_ft_common.h>
#define TIMEOUT_CNT 200
#define TIMEOUT_DHR_CNT 50
#define PATH_LEN 50
#define FILE_BUF_LEN 110
#define ID_INDEX_NUMS 2
#define RETRY_MAX 3
#define VERSION_FILE_NAME_LEN 20
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
/* To avoid wrong folder close */
#define LSM6DSO_SELFTEST_TRUE 3
#define LSM6DSO_SELFTEST_FALSE 4
#endif
#define AUTO_CAL_X_START 1
#define AUTO_CAL_Y_START 20
#define AUTO_CAL_Z_START 39
#define UNKNOWN_INDEX 0
#define DEVICE_INFO_LENGTH 10
#if IS_ENABLED(CONFIG_SEC_KUNIT)
#include <kunit/mock.h>
#define __mockable __weak
#define __visible_for_testing
#else
#define __mockable
#define __visible_for_testing static
#endif
enum {
D_FACTOR,
R_COEF,
G_COEF,
B_COEF,
C_COEF,
CT_COEF,
CT_OFFSET,
THD_HIGH,
THD_LOW,
IRIS_PROX_THD,
SUM_CRC,
EFS_SAVE_NUMS,
};
enum {
ID_UTYPE,
ID_BLACK,
ID_WHITE,
ID_GOLD,
ID_SILVER,
ID_GREEN,
ID_BLUE,
ID_PINKGOLD,
ID_MAX,
};
#if IS_ENABLED(CONFIG_SUPPORT_SENSOR_FOLD)
struct sensor_fold_state {
int64_t ts;
int state; // 0: unfold, 1: close(fold)
};
#endif
/* Main struct containing all the data */
struct adsp_data {
struct device *adsp;
struct device *sensor_device[MSG_SENSOR_MAX];
struct device_attribute **sensor_attr[MSG_SENSOR_MAX];
struct sock *adsp_skt;
int32_t *msg_buf[MSG_SENSOR_MAX];
unsigned int ready_flag[MSG_TYPE_MAX];
bool sysfs_created[MSG_SENSOR_MAX];
struct mutex prox_factory_mutex;
struct mutex light_factory_mutex;
struct mutex accel_factory_mutex;
struct mutex remove_sysfs_mutex;
struct mutex sensors_dump_mutex;
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_OPTIC)
struct mutex vir_optic_factory_mutex;
#endif
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_FACTORY)
struct mutex flip_cover_factory_mutex;
#endif
#if IS_ENABLED(CONFIG_BACKTAP_FACTORY)
struct mutex backtap_factory_mutex;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
struct mutex digital_hall_mutex;
#endif
#if IS_ENABLED(CONFIG_HALL_NOTIFIER)
struct notifier_block adsp_nb;
#endif
#ifdef CONFIG_VBUS_NOTIFIER
struct notifier_block vbus_nb;
#endif
int32_t fac_fstate;
#if IS_ENABLED(CONFIG_LIGHT_FACTORY)
struct delayed_work light_init_work;
bool light_factory_is_ready;
char light_device_vendor[2][10];
char light_device_name[2][10];
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_CALIBRATION)
struct delayed_work light_cal_work;
int32_t light_cal_result;
int32_t light_cal1;
int32_t light_cal2;
int32_t copr_w;
int32_t sub_light_cal_result;
int32_t sub_light_cal1;
int32_t sub_light_cal2;
int32_t sub_copr_w;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DDI_COPR_FOR_LIGHT_SENSOR)
struct delayed_work light_copr_debug_work;
int light_copr_debug_count;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AP_COPR_FOR_LIGHT_SENSOR)
struct delayed_work light_copr_work;
int32_t copr_data[15];
bool has_pending_copr_data;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_BRIGHTNESS_NOTIFY_FOR_LIGHT_SENSOR)
struct work_struct light_br_work;
#endif
#if IS_ENABLED(CONFIG_LIGHT_FACTORY)
int32_t light_temp_reg;
int32_t brightness_info[6];
int32_t pre_bl_level[2];
int32_t pre_panel_state[2];
int32_t pre_screen_mode[2];
int32_t pre_panel_idx;
int32_t pre_display_idx;
int32_t light_debug_info_cmd;
int32_t hyst[4];
int32_t brightness_resolution[2];
#endif
#if IS_ENABLED(CONFIG_SUPPORT_PROX_CALIBRATION)
int32_t prox_cal;
int32_t prox_sub_cal;
#endif
struct delayed_work accel_cal_work;
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
struct delayed_work sub_accel_cal_work;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
struct delayed_work sub2_accel_cal_work;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG) || defined(CONFIG_SUPPORT_ACCEL_HIGHG)
struct delayed_work accel_highg_cal_work;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_SEAMLESS)
struct delayed_work light_seamless_work;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973)
struct delayed_work lsm6dso_selftest_stop_work;
struct delayed_work dhall_cal_work;
#elif IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
struct delayed_work lsm6dso_selftest_stop_work;
#endif
struct delayed_work pressure_cal_work;
char press_device_vendor[DEVICE_INFO_LENGTH];
char press_device_name[DEVICE_INFO_LENGTH];
#if IS_ENABLED(CONFIG_SUPPORT_SENSOR_FOLD)
struct sensor_fold_state fold_state;
#endif
uint32_t support_algo;
bool restrict_mode;
int turn_over_crash;
bool send_probe_fail_msg;
bool fssr_ignore;
bool fssr_dump;
};
struct device_id_t {
uint8_t device_id;
char device_vendor[DEVICE_INFO_LENGTH];
char device_name[DEVICE_INFO_LENGTH];
};
#ifdef CONFIG_SEC_FACTORY
int get_mag_raw_data(int32_t *raw_data);
#endif
int get_accel_raw_data(int32_t *raw_data);
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
int get_sub_accel_raw_data(int32_t *raw_data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
int get_sub2_accel_raw_data(int32_t *raw_data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG)
int get_accel_highg_raw_data(int32_t *raw_data);
#endif
int adsp_get_sensor_data(int sensor_type);
int adsp_factory_register(unsigned int type,
struct device_attribute *attributes[]);
int adsp_factory_unregister(unsigned int type);
#if IS_ENABLED(CONFIG_SUPPORT_DEVICE_MODE) || defined(CONFIG_VBUS_NOTIFIER) || IS_ENABLED(CONFIG_HALL_NOTIFIER)
struct adsp_data* adsp_ssc_core_register(unsigned int type,
struct device_attribute *attributes[]);
struct adsp_data* adsp_ssc_core_unregister(unsigned int type);
#endif
int adsp_unicast(void *param, int param_size, u16 sensor_type,
u32 portid, u16 msg_type);
int sensors_register(struct device **dev, void *drvdata,
struct device_attribute *attributes[], char *name);
void sensors_unregister(struct device *dev,
struct device_attribute *attributes[]);
int core_factory_init(void);
void core_factory_exit(void);
#if IS_ENABLED(CONFIG_LSM6DSO_FACTORY)
int lsm6dso_accel_factory_init(void);
void lsm6dso_accel_factory_exit(void);
int lsm6dso_gyro_factory_init(void);
void lsm6dso_gyro_factory_exit(void);
#endif
#if IS_ENABLED(CONFIG_LSM6DSL_FACTORY)
int lsm6dsl_accel_factory_init(void);
void lsm6dsl_accel_factory_exit(void);
int lsm6dsl_gyro_factory_init(void);
void lsm6dsl_gyro_factory_exit(void);
#endif
void accel_factory_init_work(struct adsp_data *data);
void accel_cal_work_func(struct work_struct *work);
#if IS_ENABLED(CONFIG_AK09918_FACTORY)
int ak09918_factory_init(void);
void ak09918_factory_exit(void);
#endif
#if IS_ENABLED(CONFIG_LPS22HH_FACTORY)
int lps22hh_pressure_factory_init(void);
void lps22hh_pressure_factory_exit(void);
#elif IS_ENABLED(CONFIG_PRESSURE_FACTORY)
int pressure_factory_init(void);
void pressure_factory_exit(void);
#endif
#if IS_ENABLED(CONFIG_LIGHT_FACTORY)
int light_factory_init(void);
void light_factory_exit(void);
void light_init_work(struct adsp_data *data);
void light_init_work_func(struct work_struct *work);
#endif
#if IS_ENABLED(CONFIG_PROX_FACTORY)
int prox_factory_init(void);
void prox_factory_exit(void);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
int lsm6dso_sub_accel_factory_init(void);
void lsm6dso_sub_accel_factory_exit(void);
int lsm6dso_sub_gyro_factory_init(void);
void lsm6dso_sub_gyro_factory_exit(void);
void sub_accel_factory_init_work(struct adsp_data *data);
void sub_accel_cal_work_func(struct work_struct *work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
int sub2_accel_factory_init(void);
void sub2_accel_factory_exit(void);
int sub2_gyro_factory_init(void);
void sub2_gyro_factory_exit(void);
void sub2_accel_factory_init_work(struct adsp_data *data);
void sub2_accel_cal_work_func(struct work_struct *work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG)
int accel_highg_factory_init(void);
void accel_highg_factory_exit(void);
void accel_highg_factory_init_work(struct adsp_data *data);
void accel_highg_cal_work_func(struct work_struct *work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_MAG)
int mag_sub_factory_init(void);
void mag_sub_factory_exit(void);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
int ak09970_factory_init(void);
void ak09970_factory_exit(void);
void lsm6dso_selftest_stop_work_func(struct work_struct *work);
bool lf_stream_read_cal_data(int axis, int *cal_data);
bool lf_stream_read_auto_cal_x_data(int *cal_data);
bool lf_stream_read_auto_cal_y_data(int *cal_data);
bool lf_stream_read_auto_cal_z_data(int *cal_data);
int lf_stream_write_auto_cal_data(bool first_booting);
int lf_stream_write_cal_data(int axis, bool first_booting);
void lf_stream_set_mode_flag(bool is_first_boot, int *flag, umode_t *mode);
bool lf_stream_get_info_from_axis(int axis, int *index, int *nums);
int lf_stream_get_index_cal_data(int axis, int index);
bool lf_stream_get_cal_path(int axis, char *path);
bool lf_stream_get_data_buf(int axis, int32_t *data_buf);
#elif IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
void lsm6dso_selftest_stop_work_func(struct work_struct *work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DEVICE_MODE)
void sns_device_mode_init_work(void);
void sns_flip_init_work(void);
#endif
#ifdef CONFIG_VBUS_NOTIFIER
void sns_vbus_init_work(void);
#endif
#if IS_ENABLED(CONFIG_HALL_NOTIFIER)
void sns_mpp_cover_init_work(void);
#endif
#if IS_ENABLED(CONFIG_BACKTAP_FACTORY)
int backtap_factory_init(void);
void backtap_factory_exit(void);
#endif
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_FACTORY)
int flip_cover_detector_factory_init(void);
void flip_cover_detector_factory_exit(void);
void flip_cover_detector_cal_init_work(void);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_CALIBRATION)
void light_cal_init_work(struct adsp_data *data);
void light_cal_read_work_func(struct work_struct *work);
#endif /* CONFIG_SUPPORT_LIGHT_CALIBRATION */
#if IS_ENABLED(CONFIG_SUPPORT_DDI_COPR_FOR_LIGHT_SENSOR)
void light_copr_debug_work_func(struct work_struct *work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AP_COPR_FOR_LIGHT_SENSOR)
void light_copr_work_func(struct work_struct *work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_PROX_CALIBRATION)
void prox_cal_init_work(struct adsp_data *data);
void prox_send_cal_data(struct adsp_data *data, uint16_t prox_idx, bool fac_cal);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_PROX_POWER_ON_CAL)
void prox_factory_init_work(void);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
void digital_hall_factory_auto_cal_init_work(struct adsp_data *data);
int get_hall_angle_data(int32_t *raw_data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_SEAMLESS)
void light_seamless_work_func(struct work_struct *work);
void light_seamless_init_work(struct adsp_data *data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_OPTIC)
int get_light_sidx(struct adsp_data *data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_BRIGHTNESS_NOTIFY_FOR_LIGHT_SENSOR) && \
IS_ENABLED(CONFIG_SEC_PANEL_NOTIFIER_V2)
void light_brightness_work_func(struct work_struct *work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
void dhall_cal_work_func(struct work_struct *work);
#endif
void pressure_factory_init_work(struct adsp_data *data);
void pressure_cal_work_func(struct work_struct *work);
struct adsp_data* adsp_get_struct_data(void);
bool sns_check_ignore_crash(void);
#endif /* __ADSP_SENSOR_H__ */

View File

@@ -0,0 +1,796 @@
/*
* 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/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/sec_class.h>
#include "adsp.h"
static u8 msg_size[MSG_SENSOR_MAX] = {
MSG_ACCEL_MAX,
MSG_GYRO_MAX,
MSG_MAG_MAX,
MSG_PRESSURE_MAX,
MSG_LIGHT_MAX,
MSG_PROX_MAX, //5
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_OPTIC)
MSG_LIGHT_MAX,
MSG_PROX_MAX,
#endif
#if IS_ENABLED(CONFIG_SUPPORT_FLICKER)
MSG_FLICKER_MAX,
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
MSG_ACCEL_MAX,
MSG_GYRO_MAX,
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
MSG_ACCEL_MAX,
MSG_GYRO_MAX,
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG)
MSG_ACCEL_MAX,
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_MAG) || defined(CONFIG_SUPPORT_DUAL_MAG)
MSG_MAG_MAX,
#endif
MSG_TYPE_SIZE_ZERO, /* PHYSICAL_SENSOR_SYSFS */
MSG_GYRO_TEMP_MAX,
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
MSG_GYRO_TEMP_MAX,
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
MSG_GYRO_TEMP_MAX,
#endif
MSG_PRESSURE_TEMP_MAX,
MSG_TYPE_SIZE_ZERO, /* MSG_MAG_CAL */
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_MAG) || defined(CONFIG_SUPPORT_DUAL_MAG)
MSG_TYPE_SIZE_ZERO,
#endif
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_FACTORY)
MSG_FLIP_COVER_DETECTOR_MAX,
#endif
#if IS_ENABLED(CONFIG_SUPPORT_VIRTUAL_OPTIC)
MSG_VOPTIC_MAX,
#endif
MSG_REG_SNS_MAX, /* MSG_REG_SNS */
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
MSG_DIGITAL_HALL_MAX,
MSG_DIGITAL_HALL_ANGLE_MAX,
#if ENABLE_LF_STREAM
MSG_DIGITAL_HALL_ANGLE_MAX,
#endif
#elif IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
MSG_REF_ANGLE_MAX,
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_DDI_COPR_FOR_LIGHT_SENSOR)
MSG_DDI_MAX,
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_MAIN2_SENSOR) || defined(CONFIG_SUPPORT_LIGHT_MAIN2_SENSOR)
MSG_TYPE_SIZE_ZERO,
#endif
#if IS_ENABLED(CONFIG_BACKTAP_FACTORY) || defined(CONFIG_BACKTAP_FACTORY)
MSG_BACKTAP_MAX,
#endif
MSG_TYPE_SIZE_ZERO,
MSG_COMMON_INFO_MAX,
};
/* The netlink socket */
struct adsp_data *data;
DEFINE_MUTEX(factory_mutex);
struct adsp_data* adsp_get_struct_data(void)
{
return data;
}
/* Function used to send message to the user space */
int adsp_unicast(void *param, int param_size, u16 sensor_type,
u32 portid, u16 msg_type)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
void *msg;
int ret = -1;
u16 nlmsg_type = (sensor_type << 8) | msg_type;
if (data->restrict_mode && msg_type == MSG_TYPE_SET_ACCEL_MOTOR) {
pr_err("[FACTORY] %s - restrict_mode\n", __func__);
return ret;
}
data->ready_flag[msg_type] &= ~(1 << sensor_type);
skb = nlmsg_new(param_size, GFP_KERNEL);
if (!skb) {
pr_err("[FACTORY] %s - nlmsg_new fail\n", __func__);
return -ENOMEM;
}
nlh = nlmsg_put(skb, portid, 0, nlmsg_type, param_size, 0);
if (nlh == NULL) {
pr_err("[FACTORY] %s - nlmsg_put fail\n", __func__);
nlmsg_free(skb);
return -EMSGSIZE;
}
msg = nlmsg_data(nlh);
memcpy(msg, param, param_size);
NETLINK_CB(skb).dst_group = 0;
ret = nlmsg_unicast(data->adsp_skt, skb, PID);
if (ret != 0)
pr_err("[FACTORY] %s - ret = %d\n", __func__, ret);
return ret;
}
EXPORT_SYMBOL(adsp_unicast);
#if IS_ENABLED(CONFIG_SUPPORT_DEVICE_MODE) || defined(CONFIG_VBUS_NOTIFIER) || IS_ENABLED(CONFIG_HALL_NOTIFIER)
struct adsp_data* adsp_ssc_core_register(unsigned int type,
struct device_attribute *attributes[])
{
int ret = 0;
data->sensor_attr[type] = attributes;
ret = sensors_register(&data->sensor_device[type], data,
data->sensor_attr[type], "ssc_core");
data->sysfs_created[type] = true;
pr_info("[FACTORY] %s - type:%u ptr:%pK\n",
__func__, type, data->sensor_device[type]);
return data;
}
struct adsp_data* adsp_ssc_core_unregister(unsigned int type)
{
pr_info("[FACTORY] %s - type:%u ptr:%pK\n",
__func__, type, data->sensor_device[type]);
if (data->sysfs_created[type]) {
sensors_unregister(data->sensor_device[type],
data->sensor_attr[type]);
data->sysfs_created[type] = false;
} else {
pr_info("[FACTORY] %s: skip type %u\n", __func__, type);
}
return data;
}
#endif
int adsp_factory_register(unsigned int type,
struct device_attribute *attributes[])
{
int ret = 0;
char *dev_name;
switch (type) {
case MSG_ACCEL:
dev_name = "accelerometer_sensor";
break;
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG)
case MSG_ACCEL_HIGHG:
dev_name = "accelerometer_sensor_high_g";
break;
#endif
case MSG_GYRO:
dev_name = "gyro_sensor";
break;
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
case MSG_ACCEL_SUB:
dev_name = "sub_accelerometer_sensor";
break;
case MSG_GYRO_SUB:
dev_name = "sub_gyro_sensor";
break;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
case MSG_ACCEL_SUB2:
dev_name = "sub2_accelerometer_sensor";
break;
case MSG_GYRO_SUB2:
dev_name = "sub2_gyro_sensor";
break;
#endif
case MSG_MAG:
dev_name = "magnetic_sensor";
break;
case MSG_PRESSURE:
dev_name = "barometer_sensor";
break;
case MSG_LIGHT:
dev_name = "light_sensor";
break;
case MSG_PROX:
dev_name = "proximity_sensor";
break;
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_OPTIC)
case MSG_LIGHT_SUB:
dev_name = "sub_light_sensor";
break;
case MSG_PROX_SUB:
dev_name = "sub_proximity_sensor";
break;
#endif
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_FACTORY)
case MSG_FLIP_COVER_DETECTOR:
dev_name = "flip_cover_detector_sensor";
break;
#endif
#if IS_ENABLED(CONFIG_BACKTAP_FACTORY)
case MSG_BACKTAP:
dev_name = "backtap_sensor";
break;
#endif
case MSG_SSC_CORE:
dev_name = "ssc_core";
break;
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
case MSG_DIGITAL_HALL:
dev_name = "digital_hall";
break;
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_MAG) || defined(CONFIG_SUPPORT_DUAL_MAG)
case MSG_MAG_SUB:
dev_name = "sub_magnetic_sensor";
break;
#endif
default:
dev_name = "unknown_sensor";
break;
}
data->sensor_attr[type] = attributes;
ret = sensors_register(&data->sensor_device[type], data,
data->sensor_attr[type], dev_name);
data->sysfs_created[type] = true;
pr_info("[FACTORY] %s - type:%u ptr:%pK\n",
__func__, type, data->sensor_device[type]);
return ret;
}
EXPORT_SYMBOL(adsp_factory_register);
int adsp_factory_unregister(unsigned int type)
{
pr_info("[FACTORY] %s - type:%u ptr:%pK\n",
__func__, type, data->sensor_device[type]);
if (data->sysfs_created[type]) {
sensors_unregister(data->sensor_device[type],
data->sensor_attr[type]);
data->sysfs_created[type] = false;
} else {
pr_info("[FACTORY] %s: skip type %u\n", __func__, type);
}
return 0;
}
EXPORT_SYMBOL(adsp_factory_unregister);
int get_accel_raw_data(int32_t *raw_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_ACCEL, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_ACCEL) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_ACCEL);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return -1;
}
memcpy(raw_data, &data->msg_buf[MSG_ACCEL][0], sizeof(int32_t) * 3);
return 0;
}
EXPORT_SYMBOL(get_accel_raw_data);
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
int get_sub_accel_raw_data(int32_t *raw_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_ACCEL_SUB, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_ACCEL_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_ACCEL_SUB);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return -1;
}
memcpy(raw_data, &data->msg_buf[MSG_ACCEL_SUB][0], sizeof(int32_t) * 3);
return 0;
}
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG)
int get_accel_highg_raw_data(int32_t *raw_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_ACCEL_HIGHG, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_ACCEL_HIGHG) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_ACCEL_HIGHG);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return -1;
}
memcpy(raw_data, &data->msg_buf[MSG_ACCEL_HIGHG][0], sizeof(int32_t) * 3);
return 0;
}
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
int get_sub2_accel_raw_data(int32_t *raw_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_ACCEL_SUB2, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_ACCEL_SUB2) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_ACCEL_SUB2);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return -1;
}
memcpy(raw_data, &data->msg_buf[MSG_ACCEL_SUB2][0], sizeof(int32_t) * 3);
return 0;
}
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
void lsm6dso_selftest_stop_work_func(struct work_struct *work)
{
int msg_buf = LSM6DSO_SELFTEST_FALSE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_DIGITAL_HALL_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
}
#elif IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
void lsm6dso_selftest_stop_work_func(struct work_struct *work)
{
int msg_buf = LSM6DSO_SELFTEST_FALSE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_REF_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
}
#endif
#ifdef CONFIG_SEC_FACTORY
int get_mag_raw_data(int32_t *raw_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_MAG, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_MAG) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_MAG);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return -1;
}
memcpy(raw_data, &data->msg_buf[MSG_MAG][0], sizeof(int32_t) * 3);
return 0;
}
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
int get_hall_angle_data(int32_t *raw_data)
{
uint8_t cnt = 0;
mutex_lock(&data->digital_hall_mutex);
adsp_unicast(NULL, 0, MSG_DIGITAL_HALL_ANGLE, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_DIGITAL_HALL_ANGLE) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_DIGITAL_HALL_ANGLE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return -1;
}
pr_info("[FACTORY] %s - st %d/%d, akm %d/%d, lf %d/%d, hall %d/%d/%d(uT)\n",
__func__, data->msg_buf[MSG_DIGITAL_HALL_ANGLE][0],
data->msg_buf[MSG_DIGITAL_HALL_ANGLE][1],
data->msg_buf[MSG_DIGITAL_HALL_ANGLE][2],
data->msg_buf[MSG_DIGITAL_HALL_ANGLE][3],
data->msg_buf[MSG_DIGITAL_HALL_ANGLE][4],
data->msg_buf[MSG_DIGITAL_HALL_ANGLE][5],
data->msg_buf[MSG_DIGITAL_HALL_ANGLE][6],
data->msg_buf[MSG_DIGITAL_HALL_ANGLE][7],
data->msg_buf[MSG_DIGITAL_HALL_ANGLE][8]);
*raw_data = data->msg_buf[MSG_DIGITAL_HALL_ANGLE][2];
mutex_unlock(&data->digital_hall_mutex);
return 0;
}
#endif
static int process_received_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
u16 sensor_type = nlh->nlmsg_type >> 8;
u16 msg_type = nlh->nlmsg_type & 0xff;
/* check the boundary to prevent memory attack */
if (msg_type >= MSG_TYPE_MAX || sensor_type >= MSG_SENSOR_MAX ||
nlh->nlmsg_len - (int32_t)sizeof(struct nlmsghdr) >
sizeof(int32_t) * msg_size[sensor_type]) {
pr_err("[FACTORY] %s %d, %d, %d\n", __func__, msg_type, sensor_type, nlh->nlmsg_len);
return 0;
}
if (sensor_type == MSG_FACTORY_INIT_CMD) {
pr_info("[FACTORY] %s - MSG_FACTORY_INIT_CMD\n", __func__);
accel_factory_init_work(data);
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
sub_accel_factory_init_work(data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG)
accel_highg_factory_init_work(data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DEVICE_MODE)
sns_device_mode_init_work();
sns_flip_init_work();
#endif
#if IS_ENABLED(CONFIG_LIGHT_FACTORY)
light_init_work(data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_CALIBRATION)
light_cal_init_work(data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_PROX_CALIBRATION)
prox_cal_init_work(data);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_PROX_POWER_ON_CAL)
prox_factory_init_work();
#endif
#ifdef CONFIG_VBUS_NOTIFIER
sns_vbus_init_work();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
digital_hall_factory_auto_cal_init_work(data);
#endif
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_FACTORY)
flip_cover_detector_cal_init_work();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_SEAMLESS)
light_seamless_init_work(data);
#endif
#if IS_ENABLED(CONFIG_LPS22HH_FACTORY) || IS_ENABLED(CONFIG_PRESSURE_FACTORY)
pressure_factory_init_work(data);
#endif
#if IS_ENABLED(CONFIG_HALL_NOTIFIER)
sns_mpp_cover_init_work();
#endif
return 0;
}
memcpy(data->msg_buf[sensor_type],
(int32_t *)NLMSG_DATA(nlh),
nlh->nlmsg_len - (int32_t)sizeof(struct nlmsghdr));
data->ready_flag[msg_type] |= 1 << sensor_type;
return 0;
}
static void factory_receive_skb(struct sk_buff *skb)
{
struct netlink_ext_ack extack = {};
struct nlmsghdr *nlh;
int len;
int err;
nlh = (struct nlmsghdr *)skb->data;
len = skb->len;
while (NLMSG_OK(nlh, len)) {
err = process_received_msg(skb, nlh);
/* if err or if this message says it wants a response */
if (err || (nlh->nlmsg_flags & NLM_F_ACK))
netlink_ack(skb, nlh, err, &extack);
nlh = NLMSG_NEXT(nlh, len);
}
}
/* Receive messages from netlink socket. */
static void factory_test_result_receive(struct sk_buff *skb)
{
mutex_lock(&factory_mutex);
factory_receive_skb(skb);
mutex_unlock(&factory_mutex);
}
struct netlink_kernel_cfg netlink_cfg = {
.input = factory_test_result_receive,
};
static int __init factory_adsp_init(void)
{
int i;
pr_info("[FACTORY] %s\n", __func__);
data = kzalloc(sizeof(*data), GFP_KERNEL);
for (i = 0; i < MSG_SENSOR_MAX; i++) {
if (msg_size[i] > 0)
data->msg_buf[i] = kzalloc(sizeof(int32_t) * msg_size[i],
GFP_KERNEL);
}
data->adsp_skt = netlink_kernel_create(&init_net,
NETLINK_ADSP_FAC, &netlink_cfg);
for (i = 0; i < MSG_SENSOR_MAX; i++)
data->sysfs_created[i] = false;
for (i = 0; i < MSG_TYPE_MAX; i++)
data->ready_flag[i] = 0;
data->restrict_mode = false;
data->turn_over_crash = 0;
data->fssr_ignore = false;
data->fssr_dump = false;
mutex_init(&data->accel_factory_mutex);
mutex_init(&data->prox_factory_mutex);
mutex_init(&data->light_factory_mutex);
mutex_init(&data->remove_sysfs_mutex);
mutex_init(&data->sensors_dump_mutex);
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_OPTIC)
mutex_init(&data->vir_optic_factory_mutex);
#endif
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_FACTORY)
mutex_init(&data->flip_cover_factory_mutex);
#endif
#if IS_ENABLED(CONFIG_BACKTAP_FACTORY)
mutex_init(&data->backtap_factory_mutex);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
mutex_init(&data->digital_hall_mutex);
INIT_DELAYED_WORK(&data->dhall_cal_work, dhall_cal_work_func);
#endif
#if IS_ENABLED(CONFIG_LIGHT_FACTORY)
INIT_DELAYED_WORK(&data->light_init_work, light_init_work_func);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_CALIBRATION)
INIT_DELAYED_WORK(&data->light_cal_work, light_cal_read_work_func);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DDI_COPR_FOR_LIGHT_SENSOR)
INIT_DELAYED_WORK(&data->light_copr_debug_work,
light_copr_debug_work_func);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AP_COPR_FOR_LIGHT_SENSOR)
INIT_DELAYED_WORK(&data->light_copr_work, light_copr_work_func);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_BRIGHTNESS_NOTIFY_FOR_LIGHT_SENSOR) && \
IS_ENABLED(CONFIG_SEC_PANEL_NOTIFIER_V2)
INIT_WORK(&data->light_br_work, light_brightness_work_func);
#endif
INIT_DELAYED_WORK(&data->accel_cal_work, accel_cal_work_func);
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
INIT_DELAYED_WORK(&data->sub_accel_cal_work, sub_accel_cal_work_func);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
INIT_DELAYED_WORK(&data->sub2_accel_cal_work, sub2_accel_cal_work_func);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG)
INIT_DELAYED_WORK(&data->accel_highg_cal_work, accel_highg_cal_work_func);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
INIT_DELAYED_WORK(&data->lsm6dso_selftest_stop_work, lsm6dso_selftest_stop_work_func);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_SEAMLESS)
INIT_DELAYED_WORK(&data->light_seamless_work, light_seamless_work_func);
#endif
#if IS_ENABLED(CONFIG_LPS22HH_FACTORY) || IS_ENABLED(CONFIG_PRESSURE_FACTORY)
INIT_DELAYED_WORK(&data->pressure_cal_work, pressure_cal_work_func);
#endif
core_factory_init();
#if IS_ENABLED(CONFIG_LSM6DSO_FACTORY)
lsm6dso_accel_factory_init();
lsm6dso_gyro_factory_init();
#endif
#if IS_ENABLED(CONFIG_LSM6DSL_FACTORY)
lsm6dsl_accel_factory_init();
lsm6dsl_gyro_factory_init();
#endif
#if IS_ENABLED(CONFIG_AK09918_FACTORY)
ak09918_factory_init();
#endif
#if IS_ENABLED(CONFIG_LPS22HH_FACTORY)
lps22hh_pressure_factory_init();
#elif IS_ENABLED(CONFIG_PRESSURE_FACTORY)
pressure_factory_init();
#endif
#if IS_ENABLED(CONFIG_BACKTAP_FACTORY)
backtap_factory_init();
#endif
#if IS_ENABLED(CONFIG_LIGHT_FACTORY)
light_factory_init();
#endif
#if IS_ENABLED(CONFIG_PROX_FACTORY)
prox_factory_init();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
lsm6dso_sub_accel_factory_init();
lsm6dso_sub_gyro_factory_init();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
sub2_accel_factory_init();
sub2_gyro_factory_init();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG)
accel_highg_factory_init();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
ak09970_factory_init();
#endif
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_FACTORY)
flip_cover_detector_factory_init();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_MAG)
mag_sub_factory_init();
#endif
pr_info("[FACTORY] %s: Timer Init\n", __func__);
return 0;
}
static void __exit factory_adsp_exit(void)
{
int i;
core_factory_exit();
#if IS_ENABLED(CONFIG_LSM6DSO_FACTORY)
lsm6dso_accel_factory_exit();
lsm6dso_gyro_factory_exit();
#endif
#if IS_ENABLED(CONFIG_LSM6DSL_FACTORY)
lsm6dsl_accel_factory_exit();
lsm6dsl_gyro_factory_exit();
#endif
#if IS_ENABLED(CONFIG_AK09918_FACTORY)
ak09918_factory_exit();
#endif
#if IS_ENABLED(CONFIG_LPS22HH_FACTORY)
lps22hh_pressure_factory_exit();
#elif IS_ENABLED(CONFIG_PRESSURE_FACTORY)
pressure_factory_exit();
#endif
#if IS_ENABLED(CONFIG_BACKTAP_FACTORY)
backtap_factory_exit();
#endif
#if IS_ENABLED(CONFIG_LIGHT_FACTORY)
cancel_delayed_work_sync(&data->light_init_work);
light_factory_exit();
#endif
#if IS_ENABLED(CONFIG_PROX_FACTORY)
prox_factory_exit();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
lsm6dso_sub_accel_factory_exit();
lsm6dso_sub_gyro_factory_exit();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
sub2_accel_factory_exit();
sub2_gyro_factory_exit();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG) || defined(CONFIG_SUPPORT_ACCEL_HIGHG)
accel_highg_factory_exit();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
ak09970_factory_exit();
#endif
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_FACTORY)
flip_cover_detector_factory_exit();
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_MAG)
mag_sub_factory_exit();
#endif
mutex_destroy(&data->accel_factory_mutex);
mutex_destroy(&data->prox_factory_mutex);
mutex_destroy(&data->light_factory_mutex);
mutex_destroy(&data->remove_sysfs_mutex);
mutex_destroy(&data->sensors_dump_mutex);
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_OPTIC)
mutex_destroy(&data->vir_optic_factory_mutex);
#endif
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_FACTORY)
mutex_destroy(&data->flip_cover_factory_mutex);
#endif
#if IS_ENABLED(CONFIG_BACKTAP_FACTORY)
mutex_destroy(&data->backtap_factory_mutex);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973)
mutex_destroy(&data->digital_hall_mutex);
cancel_delayed_work_sync(&data->dhall_cal_work);
cancel_delayed_work_sync(&data->lsm6dso_selftest_stop_work);
#elif IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
cancel_delayed_work_sync(&data->lsm6dso_selftest_stop_work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_CALIBRATION)
cancel_delayed_work_sync(&data->light_cal_work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_DDI_COPR_FOR_LIGHT_SENSOR)
cancel_delayed_work_sync(&data->light_copr_debug_work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AP_COPR_FOR_LIGHT_SENSOR)
cancel_delayed_work_sync(&data->light_copr_work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_BRIGHTNESS_NOTIFY_FOR_LIGHT_SENSOR)
cancel_work_sync(&data->light_br_work);
#endif
cancel_delayed_work_sync(&data->accel_cal_work);
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_6AXIS)
cancel_delayed_work_sync(&data->sub_accel_cal_work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_TRIPLE_6AXIS)
cancel_delayed_work_sync(&data->sub2_accel_cal_work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_ACCEL_HIGHG) || defined(CONFIG_SUPPORT_ACCEL_HIGHG)
cancel_delayed_work_sync(&data->accel_highg_cal_work);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_LIGHT_SEAMLESS)
cancel_delayed_work_sync(&data->light_seamless_work);
#endif
cancel_delayed_work_sync(&data->pressure_cal_work);
for (i = 0; i < MSG_SENSOR_MAX; i++)
kfree(data->msg_buf[i]);
pr_info("[FACTORY] %s\n", __func__);
}
module_init(factory_adsp_init);
module_exit(factory_adsp_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Support for factory test sensors (adsp)");

View File

@@ -0,0 +1,256 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define VENDOR "AKM"
#define CHIP_ID "AK09918"
#define MAG_ST_TRY_CNT 3
#define ABS(x) (((x)>0)?(x):-(x))
#define AKM_ST_FAIL (-1)
static ssize_t mag_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t mag_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t mag_check_cntl(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "OK\n");
}
static ssize_t mag_check_registers(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
static ssize_t mag_get_asa(struct device *dev,
struct device_attribute *attr, char *buf)
{
/* Do not have Fuserom */
return snprintf(buf, PAGE_SIZE, "%u,%u,%u\n", 128, 128, 128);
}
static ssize_t mag_get_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
/* Do not have Fuserom */
return snprintf(buf, PAGE_SIZE, "%s\n", "OK");
}
static ssize_t mag_raw_data_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_MAG, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_MAG) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_MAG);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "0,0,0\n");
}
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
data->msg_buf[MSG_MAG][0],
data->msg_buf[MSG_MAG][1],
data->msg_buf[MSG_MAG][2]);
}
static ssize_t mag_raw_data_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
adsp_unicast(NULL, 0, MSG_MAG_CAL, 0, MSG_TYPE_FACTORY_ENABLE);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL, 0, MSG_TYPE_SET_CAL_DATA);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL, 0, MSG_TYPE_FACTORY_DISABLE);
return size;
}
static ssize_t mag_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int retry = 0, i;
int abs_adc_sum = 0, abs_adc_x = 0, abs_adc_y = 0, abs_adc_z = 0;
int st_status = 0;
RETRY_MAG_SELFTEST:
pr_info("[FACTORY] %s - start\n", __func__);
adsp_unicast(NULL, 0, MSG_MAG, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_MAG) &&
cnt++ < TIMEOUT_CNT)
msleep(26);
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_MAG);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
data->msg_buf[MSG_MAG][0] = -1;
#ifdef CONFIG_SEC_FACTORY
panic("force crash : sensor selftest timeout\n");
#endif
}
if (!(data->msg_buf[MSG_MAG][0] == 0)) {
if (retry < MAG_ST_TRY_CNT) {
retry++;
for (i = 0; i < 10; i++)
data->msg_buf[MSG_MAG][i] = 0;
msleep(100);
cnt = 0;
pr_info("[FACTORY] %s - retry %d\n", __func__, retry);
goto RETRY_MAG_SELFTEST;
}
adsp_unicast(NULL, 0, MSG_MAG_CAL, 0, MSG_TYPE_FACTORY_ENABLE);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL, 0, MSG_TYPE_SET_CAL_DATA);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL, 0, MSG_TYPE_FACTORY_DISABLE);
return snprintf(buf, PAGE_SIZE, "-1,0,0,0,0,0,0,0,0,0\n");
}
if (data->msg_buf[MSG_MAG][1] != 0) {
pr_info("[FACTORY] %s - msg_buf[1] 0x%x\n", __func__, data->msg_buf[MSG_MAG][1]);
st_status = AKM_ST_FAIL;
}
pr_info("[FACTORY] status=%d, st_status=%d, st_xyz=%d,%d,%d, dac=%d, adc=%d, adc_xyz=%d,%d,%d\n",
data->msg_buf[MSG_MAG][0], st_status,
data->msg_buf[MSG_MAG][2], data->msg_buf[MSG_MAG][3],
data->msg_buf[MSG_MAG][4], data->msg_buf[MSG_MAG][5],
data->msg_buf[MSG_MAG][6], data->msg_buf[MSG_MAG][7],
data->msg_buf[MSG_MAG][8], data->msg_buf[MSG_MAG][9]);
abs_adc_x = ABS(data->msg_buf[MSG_MAG][7]);
abs_adc_y = ABS(data->msg_buf[MSG_MAG][8]);
abs_adc_z = ABS(data->msg_buf[MSG_MAG][9]);
abs_adc_sum = abs_adc_x + abs_adc_y + abs_adc_z;
if (abs_adc_sum >= 26666) {
pr_info("[FACTORY] abs_adc_sum is higher then 40Gauss\n");
st_status = AKM_ST_FAIL;
}
adsp_unicast(NULL, 0, MSG_MAG_CAL, 0, MSG_TYPE_FACTORY_ENABLE);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL, 0, MSG_TYPE_SET_CAL_DATA);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL, 0, MSG_TYPE_FACTORY_DISABLE);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_MAG][0], st_status,
data->msg_buf[MSG_MAG][2], data->msg_buf[MSG_MAG][3],
data->msg_buf[MSG_MAG][4], data->msg_buf[MSG_MAG][5],
data->msg_buf[MSG_MAG][6], data->msg_buf[MSG_MAG][7],
data->msg_buf[MSG_MAG][8], data->msg_buf[MSG_MAG][9]);
}
static ssize_t mag_dhr_sensor_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_MAG, 0, MSG_TYPE_GET_DHR_INFO);
while (!(data->ready_flag[MSG_TYPE_GET_DHR_INFO] & 1 << MSG_MAG) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_DHR_INFO] &= ~(1 << MSG_MAG);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else {
pr_info("[FACTORY] %s - [00h-03h] %02x,%02x,%02x,%02x [10h-16h,18h] %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x [30h-32h] %02x,%02x,%02x\n",
__func__,
data->msg_buf[MSG_MAG][0], data->msg_buf[MSG_MAG][1],
data->msg_buf[MSG_MAG][2], data->msg_buf[MSG_MAG][3],
data->msg_buf[MSG_MAG][4], data->msg_buf[MSG_MAG][5],
data->msg_buf[MSG_MAG][6], data->msg_buf[MSG_MAG][7],
data->msg_buf[MSG_MAG][8], data->msg_buf[MSG_MAG][9],
data->msg_buf[MSG_MAG][10], data->msg_buf[MSG_MAG][11],
data->msg_buf[MSG_MAG][12], data->msg_buf[MSG_MAG][13],
data->msg_buf[MSG_MAG][14]);
}
return snprintf(buf, PAGE_SIZE, "%s\n", "Done");
}
static DEVICE_ATTR(name, 0444, mag_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, mag_vendor_show, NULL);
static DEVICE_ATTR(raw_data, 0664, mag_raw_data_show, mag_raw_data_store);
static DEVICE_ATTR(dac, 0444, mag_check_cntl, NULL);
static DEVICE_ATTR(chk_registers, 0444, mag_check_registers, NULL);
static DEVICE_ATTR(selftest, 0440, mag_selftest_show, NULL);
static DEVICE_ATTR(asa, 0444, mag_get_asa, NULL);
static DEVICE_ATTR(status, 0444, mag_get_status, NULL);
#ifdef CONFIG_SEC_FACTORY
static DEVICE_ATTR(dhr_sensor_info, 0444, mag_dhr_sensor_info_show, NULL);
#else
static DEVICE_ATTR(dhr_sensor_info, 0440, mag_dhr_sensor_info_show, NULL);
#endif
static struct device_attribute *mag_attrs[] = {
&dev_attr_name,
&dev_attr_vendor,
&dev_attr_raw_data,
&dev_attr_dac,
&dev_attr_chk_registers,
&dev_attr_selftest,
&dev_attr_asa,
&dev_attr_status,
&dev_attr_dhr_sensor_info,
NULL,
};
int ak09918_factory_init(void)
{
adsp_factory_register(MSG_MAG, mag_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void ak09918_factory_exit(void)
{
adsp_factory_unregister(MSG_MAG);
pr_info("[FACTORY] %s\n", __func__);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 2024, 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define NAME "Back Tap"
#define VENDOR "Samsung"
/* 1: Double Tap
* 2: Triple Tap
* 3: Double and Triple Tap
*/
static int backtap_type = 3;
static int backtap_thd;
static ssize_t backtap_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", NAME);
}
static ssize_t backtap_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t backtap_peak_thd_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY] %s: Curr THD %d\n", __func__, backtap_thd);
return snprintf(buf, PAGE_SIZE, "%d\n", backtap_thd);
}
static ssize_t backtap_peak_thd_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int cnt = 0;
int msg_buf;
int ret = 0;
ret = kstrtoint(buf, 10, &msg_buf);
if (ret < 0) {
pr_err("[FACTORY] %s: kstrtoint fail\n", __func__);
return -EINVAL;
}
if (msg_buf < 0 || msg_buf > 2) {
pr_err("[FACTORY] %s: Invalid value\n", __func__);
return -EINVAL;
}
pr_info("[FACTORY] %s: msg_buf = %d\n", __func__, msg_buf);
mutex_lock(&data->backtap_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int),
MSG_BACKTAP, 0, MSG_TYPE_SET_THRESHOLD);
while (!(data->ready_flag[MSG_TYPE_SET_THRESHOLD] & 1 << MSG_BACKTAP) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_THRESHOLD] &= ~(1 << MSG_BACKTAP);
if (cnt >= TIMEOUT_CNT)
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
else
backtap_thd = data->msg_buf[MSG_BACKTAP][0];
pr_info("[FACTORY] %s: New THD %d\n", __func__, backtap_thd);
mutex_unlock(&data->backtap_factory_mutex);
return size;
}
static ssize_t backtap_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY] %s: Curr Type %d\n", __func__, backtap_type);
return snprintf(buf, PAGE_SIZE, "%d\n", backtap_type);
}
static ssize_t backtap_type_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int cnt = 0;
int msg_buf;
int ret = 0;
ret = kstrtoint(buf, 10, &msg_buf);
if (ret < 0) {
pr_err("[FACTORY] %s: kstrtoint fail\n", __func__);
return -EINVAL;
}
if (msg_buf <= 0 || msg_buf >= 4) {
pr_err("[FACTORY] %s: Invalid value\n", __func__);
return -EINVAL;
}
pr_info("[FACTORY] %s: msg_buf = %d\n", __func__, msg_buf);
mutex_lock(&data->backtap_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int),
MSG_BACKTAP, 0, MSG_TYPE_OPTION_DEFINE);
while (!(data->ready_flag[MSG_TYPE_OPTION_DEFINE] & 1 << MSG_BACKTAP) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_OPTION_DEFINE] &= ~(1 << MSG_BACKTAP);
if (cnt >= TIMEOUT_CNT)
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
else
backtap_type = data->msg_buf[MSG_BACKTAP][0];
pr_info("[FACTORY] %s: New Type %d\n", __func__, backtap_type);
mutex_unlock(&data->backtap_factory_mutex);
return size;
}
static DEVICE_ATTR(name, 0444, backtap_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, backtap_vendor_show, NULL);
static DEVICE_ATTR(backtap_peak_thd, 0660, backtap_peak_thd_show, backtap_peak_thd_store);
static DEVICE_ATTR(backtap_type, 0660, backtap_type_show, backtap_type_store);
static struct device_attribute *backtap_attrs[] = {
&dev_attr_name,
&dev_attr_vendor,
&dev_attr_backtap_peak_thd,
&dev_attr_backtap_type,
NULL,
};
int __init backtap_factory_init(void)
{
adsp_factory_register(MSG_BACKTAP, backtap_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit backtap_factory_exit(void)
{
adsp_factory_unregister(MSG_BACKTAP);
pr_info("[FACTORY] %s\n", __func__);
}

View File

@@ -0,0 +1,707 @@
/*
* Copyright (C) 2020, 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/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/notifier.h>
#include "adsp.h"
enum {
OFF = 0,
ON = 1
};
enum {
X = 0,
Y = 1,
Z = 2,
AXIS_MAX
};
#define ATTACH "ATTACH"
#define DETACH "DETACH"
#define PASS "PASS"
#define FAIL "FAIL"
#define AXIS_SELECT X
#define THRESHOLD -500
#define DETACH_MARGIN 100
#define SATURATION_VALUE 4900
#define MAG_DELAY_MS 10
#define COVER_DETACH 0 // OPEN
#define COVER_ATTACH 1 // CLOSE
#define COVER_ATTACH_NFC_ACTIVE 2 // CLOSE
#define COVER_ATTACH_NFC_TAG_PRESENT 7 // CLOSE
static bool fcd_available;
static int fcd_dual_cal_matrix;
struct factory_cover_status_data {
char cover_status[10];
uint32_t axis_select;
int32_t threshold;
int32_t init[AXIS_MAX];
int32_t attach[AXIS_MAX];
int32_t attach_extremum[AXIS_MAX];
int32_t detach[AXIS_MAX];
char attach_result[10];
char detach_result[10];
char final_result[10];
uint8_t factory_test_status;
int32_t attach_diff;
int32_t detach_diff;
int32_t failed_attach_max;
int32_t failed_attach_min;
uint8_t saturation;
};
struct flip_cover_detector_data {
struct hrtimer fcd_timer;
struct workqueue_struct *fcd_wq;
struct work_struct work_fcd;
ktime_t poll_delay;
struct delayed_work notifier_work;
struct adsp_data *data;
};
struct factory_cover_status_data *factory_data;
struct flip_cover_detector_data *fcd_data;
static int nfc_cover_status = -1;
static uint32_t axis_update = AXIS_SELECT;
static int32_t threshold_update = THRESHOLD;
char sysfs_cover_status[10];
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_NOTIFIER)
static BLOCKING_NOTIFIER_HEAD(fcd_nb_head);
int fcd_notifier_register(struct notifier_block *nb)
{
if (!fcd_available) {
pr_info("%s: fcd not available\n", __func__);
return -1;
} else {
pr_info("%s\n", __func__);
return blocking_notifier_chain_register(&fcd_nb_head, nb);
}
}
EXPORT_SYMBOL_GPL(fcd_notifier_register);
int fcd_notifier_unregister(struct notifier_block *nb)
{
if (!fcd_available) {
pr_info("%s: fcd not available\n", __func__);
return -1;
} else {
pr_info("%s\n", __func__);
return blocking_notifier_chain_unregister(&fcd_nb_head, nb);
}
}
EXPORT_SYMBOL(fcd_notifier_unregister);
int fcd_notifier_call_chain(unsigned long val, void *v)
{
if (!fcd_available) {
pr_info("%s: fcd not available\n", __func__);
return -1;
} else {
pr_info("%s - %lu\n", __func__, val);
return blocking_notifier_call_chain(&fcd_nb_head, val, v);
}
}
#endif
static void send_axis_threshold_settings(struct adsp_data *data, int axis, int threshold)
{
uint8_t cnt = 0;
uint16_t flip_cover_detector_idx = MSG_FLIP_COVER_DETECTOR;
int32_t msg_buf[2];
msg_buf[0] = axis;
msg_buf[1] = threshold;
mutex_lock(&data->flip_cover_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf),
flip_cover_detector_idx, 0, MSG_TYPE_SET_THRESHOLD);
while (!(data->ready_flag[MSG_TYPE_SET_THRESHOLD] & 1 << flip_cover_detector_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(20000, 20000);
data->ready_flag[MSG_TYPE_SET_THRESHOLD] &= ~(1 << flip_cover_detector_idx);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else {
axis_update = axis;
threshold_update = threshold;
}
pr_info("[FACTORY] %s: axis=%d, threshold=%d\n", __func__, axis_update, threshold_update);
mutex_unlock(&data->flip_cover_factory_mutex);
}
static void send_flip_cover_status_to_mag_sensor(struct adsp_data *data, int val)
{
uint8_t cnt = 0;
int32_t msg_buf[1];
msg_buf[0] = val;
mutex_lock(&data->flip_cover_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf),
MSG_MAG, 0, MSG_TYPE_SET_TEMPORARY_MSG);
while (!(data->ready_flag[MSG_TYPE_SET_TEMPORARY_MSG] & 1 << MSG_MAG) &&
cnt++ < TIMEOUT_CNT)
usleep_range(20000, 20000);
data->ready_flag[MSG_TYPE_SET_TEMPORARY_MSG] &= ~(1 << MSG_MAG);
if (cnt >= TIMEOUT_CNT)
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
pr_info("[FACTORY] %s: nfc_cover_status=%d set in mag sensor\n", __func__, nfc_cover_status);
mutex_unlock(&data->flip_cover_factory_mutex);
}
static void notify_fcd_status(struct work_struct *work)
{
#if IS_ENABLED(CONFIG_FLIP_COVER_DETECTOR_NOTIFIER)
fcd_notifier_call_chain(nfc_cover_status, NULL);
#endif
}
static void send_nfc_cover_status(struct adsp_data *data, int val)
{
uint8_t cnt = 0;
uint16_t flip_cover_detector_idx = MSG_FLIP_COVER_DETECTOR;
int32_t msg_buf[1];
msg_buf[0] = val;
mutex_lock(&data->flip_cover_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf),
flip_cover_detector_idx, 0, MSG_TYPE_OPTION_DEFINE);
while (!(data->ready_flag[MSG_TYPE_OPTION_DEFINE] & 1 << flip_cover_detector_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(20000, 20000);
data->ready_flag[MSG_TYPE_OPTION_DEFINE] &= ~(1 << flip_cover_detector_idx);
if (cnt >= TIMEOUT_CNT)
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
else
nfc_cover_status = data->msg_buf[flip_cover_detector_idx][0];
pr_info("[FACTORY] %s: nfc_cover_status=%d\n", __func__, nfc_cover_status);
mutex_unlock(&data->flip_cover_factory_mutex);
if (fcd_dual_cal_matrix)
send_flip_cover_status_to_mag_sensor(data, val);
schedule_delayed_work(&fcd_data->notifier_work, msecs_to_jiffies(0));
}
static void get_mag_cal_data_with_saturation(struct adsp_data *data, int *mag_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_MAG, 0, MSG_TYPE_GET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_CAL_DATA] & 1 << MSG_MAG) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 500);
data->ready_flag[MSG_TYPE_GET_CAL_DATA] &= ~(1 << MSG_MAG);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else {
mag_data[X] = data->msg_buf[MSG_MAG][0];
mag_data[Y] = data->msg_buf[MSG_MAG][1];
mag_data[Z] = data->msg_buf[MSG_MAG][2];
factory_data->saturation = data->msg_buf[MSG_MAG][3];
}
pr_info("[FACTORY] %s: %d, %d, %d, %d\n", __func__,
mag_data[0], mag_data[1], mag_data[2], factory_data->saturation);
}
void check_cover_detection_factory(int *mag_data, int axis_select)
{
int axis = 0;
if (!strcmp(factory_data->cover_status, DETACH)) {
if (mag_data[axis_select] > factory_data->failed_attach_max) {
factory_data->failed_attach_max = mag_data[axis_select];
if (abs(factory_data->failed_attach_max - factory_data->init[axis_select])
> abs(factory_data->failed_attach_min - factory_data->init[axis_select])) {
for (axis = X; axis < AXIS_MAX; axis++) {
factory_data->attach[axis] = mag_data[axis];
}
}
} else if (mag_data[axis_select] < factory_data->failed_attach_min) {
factory_data->failed_attach_min = mag_data[axis_select];
if (abs(factory_data->failed_attach_max - factory_data->init[axis_select])
< abs(factory_data->failed_attach_min - factory_data->init[axis_select])) {
for (axis = X; axis < AXIS_MAX; axis++) {
factory_data->attach[axis] = mag_data[axis];
}
}
}
pr_info("[FACTORY] %s: failed_attach_max=%d, failed_attach_min=%d\n", __func__,
factory_data->failed_attach_max, factory_data->failed_attach_min);
factory_data->attach_diff = mag_data[axis_select] - factory_data->init[axis_select];
if (abs(factory_data->attach_diff) > factory_data->threshold) {
snprintf(factory_data->cover_status, 10, ATTACH);
snprintf(factory_data->attach_result, 10, PASS);
for (axis = X; axis < AXIS_MAX; axis++) {
factory_data->attach[axis] = mag_data[axis];
factory_data->attach_extremum[axis] = mag_data[axis];
}
pr_info("[FACTORY] %s: COVER ATTACHED\n", __func__);
}
} else {
if (factory_data->attach_diff > 0) {
if (factory_data->saturation) {
for (axis = X; axis < AXIS_MAX; axis++) {
mag_data[axis] = SATURATION_VALUE;
}
}
if (mag_data[axis_select] > factory_data->attach_extremum[axis_select]) {
for (axis = X; axis < AXIS_MAX; axis++) {
factory_data->attach_extremum[axis] = mag_data[axis];
factory_data->detach[axis] = 0;
}
}
} else {
if (factory_data->saturation) {
for (axis = X; axis < AXIS_MAX; axis++) {
mag_data[axis] = -SATURATION_VALUE;
}
}
if (mag_data[axis_select] < factory_data->attach_extremum[axis_select]) {
for (axis = X; axis < AXIS_MAX; axis++) {
factory_data->attach_extremum[axis] = mag_data[axis];
factory_data->detach[axis] = 0;
}
}
}
factory_data->detach_diff = mag_data[axis_select] - factory_data->attach_extremum[axis_select];
if (factory_data->attach_diff > 0) {
if (mag_data[axis_select] < (factory_data->attach_extremum[axis_select] - DETACH_MARGIN)) {
for (axis = X; axis < AXIS_MAX; axis++) {
factory_data->detach[axis] = mag_data[axis];
}
}
if (factory_data->detach_diff < -factory_data->threshold) {
snprintf(factory_data->cover_status, 10, DETACH);
snprintf(factory_data->detach_result, 10, PASS);
snprintf(factory_data->final_result, 10, PASS);
factory_data->factory_test_status = OFF;
pr_info("[FACTORY] %s: COVER_DETACHED\n", __func__);
}
} else {
if (mag_data[axis_select] > (factory_data->attach_extremum[axis_select] + DETACH_MARGIN)) {
for (axis = X; axis < AXIS_MAX; axis++) {
factory_data->detach[axis] = mag_data[axis];
}
}
if (factory_data->detach_diff > factory_data->threshold) {
snprintf(factory_data->cover_status, 10, DETACH);
snprintf(factory_data->detach_result, 10, PASS);
snprintf(factory_data->final_result, 10, PASS);
factory_data->factory_test_status = OFF;
pr_info("[FACTORY] %s: COVER_DETACHED\n", __func__);
}
}
}
pr_info("[FACTORY1] %s: cover_status=%s, axis_select=%d, thd=%d, \
x_init=%d, x_attach=%d, x_min_max=%d, x_detach=%d, \
y_init=%d, y_attach=%d, y_min_max=%d, y_detach=%d, \
z_init=%d, z_attach=%d, z_min_max=%d, z_detach=%d, \
attach_result=%s, detach_result=%s, final_result=%s\n",
__func__, factory_data->cover_status, factory_data->axis_select, factory_data->threshold,
factory_data->init[X], factory_data->attach[X], factory_data->attach_extremum[X], factory_data->detach[X],
factory_data->init[Y], factory_data->attach[Y], factory_data->attach_extremum[Y], factory_data->detach[Y],
factory_data->init[Z], factory_data->attach[Z], factory_data->attach_extremum[Z], factory_data->detach[Z],
factory_data->attach_result, factory_data->detach_result, factory_data->final_result);
}
static void fcd_work_func(struct work_struct *work)
{
int mag_data[AXIS_MAX];
if (factory_data->factory_test_status == ON) {
get_mag_cal_data_with_saturation(fcd_data->data, mag_data);
check_cover_detection_factory(mag_data, factory_data->axis_select);
}
}
static enum hrtimer_restart fcd_timer_func(struct hrtimer *timer)
{
queue_work(fcd_data->fcd_wq, &fcd_data->work_fcd);
hrtimer_forward_now(&fcd_data->fcd_timer, fcd_data->poll_delay);
if (factory_data->factory_test_status == ON)
return HRTIMER_RESTART;
else
return HRTIMER_NORESTART;
}
static void factory_data_init(void)
{
int mag_data[AXIS_MAX];
int axis = 0;
memset(factory_data, 0, sizeof(struct factory_cover_status_data));
get_mag_cal_data_with_saturation(fcd_data->data, mag_data);
factory_data->axis_select = axis_update;
factory_data->threshold = (threshold_update > 0) ? threshold_update : threshold_update * (-1);
for (axis = X; axis < AXIS_MAX; axis++) {
factory_data->init[axis] = mag_data[axis];
factory_data->attach[axis] = mag_data[axis];
}
factory_data->failed_attach_max = mag_data[factory_data->axis_select];
factory_data->failed_attach_min = mag_data[factory_data->axis_select];
snprintf(factory_data->cover_status, 10, DETACH);
snprintf(factory_data->attach_result, 10, FAIL);
snprintf(factory_data->detach_result, 10, FAIL);
snprintf(factory_data->final_result, 10, FAIL);
}
static void enable_factory_test(int request)
{
if (request == ON) {
factory_data_init();
factory_data->factory_test_status = ON;
hrtimer_start(&fcd_data->fcd_timer, fcd_data->poll_delay, HRTIMER_MODE_REL);
} else {
hrtimer_cancel(&fcd_data->fcd_timer);
cancel_work_sync(&fcd_data->work_fcd);
factory_data->factory_test_status = OFF;
}
}
static ssize_t nfc_cover_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
if (nfc_cover_status == COVER_ATTACH || nfc_cover_status == COVER_ATTACH_NFC_ACTIVE || nfc_cover_status == COVER_ATTACH_NFC_TAG_PRESENT) {
snprintf(sysfs_cover_status, 10, "CLOSE");
} else if (nfc_cover_status == COVER_DETACH) {
snprintf(sysfs_cover_status, 10, "OPEN");
}
pr_info("[FACTORY] %s: sysfs_cover_status=%s\n", __func__, sysfs_cover_status);
return snprintf(buf, PAGE_SIZE, "%s\n", sysfs_cover_status);
}
static ssize_t nfc_cover_status_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int status = 0;
if (kstrtoint(buf, 10, &status)) {
pr_err("[FACTORY] %s: kstrtoint fail\n", __func__);
return size;
}
send_nfc_cover_status(data, status);
pr_info("[FACTORY] %s: status=%d\n", __func__, status);
return size;
}
static ssize_t factory_cover_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY] %s: status=%s, axis=%d, thd=%d, \
x_init=%d, x_attach=%d, x_min_max=%d, x_detach=%d, \
y_init=%d, y_attach=%d, y_min_max=%d, y_detach=%d, \
z_init=%d, z_attach=%d, z_min_max=%d, z_detach=%d, \
attach_result=%s, detach_result=%s, final_result=%s\n",
__func__, factory_data->cover_status, factory_data->axis_select, factory_data->threshold,
factory_data->init[X], factory_data->attach[X], factory_data->attach_extremum[X], factory_data->detach[X],
factory_data->init[Y], factory_data->attach[Y], factory_data->attach_extremum[Y], factory_data->detach[Y],
factory_data->init[Z], factory_data->attach[Z], factory_data->attach_extremum[Z], factory_data->detach[Z],
factory_data->attach_result, factory_data->detach_result, factory_data->final_result);
return snprintf(buf, PAGE_SIZE, "%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%s\n",
factory_data->cover_status, factory_data->axis_select, factory_data->threshold,
factory_data->init[X], factory_data->attach[X], factory_data->attach_extremum[X], factory_data->detach[X],
factory_data->init[Y], factory_data->attach[Y], factory_data->attach_extremum[Y], factory_data->detach[Y],
factory_data->init[Z], factory_data->attach[Z], factory_data->attach_extremum[Z], factory_data->detach[Z],
factory_data->attach_result, factory_data->detach_result, factory_data->final_result);
}
static ssize_t factory_cover_status_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int factory_test_request = -1;
fcd_data->data = data;
if (kstrtoint(buf, 10, &factory_test_request)) {
pr_err("[FACTORY] %s: kstrtoint fail\n", __func__);
return size;
}
pr_info("[FACTORY] %s: factory_test_request=%d\n", __func__, factory_test_request);
if (factory_test_request == ON && factory_data->factory_test_status == OFF)
enable_factory_test(ON);
else if (factory_test_request == OFF && factory_data->factory_test_status == ON)
enable_factory_test(OFF);
return size;
}
static ssize_t axis_threshold_setting_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY] %s: axis=%d, threshold=%d\n", __func__, axis_update, threshold_update);
return snprintf(buf, PAGE_SIZE, "%d,%d\n", axis_update, threshold_update);
}
static ssize_t axis_threshold_setting_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int ret;
int axis, threshold;
ret = sscanf(buf, "%d,%d", &axis, &threshold);
if (ret != 2) {
pr_err("[FACTORY] %s: Invalid values received, ret=%d\n", __func__, ret);
return -EINVAL;
}
if (axis < 0 || axis >= AXIS_MAX) {
pr_err("[FACTORY] %s: Invalid axis value received\n", __func__);
return -EINVAL;
}
pr_info("[FACTORY] %s: axis=%d, threshold=%d\n", __func__, axis, threshold);
send_axis_threshold_settings(data, axis, threshold);
return size;
}
static ssize_t mag_cal_matrix_num_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int cal_matrix_num;
adsp_unicast(NULL, 0, MSG_MAG, 0, MSG_TYPE_GET_THRESHOLD);
while (!(data->ready_flag[MSG_TYPE_GET_THRESHOLD] & 1 << MSG_MAG) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_THRESHOLD] &= ~(1 << MSG_MAG);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
cal_matrix_num = -1;
} else {
pr_info("[FACTORY] %s cal_matix_num = %d\n", __func__, data->msg_buf[MSG_MAG][0]);
cal_matrix_num = data->msg_buf[MSG_MAG][0];
}
return snprintf(buf, PAGE_SIZE, "%d\n", cal_matrix_num);
}
void flip_cover_detector_cal_init_work(void)
{
if (fcd_dual_cal_matrix && nfc_cover_status > 0) {
int32_t msg_buf[1];
msg_buf[0] = nfc_cover_status;
adsp_unicast(msg_buf, sizeof(msg_buf), MSG_MAG, 0, MSG_TYPE_SET_TEMPORARY_MSG);
pr_info("[FACTORY] %s: nfc_cover_status=%d set in mag sensor after factory init\n",
__func__, msg_buf[0]);
}
}
static DEVICE_ATTR(nfc_cover_status, 0664, nfc_cover_status_show, nfc_cover_status_store);
static DEVICE_ATTR(factory_cover_status, 0664, factory_cover_status_show, factory_cover_status_store);
static DEVICE_ATTR(axis_threshold_setting, 0664, axis_threshold_setting_show, axis_threshold_setting_store);
static DEVICE_ATTR(cal_matrix_num, 0444, mag_cal_matrix_num_show, NULL);
static struct device_attribute *flip_cover_detector_attrs[] = {
&dev_attr_nfc_cover_status,
&dev_attr_factory_cover_status,
&dev_attr_axis_threshold_setting,
&dev_attr_cal_matrix_num,
NULL,
};
void check_device_default_thd(struct device_node *np)
{
int ret = of_property_read_u32(np, "fcd,attach_thd", &threshold_update);
if (ret < 0) {
pr_info("[FACTORY] %s: attach_thd not found, ret=%d\n", __func__, ret);
threshold_update = THRESHOLD;
}
pr_info("[FACTORY] %s: %d\n", __func__, threshold_update);
}
void check_device_axis_update(struct device_node *np)
{
int ret = of_property_read_u32(np, "fcd,axis", &axis_update);
if (ret < 0) {
pr_info("[FACTORY] %s: fcd,axis not found, ret=%d\n", __func__, ret);
axis_update = AXIS_SELECT;
}
pr_info("[FACTORY] %s: %d\n", __func__, axis_update);
}
void check_fcd_dual_cal_matrix_support(struct device_node *np)
{
int ret = of_property_read_u32(np, "fcd,dual_cal_matrix", &fcd_dual_cal_matrix);
if (ret < 0) {
pr_info("[FACTORY] %s: fcd,dual_cal_matrix not found, ret=%d\n", __func__, ret);
fcd_dual_cal_matrix = 0;
}
pr_info("[FACTORY] %s: %d\n", __func__, fcd_dual_cal_matrix);
}
static bool check_flip_cover_detector_availability(void)
{
struct device_node *np = of_find_node_by_name(NULL, "flip_cover_detector_sensor");
if (np == NULL) {
pr_info("[FACTORY] %s: false\n", __func__);
fcd_available = false;
} else {
pr_info("[FACTORY] %s: true\n", __func__);
fcd_available = true;
check_fcd_dual_cal_matrix_support(np);
check_device_default_thd(np);
check_device_axis_update(np);
}
return fcd_available;
}
int flip_cover_detector_factory_init(void)
{
fcd_available = check_flip_cover_detector_availability();
if (!fcd_available)
return 0;
adsp_factory_register(MSG_FLIP_COVER_DETECTOR, flip_cover_detector_attrs);
fcd_data = kzalloc(sizeof(*fcd_data), GFP_KERNEL);
if (fcd_data == NULL) {
pr_err("[FACTORY] %s: Memory allocation failed for fcd_data\n", __func__);
return -ENOMEM;
}
factory_data = kzalloc(sizeof(*factory_data), GFP_KERNEL);
if (factory_data == NULL) {
pr_err("[FACTORY] %s: Memory allocation failed for factory_data\n", __func__);
kfree(fcd_data);
return -ENOMEM;
}
hrtimer_init(&fcd_data->fcd_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
fcd_data->fcd_timer.function = fcd_timer_func;
fcd_data->fcd_wq = create_singlethread_workqueue("flip_cover_detector_wq");
if (fcd_data->fcd_wq == NULL) {
pr_err("[FACTORY] %s: could not create flip cover detector wq\n", __func__);
kfree(fcd_data);
kfree(factory_data);
return -ENOMEM;
}
INIT_WORK(&fcd_data->work_fcd, fcd_work_func);
fcd_data->poll_delay = ns_to_ktime(MAG_DELAY_MS * NSEC_PER_MSEC);
INIT_DELAYED_WORK(&fcd_data->notifier_work, notify_fcd_status);
snprintf(sysfs_cover_status, 10, "OPEN");
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void flip_cover_detector_factory_exit(void)
{
if (!fcd_available)
return;
cancel_delayed_work(&fcd_data->notifier_work);
adsp_factory_unregister(MSG_FLIP_COVER_DETECTOR);
if (fcd_data != NULL) {
if (factory_data->factory_test_status == ON)
enable_factory_test(OFF);
if (fcd_data->fcd_wq != NULL) {
destroy_workqueue(fcd_data->fcd_wq);
fcd_data->fcd_wq = NULL;
}
kfree(fcd_data);
kfree(factory_data);
}
pr_info("[FACTORY] %s\n", __func__);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,326 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define VENDOR "STM"
#if IS_ENABLED(CONFIG_LPS22DF_FACTORY)
#define CHIP_ID "LPS22DF"
#else
#define CHIP_ID "LPS22HH"
#endif
#define CALIBRATION_FILE_PATH "/efs/FactoryApp/baro_delta"
#define PR_MAX 8388607 /* 24 bit 2'compl */
#define PR_MIN -8388608
#define SNS_SUCCESS 0
#define ST_PASS 1
#define ST_FAIL 0
static int sea_level_pressure;
static int pressure_cal;
static ssize_t pressure_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t pressure_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t sea_level_pressure_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", sea_level_pressure);
}
static ssize_t sea_level_pressure_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
if (sscanf(buf, "%10d", &sea_level_pressure) != 1) {
pr_err("[FACTORY] %s: sscanf error\n", __func__);
return size;
}
sea_level_pressure = sea_level_pressure / 100;
pr_info("[FACTORY] %s: sea_level_pressure = %d\n", __func__,
sea_level_pressure);
return size;
}
/*
int pressure_open_calibration(struct adsp_data *data)
{
int error = 0;
return error;
}
*/
static ssize_t pressure_cabratioin_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
schedule_delayed_work(&data->pressure_cal_work, 0);
return size;
}
static ssize_t pressure_cabratioin_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
//struct adsp_data *data = dev_get_drvdata(dev);
//pressure_open_calibration(data);
return snprintf(buf, PAGE_SIZE, "%d\n", pressure_cal);
}
static ssize_t temperature_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_PRESSURE_TEMP, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] &
1 << MSG_PRESSURE_TEMP) && cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_PRESSURE_TEMP);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-99\n");
}
return snprintf(buf, PAGE_SIZE, "%d\n",
data->msg_buf[MSG_PRESSURE_TEMP][0]);
}
static ssize_t selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_PRESSURE, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &
1 << MSG_PRESSURE) && cnt++ < TIMEOUT_CNT)
msleep(26);
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "0\n");
}
pr_info("[FACTORY] %s : P:%d, T:%d, RES:%d\n",
__func__, data->msg_buf[MSG_PRESSURE][0],
data->msg_buf[MSG_PRESSURE][1], data->msg_buf[MSG_PRESSURE][2]);
if (SNS_SUCCESS == data->msg_buf[MSG_PRESSURE][2])
return snprintf(buf, PAGE_SIZE, "%d\n", ST_PASS);
else
return snprintf(buf, PAGE_SIZE, "%d\n", ST_FAIL);
}
static ssize_t pressure_dhr_sensor_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int i = 0;
adsp_unicast(NULL, 0, MSG_PRESSURE, 0, MSG_TYPE_GET_DHR_INFO);
while (!(data->ready_flag[MSG_TYPE_GET_DHR_INFO] & 1 << MSG_PRESSURE) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_DHR_INFO] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else {
for (i = 0; i < 8; i++) {
pr_info("[FACTORY] %s - %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
__func__,
data->msg_buf[MSG_PRESSURE][i * 16 + 0],
data->msg_buf[MSG_PRESSURE][i * 16 + 1],
data->msg_buf[MSG_PRESSURE][i * 16 + 2],
data->msg_buf[MSG_PRESSURE][i * 16 + 3],
data->msg_buf[MSG_PRESSURE][i * 16 + 4],
data->msg_buf[MSG_PRESSURE][i * 16 + 5],
data->msg_buf[MSG_PRESSURE][i * 16 + 6],
data->msg_buf[MSG_PRESSURE][i * 16 + 7],
data->msg_buf[MSG_PRESSURE][i * 16 + 8],
data->msg_buf[MSG_PRESSURE][i * 16 + 9],
data->msg_buf[MSG_PRESSURE][i * 16 + 10],
data->msg_buf[MSG_PRESSURE][i * 16 + 11],
data->msg_buf[MSG_PRESSURE][i * 16 + 12],
data->msg_buf[MSG_PRESSURE][i * 16 + 13],
data->msg_buf[MSG_PRESSURE][i * 16 + 14],
data->msg_buf[MSG_PRESSURE][i * 16 + 15]);
}
}
return snprintf(buf, PAGE_SIZE, "%s\n", "Done");
}
static ssize_t pressure_sw_offset_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int input = 0;
int sw_offset = 0;
int ret;
ret = kstrtoint(buf, 10, &input);
if (ret < 0) {
pr_err("[FACTORY] %s: kstrtoint fail\n", __func__);
return -EINVAL;
}
pr_info("[FACTORY] %s: write value = %d\n", __func__, input);
adsp_unicast(&input, sizeof(int),
MSG_PRESSURE, 0, MSG_TYPE_SET_THRESHOLD);
while (!(data->ready_flag[MSG_TYPE_SET_THRESHOLD] & 1 << MSG_PRESSURE) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_THRESHOLD] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else {
sw_offset = data->msg_buf[MSG_PRESSURE][0];
}
pr_info("[FACTORY] %s: sw_offset %d\n", __func__, sw_offset);
return size;
}
static ssize_t pressure_sw_offset_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_PRESSURE, 0, MSG_TYPE_GET_THRESHOLD);
while (!(data->ready_flag[MSG_TYPE_GET_THRESHOLD] &
1 << MSG_PRESSURE) && cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_THRESHOLD] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "0\n");
}
pr_info("[FACTORY] %s : sw_offset %d\n",
__func__, data->msg_buf[MSG_PRESSURE][0]);
return snprintf(buf, PAGE_SIZE, "%d\n", data->msg_buf[MSG_PRESSURE][0]);
}
static DEVICE_ATTR(vendor, 0444, pressure_vendor_show, NULL);
static DEVICE_ATTR(name, 0444, pressure_name_show, NULL);
static DEVICE_ATTR(calibration, 0664,
pressure_cabratioin_show, pressure_cabratioin_store);
static DEVICE_ATTR(sea_level_pressure, 0664,
sea_level_pressure_show, sea_level_pressure_store);
static DEVICE_ATTR(temperature, 0444, temperature_show, NULL);
static DEVICE_ATTR(selftest, 0444, selftest_show, NULL);
#ifdef CONFIG_SEC_FACTORY
static DEVICE_ATTR(dhr_sensor_info, 0444,
pressure_dhr_sensor_info_show, NULL);
#else
static DEVICE_ATTR(dhr_sensor_info, 0440,
pressure_dhr_sensor_info_show, NULL);
#endif
static DEVICE_ATTR(sw_offset, 0664,
pressure_sw_offset_show, pressure_sw_offset_store);
static struct device_attribute *pressure_attrs[] = {
&dev_attr_vendor,
&dev_attr_name,
&dev_attr_calibration,
&dev_attr_sea_level_pressure,
&dev_attr_temperature,
&dev_attr_selftest,
&dev_attr_dhr_sensor_info,
&dev_attr_sw_offset,
NULL,
};
void pressure_cal_work_func(struct work_struct *work)
{
struct adsp_data *data = container_of((struct delayed_work *)work,
struct adsp_data, pressure_cal_work);
int cnt = 0;
int temp = 0;
adsp_unicast(&temp, sizeof(temp), MSG_PRESSURE, 0, MSG_TYPE_SET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_SET_CAL_DATA] & 1 << MSG_PRESSURE) &&
cnt++ < 3)
msleep(30);
data->ready_flag[MSG_TYPE_SET_CAL_DATA] &= ~(1 << MSG_PRESSURE);
if (cnt >= 3) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return;
}
pressure_cal = data->msg_buf[MSG_PRESSURE][0];
pr_info("[FACTORY] %s: pressure_cal = %d (lsb)\n", __func__, data->msg_buf[MSG_PRESSURE][0]);
}
EXPORT_SYMBOL(pressure_cal_work_func);
void pressure_factory_init_work(struct adsp_data *data)
{
schedule_delayed_work(&data->pressure_cal_work, msecs_to_jiffies(8000));
}
EXPORT_SYMBOL(pressure_factory_init_work);
int __init lps22hh_pressure_factory_init(void)
{
adsp_factory_register(MSG_PRESSURE, pressure_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit lps22hh_pressure_factory_exit(void)
{
adsp_factory_unregister(MSG_PRESSURE);
pr_info("[FACTORY] %s\n", __func__);
}

View File

@@ -0,0 +1,191 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define VENDOR "STM"
#define CHIP_ID "LSM6DSL"
#define ST_PASS 1
#define ST_FAIL 0
#define ST_ZRO_MIN (-40)
#define ST_ZRO_MAX 40
#define SELFTEST_REVISED 1
static ssize_t gyro_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t gyro_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t selftest_revised_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", SELFTEST_REVISED);
}
static ssize_t gyro_power_off(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY]: %s\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", 1);
}
static ssize_t gyro_power_on(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY]: %s\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", 1);
}
static ssize_t gyro_temp_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_GYRO_TEMP, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_GYRO_TEMP)
&& cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_GYRO_TEMP);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-99\n");
}
pr_info("[FACTORY] %s: gyro_temp = %d\n", __func__,
data->msg_buf[MSG_GYRO_TEMP][0]);
return snprintf(buf, PAGE_SIZE, "%d\n",
data->msg_buf[MSG_GYRO_TEMP][0]);
}
static ssize_t gyro_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int st_diff_res = ST_FAIL;
int st_zro_res = ST_FAIL;
pr_info("[FACTORY] %s - start", __func__);
adsp_unicast(NULL, 0, MSG_GYRO, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_GYRO) &&
cnt++ < TIMEOUT_CNT)
msleep(25);
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_GYRO);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE,
"0,0,0,0,0,0,0,0,0,0,0,0,%d,%d\n",
ST_FAIL, ST_FAIL);
}
if (data->msg_buf[MSG_GYRO][1] != 0) {
pr_info("[FACTORY] %s - failed(%d, %d)\n", __func__,
data->msg_buf[MSG_GYRO][1],
data->msg_buf[MSG_GYRO][5]);
pr_info("[FACTORY]: %s - %d,%d,%d\n", __func__,
data->msg_buf[MSG_GYRO][2],
data->msg_buf[MSG_GYRO][3],
data->msg_buf[MSG_GYRO][4]);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
data->msg_buf[MSG_GYRO][2],
data->msg_buf[MSG_GYRO][3],
data->msg_buf[MSG_GYRO][4]);
}
if (!data->msg_buf[MSG_GYRO][5])
st_diff_res = ST_PASS;
if((ST_ZRO_MIN <= data->msg_buf[MSG_GYRO][6])
&& (data->msg_buf[MSG_GYRO][6] <= ST_ZRO_MAX)
&& (ST_ZRO_MIN <= data->msg_buf[MSG_GYRO][7])
&& (data->msg_buf[MSG_GYRO][7] <= ST_ZRO_MAX)
&& (ST_ZRO_MIN <= data->msg_buf[MSG_GYRO][8])
&& (data->msg_buf[MSG_GYRO][8]<= ST_ZRO_MAX))
st_zro_res = ST_PASS;
pr_info("[FACTORY]: %s - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
__func__,
data->msg_buf[MSG_GYRO][2], data->msg_buf[MSG_GYRO][3],
data->msg_buf[MSG_GYRO][4], data->msg_buf[MSG_GYRO][6],
data->msg_buf[MSG_GYRO][7], data->msg_buf[MSG_GYRO][8],
data->msg_buf[MSG_GYRO][9], data->msg_buf[MSG_GYRO][10],
data->msg_buf[MSG_GYRO][11], data->msg_buf[MSG_GYRO][12],
data->msg_buf[MSG_GYRO][13], data->msg_buf[MSG_GYRO][14],
st_diff_res, st_zro_res);
return snprintf(buf, PAGE_SIZE,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_GYRO][2], data->msg_buf[MSG_GYRO][3],
data->msg_buf[MSG_GYRO][4], data->msg_buf[MSG_GYRO][6],
data->msg_buf[MSG_GYRO][7], data->msg_buf[MSG_GYRO][8],
data->msg_buf[MSG_GYRO][9], data->msg_buf[MSG_GYRO][10],
data->msg_buf[MSG_GYRO][11], data->msg_buf[MSG_GYRO][12],
data->msg_buf[MSG_GYRO][13], data->msg_buf[MSG_GYRO][14],
st_diff_res, st_zro_res);
}
static DEVICE_ATTR(name, 0444, gyro_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, gyro_vendor_show, NULL);
static DEVICE_ATTR(selftest, 0440, gyro_selftest_show, NULL);
static DEVICE_ATTR(power_on, 0444, gyro_power_on, NULL);
static DEVICE_ATTR(power_off, 0444, gyro_power_off, NULL);
static DEVICE_ATTR(temperature, 0440, gyro_temp_show, NULL);
static DEVICE_ATTR(selftest_revised, 0440, selftest_revised_show, NULL);
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_revised,
NULL,
};
int __init lsm6dsl_gyro_factory_init(void)
{
adsp_factory_register(MSG_GYRO, gyro_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit lsm6dsl_gyro_factory_exit(void)
{
adsp_factory_unregister(MSG_GYRO);
pr_info("[FACTORY] %s\n", __func__);
}

View File

@@ -0,0 +1,868 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#ifdef CONFIG_SEC_VIB_NOTIFIER
#include <linux/vibrator/sec_vibrator_notifier.h>
#endif
#define VENDOR "STM"
#if IS_ENABLED(CONFIG_LSM6DSV_FACTORY)
#define CHIP_ID "LSM6DSV"
#else
#define CHIP_ID "LSM6DSO"
#endif
#define ACCEL_ST_TRY_CNT 3
#define ACCEL_FACTORY_CAL_CNT 20
#define ACCEL_RAW_DATA_CNT 3
#define MAX_ACCEL_1G 2048
#define STM_LSM6DSO_INT_CHECK_RUNNING 4
#define STM_LSM6DSV_INT_CHECK_SKIP_IBI 5
#define MAX_MOTOR_STOP_TIMEOUT (8 * NSEC_PER_SEC)
/* Haptic Pattern A vibrate during 7ms.
* touch, touchkey, operation feedback use this.
* Do not call motor_workfunc when duration is 7ms.
*/
#define DURATION_SKIP 10
#define MOTOR_OFF 0
#define MOTOR_ON 1
#define CALL_VIB_IDX 65534
#ifdef CONFIG_SEC_VIB_NOTIFIER
struct accel_motor_data {
struct notifier_block motor_nb;
struct hrtimer motor_stop_timer;
struct workqueue_struct *slpi_motor_wq;
struct work_struct work_slpi_motor;
atomic_t motor_state;
int idx;
int timeout;
};
struct accel_motor_data *pdata_motor;
#endif
struct accel_data {
struct work_struct work_accel;
struct workqueue_struct *accel_wq;
struct adsp_data *dev_data;
bool is_complete_cal;
bool lpf_onoff;
bool st_complete;
atomic_t vib_state;
int32_t raw_data[ACCEL_RAW_DATA_CNT];
int32_t avg_data[ACCEL_RAW_DATA_CNT];
};
static struct accel_data *pdata;
static bool is_ignore_crash_factory = false;
static ssize_t accel_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t accel_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t sensor_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", "ADSP");
}
int get_accel_cal_data(struct adsp_data *data, int32_t *cal_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_ACCEL, 0, MSG_TYPE_GET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_CAL_DATA] & 1 << MSG_ACCEL) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_CAL_DATA] &= ~(1 << MSG_ACCEL);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return 0;
}
if (data->msg_buf[MSG_ACCEL][3] != ACCEL_RAW_DATA_CNT) {
pr_err("[FACTORY] %s: Reading Bytes Num %d!!!\n",
__func__, data->msg_buf[MSG_ACCEL][3]);
return 0;
}
cal_data[0] = data->msg_buf[MSG_ACCEL][0];
cal_data[1] = data->msg_buf[MSG_ACCEL][1];
cal_data[2] = data->msg_buf[MSG_ACCEL][2];
pr_info("[FACTORY] %s: %d, %d, %d, %d\n", __func__,
cal_data[0], cal_data[1], cal_data[2],
data->msg_buf[MSG_ACCEL][3]);
return data->msg_buf[MSG_ACCEL][3];
}
void set_accel_cal_data(struct adsp_data *data)
{
uint8_t cnt = 0;
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__, pdata->avg_data[0],
pdata->avg_data[1], pdata->avg_data[2]);
adsp_unicast(pdata->avg_data, sizeof(pdata->avg_data),
MSG_ACCEL, 0, MSG_TYPE_SET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_SET_CAL_DATA] & 1 << MSG_ACCEL) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_CAL_DATA] &= ~(1 << MSG_ACCEL);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else if (data->msg_buf[MSG_ACCEL][0] != ACCEL_RAW_DATA_CNT) {
pr_err("[FACTORY] %s: Write Bytes Num %d!!!\n",
__func__, data->msg_buf[MSG_ACCEL][0]);
}
}
static ssize_t accel_calibration_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t cal_data[ACCEL_RAW_DATA_CNT] = {0, };
int ret = 0;
mutex_lock(&data->accel_factory_mutex);
ret = get_accel_cal_data(data, cal_data);
mutex_unlock(&data->accel_factory_mutex);
if (ret > 0) {
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
cal_data[0], cal_data[1], cal_data[2]);
if (cal_data[0] == 0 && cal_data[1] == 0 && cal_data[2] == 0)
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n",
0, 0, 0, 0);
else
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n",
true, cal_data[0], cal_data[1], cal_data[2]);
} else {
pr_err("[FACTORY] %s: get_accel_cal_data fail\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n", 0, 0, 0, 0);
}
}
static ssize_t accel_calibration_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
pdata->dev_data = data;
if (sysfs_streq(buf, "0")) {
mutex_lock(&data->accel_factory_mutex);
memset(pdata->avg_data, 0, sizeof(pdata->avg_data));
set_accel_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
} else {
pdata->is_complete_cal = false;
queue_work(pdata->accel_wq, &pdata->work_accel);
while (pdata->is_complete_cal == false) {
pr_info("[FACTORY] %s: In factory cal\n", __func__);
msleep(20);
}
mutex_lock(&data->accel_factory_mutex);
set_accel_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
}
return size;
}
static void accel_work_func(struct work_struct *work)
{
struct accel_data *data = container_of((struct work_struct *)work,
struct accel_data, work_accel);
int i;
mutex_lock(&data->dev_data->accel_factory_mutex);
memset(pdata->avg_data, 0, sizeof(pdata->avg_data));
adsp_unicast(pdata->avg_data, sizeof(pdata->avg_data),
MSG_ACCEL, 0, MSG_TYPE_SET_CAL_DATA);
msleep(30); /* for init of bias */
for (i = 0; i < ACCEL_FACTORY_CAL_CNT; i++) {
msleep(20);
get_accel_raw_data(pdata->raw_data);
pdata->avg_data[0] += pdata->raw_data[0];
pdata->avg_data[1] += pdata->raw_data[1];
pdata->avg_data[2] += pdata->raw_data[2];
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
pdata->raw_data[0], pdata->raw_data[1],
pdata->raw_data[2]);
}
for (i = 0; i < ACCEL_RAW_DATA_CNT; i++) {
pdata->avg_data[i] /= ACCEL_FACTORY_CAL_CNT;
pr_info("[FACTORY] %s: avg : %d\n",
__func__, pdata->avg_data[i]);
}
if (pdata->avg_data[2] > 0)
pdata->avg_data[2] -= MAX_ACCEL_1G;
else if (pdata->avg_data[2] < 0)
pdata->avg_data[2] += MAX_ACCEL_1G;
mutex_unlock(&data->dev_data->accel_factory_mutex);
pdata->is_complete_cal = true;
}
void accel_cal_work_func(struct work_struct *work)
{
struct adsp_data *data = container_of((struct delayed_work *)work,
struct adsp_data, accel_cal_work);
int ret = 0;
mutex_lock(&data->accel_factory_mutex);
ret = get_accel_cal_data(data, pdata->avg_data);
mutex_unlock(&data->accel_factory_mutex);
if (ret > 0) {
pr_info("[FACTORY] %s: ret(%d) %d, %d, %d\n", __func__, ret,
pdata->avg_data[0],
pdata->avg_data[1],
pdata->avg_data[2]);
mutex_lock(&data->accel_factory_mutex);
set_accel_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
} else {
pr_err("[FACTORY] %s: get_accel_cal_data fail (%d)\n",
__func__, ret);
}
}
static ssize_t accel_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int retry = 0;
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_DIGITAL_HALL_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#elif IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_REF_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#endif
pdata->st_complete = false;
RETRY_ACCEL_SELFTEST:
adsp_unicast(NULL, 0, MSG_ACCEL, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_ACCEL) &&
cnt++ < TIMEOUT_CNT)
msleep(26);
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_ACCEL);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
data->msg_buf[MSG_ACCEL][1] = -1;
#ifdef CONFIG_SEC_FACTORY
panic("sensor force crash : accel selftest timeout\n");
#endif
}
pr_info("[FACTORY] %s : init = %d, result = %d, XYZ = %d, %d, %d, nXYZ = %d, %d, %d\n",
__func__, data->msg_buf[MSG_ACCEL][0],
data->msg_buf[MSG_ACCEL][1], data->msg_buf[MSG_ACCEL][2],
data->msg_buf[MSG_ACCEL][3], data->msg_buf[MSG_ACCEL][4],
data->msg_buf[MSG_ACCEL][5], data->msg_buf[MSG_ACCEL][6],
data->msg_buf[MSG_ACCEL][7]);
pr_info("[FACTORY] %s : pre/postP/postN [%d, %d, %d/%d, %d, %d/%d, %d, %d], comm_err_cnt %d/%d/%d\n",
__func__, data->msg_buf[MSG_ACCEL][8],
data->msg_buf[MSG_ACCEL][9], data->msg_buf[MSG_ACCEL][10],
data->msg_buf[MSG_ACCEL][11], data->msg_buf[MSG_ACCEL][12],
data->msg_buf[MSG_ACCEL][13], data->msg_buf[MSG_ACCEL][14],
data->msg_buf[MSG_ACCEL][15], data->msg_buf[MSG_ACCEL][16],
data->msg_buf[MSG_ACCEL][17], data->msg_buf[MSG_ACCEL][18],
data->msg_buf[MSG_ACCEL][19]);
if (data->msg_buf[MSG_ACCEL][1] == 1) {
pr_info("[FACTORY] %s : Pass - result = %d, retry = %d\n",
__func__, data->msg_buf[MSG_ACCEL][1], retry);
} else {
data->msg_buf[MSG_ACCEL][1] = -5;
pr_err("[FACTORY] %s : Fail - result = %d, retry = %d\n",
__func__, data->msg_buf[MSG_ACCEL][1], retry);
if (retry < ACCEL_ST_TRY_CNT) {
retry++;
msleep(50);
cnt = 0;
pr_info("[FACTORY] %s: retry\n", __func__);
goto RETRY_ACCEL_SELFTEST;
}
}
pdata->st_complete = true;
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973) ||\
IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_ACCEL][1],
(int)abs(data->msg_buf[MSG_ACCEL][2]),
(int)abs(data->msg_buf[MSG_ACCEL][3]),
(int)abs(data->msg_buf[MSG_ACCEL][4]),
(int)abs(data->msg_buf[MSG_ACCEL][5]),
(int)abs(data->msg_buf[MSG_ACCEL][6]),
(int)abs(data->msg_buf[MSG_ACCEL][7]));
}
static ssize_t accel_raw_data_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t raw_data[ACCEL_RAW_DATA_CNT] = {0, };
static int32_t prev_raw_data[ACCEL_RAW_DATA_CNT] = {0, };
int ret = 0;
#ifdef CONFIG_SEC_FACTORY
static int same_cnt = 0;
#endif
if (pdata->st_complete == false) {
pr_info("[FACTORY] %s: selftest is running\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
raw_data[0], raw_data[1], raw_data[2]);
}
mutex_lock(&data->accel_factory_mutex);
ret = get_accel_raw_data(raw_data);
mutex_unlock(&data->accel_factory_mutex);
#ifdef CONFIG_SEC_FACTORY
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
raw_data[0], raw_data[1], raw_data[2]);
if (prev_raw_data[0] == raw_data[0] &&
prev_raw_data[1] == raw_data[1] &&
prev_raw_data[2] == raw_data[2]) {
same_cnt++;
pr_info("[FACTORY] %s: same_cnt %d\n", __func__, same_cnt);
if (same_cnt >= 20)
panic("sensor force crash : accel raw_data stuck\n");
} else
same_cnt = 0;
#endif
if (!ret) {
memcpy(prev_raw_data, raw_data, sizeof(int32_t) * 3);
} else if (!pdata->lpf_onoff) {
pr_err("[FACTORY] %s: using prev data!!!\n", __func__);
memcpy(raw_data, prev_raw_data, sizeof(int32_t) * 3);
} else {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
}
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
raw_data[0], raw_data[1], raw_data[2]);
}
static ssize_t accel_reactive_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
bool success = false;
int32_t msg_buf = 0;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL,
0, MSG_TYPE_GET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_REGISTER] & 1 << MSG_ACCEL) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_REGISTER] &= ~(1 << MSG_ACCEL);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", (int)success);
}
pr_info("[FACTORY]: %s - %d\n", __func__,
data->msg_buf[MSG_ACCEL][0]);
if (data->msg_buf[MSG_ACCEL][0] == 0)
success = true;
if (data->msg_buf[MSG_ACCEL][0] == STM_LSM6DSV_INT_CHECK_SKIP_IBI) {
pr_info("[FACTORY]: %s - IBI mode. Ignore Interrupt Check Test\n", __func__);
success = true;
}
return snprintf(buf, PAGE_SIZE, "%d\n", (int)success);
}
static ssize_t accel_reactive_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t msg_buf;
uint8_t cnt = 0;
if (sysfs_streq(buf, "1"))
pr_info("[FACTORY]: %s - on\n", __func__);
else if (sysfs_streq(buf, "0"))
pr_info("[FACTORY]: %s - off\n", __func__);
else if (sysfs_streq(buf, "2")) {
pr_info("[FACTORY]: %s - factory\n", __func__);
msg_buf = 1;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL,
0, MSG_TYPE_GET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_REGISTER] & 1 << MSG_ACCEL) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_REGISTER] &= ~(1 << MSG_ACCEL);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return size;
}
if (data->msg_buf[MSG_ACCEL][0] == STM_LSM6DSO_INT_CHECK_RUNNING)
pr_info("[FACTORY]: %s - STM_LSM6DSx_INT_CHECK_RUNNING\n", __func__);
else if (data->msg_buf[MSG_ACCEL][0] == STM_LSM6DSV_INT_CHECK_SKIP_IBI)
pr_info("[FACTORY]: %s - IBI mode. Ignore Interrupt Check Test\n", __func__);
else
pr_info("[FACTORY]: %s - Something wrong\n", __func__);
}
return size;
}
bool sns_check_ignore_crash(void)
{
return is_ignore_crash_factory;
}
EXPORT_SYMBOL(sns_check_ignore_crash);
static ssize_t accel_lowpassfilter_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int32_t msg_buf;
if (sysfs_streq(buf, "1")) {
msg_buf = 1;
is_ignore_crash_factory = false;
} else if (sysfs_streq(buf, "0")) {
msg_buf = 0;
is_ignore_crash_factory = false;
#ifdef CONFIG_SEC_FACTORY
} else if (sysfs_streq(buf, "2")) {
msg_buf = 2;
is_ignore_crash_factory = true;
pr_info("[FACTORY] %s: Pretest\n", __func__);
} else if (sysfs_streq(buf, "3")) {
msg_buf = 3;
is_ignore_crash_factory = true;
pr_info("[FACTORY] %s: Questt\n", __func__);
return size;
#endif
} else {
is_ignore_crash_factory = false;
pr_info("[FACTORY] %s: wrong value\n", __func__);
return size;
}
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL,
0, MSG_TYPE_SET_ACCEL_LPF);
while (!(data->ready_flag[MSG_TYPE_SET_ACCEL_LPF] & 1 << MSG_ACCEL) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_ACCEL_LPF] &= ~(1 << MSG_ACCEL);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return size;
}
pdata->lpf_onoff = (bool)data->msg_buf[MSG_ACCEL][0];
#if IS_ENABLED(CONFIG_LSM6DSV_FACTORY)
pr_info("[FACTORY] %s: %d, 0x0A:%02x 0x0D:%02x 0x18:%02x\n", __func__,
data->msg_buf[MSG_ACCEL][0], data->msg_buf[MSG_ACCEL][1],
data->msg_buf[MSG_ACCEL][2], data->msg_buf[MSG_ACCEL][3]);
#else
pr_info("[FACTORY] %s: %d, 0x0A:%02x 0x0D:%02x 0x10:%02x\n", __func__,
data->msg_buf[MSG_ACCEL][0], data->msg_buf[MSG_ACCEL][1],
data->msg_buf[MSG_ACCEL][2], data->msg_buf[MSG_ACCEL][3]);
#endif
return size;
}
#ifdef CONFIG_SEC_VIB_NOTIFIER
uint64_t motor_stop_timeout(int timeout_ms)
{
uint64_t timeout_ns = timeout_ms * NSEC_PER_MSEC;
if (timeout_ns > MAX_MOTOR_STOP_TIMEOUT)
return timeout_ns;
else
return MAX_MOTOR_STOP_TIMEOUT;
}
int ssc_motor_notify(struct notifier_block *nb,
unsigned long enable, void *v)
{
struct vib_notifier_context *vib = (struct vib_notifier_context *)v;
uint64_t timeout_ns = 0;
pr_info("[FACTORY] %s: %s, idx: %d timeout: %d\n",
__func__, enable ? "ON" : "OFF", vib->index, vib->timeout);
if(enable == 1) {
pdata_motor->idx = vib->index;
pdata_motor->timeout = vib->timeout;
if (pdata_motor->idx == 0)
timeout_ns = motor_stop_timeout(pdata_motor->timeout);
else
timeout_ns = MAX_MOTOR_STOP_TIMEOUT;
if (atomic_read(&pdata_motor->motor_state) == MOTOR_OFF) {
atomic_set(&pdata_motor->motor_state, MOTOR_ON);
queue_work(pdata_motor->slpi_motor_wq,
&pdata_motor->work_slpi_motor);
} else {
hrtimer_cancel(&pdata_motor->motor_stop_timer);
if (pdata_motor->idx == CALL_VIB_IDX) {
queue_work(pdata_motor->slpi_motor_wq,
&pdata_motor->work_slpi_motor);
return 0;
}
hrtimer_start(&pdata_motor->motor_stop_timer,
ns_to_ktime(timeout_ns),
HRTIMER_MODE_REL);
}
} else {
if (pdata_motor->idx == CALL_VIB_IDX) {
atomic_set(&pdata_motor->motor_state, MOTOR_OFF);
queue_work(pdata_motor->slpi_motor_wq,
&pdata_motor->work_slpi_motor);
} else
pr_info("[FACTORY] %s: Not support OFF\n", __func__);
}
return 0;
}
static enum hrtimer_restart motor_stop_timer_func(struct hrtimer *timer)
{
pr_info("[FACTORY] %s\n", __func__);
atomic_set(&pdata_motor->motor_state, MOTOR_OFF);
queue_work(pdata_motor->slpi_motor_wq, &pdata_motor->work_slpi_motor);
return HRTIMER_NORESTART;
}
void slpi_motor_work_func(struct work_struct *work)
{
int32_t msg_buf = 0;
uint64_t timeout_ns = 0;
if (pdata_motor->idx == 0)
timeout_ns = motor_stop_timeout(pdata_motor->timeout);
else
timeout_ns = MAX_MOTOR_STOP_TIMEOUT;
if (atomic_read(&pdata_motor->motor_state) == MOTOR_ON) {
if (pdata_motor->idx != CALL_VIB_IDX)
hrtimer_start(&pdata_motor->motor_stop_timer,
ns_to_ktime(timeout_ns),
HRTIMER_MODE_REL);
msg_buf = 1;
} else if (atomic_read(&pdata_motor->motor_state) == MOTOR_OFF) {
if (pdata_motor->idx != CALL_VIB_IDX)
hrtimer_cancel(&pdata_motor->motor_stop_timer);
msg_buf = 0;
} else {
pr_info("[FACTORY] %s: invalid state %d\n",
__func__, (int)atomic_read(&pdata_motor->motor_state));
}
pr_info("[FACTORY] %s: msg_buf = %d, idx/timeout = %d/%d\n",
__func__, msg_buf, pdata_motor->idx,
(int)(timeout_ns / NSEC_PER_MSEC));
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL,
0, MSG_TYPE_SET_ACCEL_MOTOR);
#ifdef CONFIG_SUPPORT_DUAL_6AXIS
usleep_range(500, 550);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL_SUB,
0, MSG_TYPE_SET_ACCEL_MOTOR);
#endif
}
#endif
static ssize_t accel_dhr_sensor_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
char ctrl1_xl = 0;
uint8_t fullscale = 0;
adsp_unicast(NULL, 0, MSG_ACCEL, 0, MSG_TYPE_GET_DHR_INFO);
while (!(data->ready_flag[MSG_TYPE_GET_DHR_INFO] & 1 << MSG_ACCEL) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_DHR_INFO] &= ~(1 << MSG_ACCEL);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else {
ctrl1_xl = data->msg_buf[MSG_ACCEL][16];
ctrl1_xl &= 0xC;
switch (ctrl1_xl) {
case 0xC:
fullscale = 8;
break;
case 0x8:
fullscale = 4;
break;
case 0x4:
fullscale = 16;
break;
case 0:
fullscale = 2;
break;
default:
break;
}
}
pr_info("[FACTORY] %s: f/s %u\n", __func__, fullscale);
return snprintf(buf, PAGE_SIZE, "\"FULL_SCALE\":\"%uG\"\n", fullscale);
}
static ssize_t accel_turn_over_crash_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
pr_info("[FACTORY] %s: %d, \n", __func__, data->turn_over_crash);
return snprintf(buf, PAGE_SIZE, "%d\n", data->turn_over_crash);
}
static ssize_t accel_turn_over_crash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t msg_buf[2] = {0, };
if (sysfs_streq(buf, "1")) {
data->turn_over_crash = 1;
msg_buf[1] = 1;
} else if (sysfs_streq(buf, "2")) {
data->turn_over_crash = 2;
msg_buf[1] = 2;
} else {
data->turn_over_crash = 0;
msg_buf[1] = 0;
}
adsp_unicast(msg_buf, sizeof(msg_buf), MSG_ACCEL,
0, MSG_TYPE_OPTION_DEFINE);
pr_info("[FACTORY] %s: %d, \n", __func__, msg_buf[1]);
return size;
}
void vib_onoff(int onoff)
{
int32_t msg_buf = MOTOR_OFF;
if (atomic_read(&pdata->vib_state) == MOTOR_ON)
msg_buf = MOTOR_ON;
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL,
0, MSG_TYPE_SET_ACCEL_MOTOR);
#ifdef CONFIG_SUPPORT_DUAL_6AXIS
usleep_range(500, 550);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL_SUB,
0, MSG_TYPE_SET_ACCEL_MOTOR);
#endif
}
static ssize_t vib_onoff_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int vib_onoff = (int)atomic_read(&pdata->vib_state);
pr_info("[FACTORY] %s: %d\n", __func__, vib_onoff);
return snprintf(buf, PAGE_SIZE, "%d\n", vib_onoff);
}
static ssize_t vib_onoff_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int32_t enable = -1;
if (sysfs_streq(buf, "1"))
enable = 1;
else
enable = 0;
if (enable == 1) {
if (atomic_read(&pdata->vib_state) == MOTOR_OFF) {
atomic_set(&pdata->vib_state, MOTOR_ON);
vib_onoff(MOTOR_ON);
} else {
pr_info("[FACTORY] %s: Current vib_state is MOTOR_ON\n", __func__);
}
} else {
atomic_set(&pdata->vib_state, MOTOR_OFF);
vib_onoff(MOTOR_OFF);
}
pr_info("[FACTORY] %s: %d\n", __func__, enable);
return size;
}
static DEVICE_ATTR(name, 0444, accel_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, accel_vendor_show, NULL);
static DEVICE_ATTR(type, 0444, sensor_type_show, NULL);
static DEVICE_ATTR(calibration, 0664,
accel_calibration_show, accel_calibration_store);
static DEVICE_ATTR(selftest, 0440,
accel_selftest_show, NULL);
static DEVICE_ATTR(raw_data, 0444, accel_raw_data_show, NULL);
static DEVICE_ATTR(reactive_alert, 0664,
accel_reactive_show, accel_reactive_store);
static DEVICE_ATTR(lowpassfilter, 0220,
NULL, accel_lowpassfilter_store);
#ifdef CONFIG_SEC_FACTORY
static DEVICE_ATTR(dhr_sensor_info, 0444,
accel_dhr_sensor_info_show, NULL);
#else
static DEVICE_ATTR(dhr_sensor_info, 0440,
accel_dhr_sensor_info_show, NULL);
#endif
static DEVICE_ATTR(turn_over_crash, 0664,
accel_turn_over_crash_show, accel_turn_over_crash_store);
static DEVICE_ATTR(vib_onoff, 0664,
vib_onoff_show, vib_onoff_store);
static struct device_attribute *acc_attrs[] = {
&dev_attr_name,
&dev_attr_vendor,
&dev_attr_type,
&dev_attr_calibration,
&dev_attr_selftest,
&dev_attr_raw_data,
&dev_attr_reactive_alert,
&dev_attr_lowpassfilter,
&dev_attr_dhr_sensor_info,
&dev_attr_turn_over_crash,
&dev_attr_vib_onoff,
NULL,
};
void accel_factory_init_work(struct adsp_data *data)
{
schedule_delayed_work(&data->accel_cal_work, msecs_to_jiffies(8000));
}
EXPORT_SYMBOL(accel_factory_init_work);
int __init lsm6dso_accel_factory_init(void)
{
adsp_factory_register(MSG_ACCEL, acc_attrs);
#ifdef CONFIG_SEC_VIB_NOTIFIER
pdata_motor = kzalloc(sizeof(*pdata_motor), GFP_KERNEL);
if (pdata_motor == NULL)
return -ENOMEM;
pdata_motor->motor_nb.notifier_call = ssc_motor_notify,
pdata_motor->motor_nb.priority = 1,
sec_vib_notifier_register(&pdata_motor->motor_nb);
hrtimer_init(&pdata_motor->motor_stop_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pdata_motor->motor_stop_timer.function = motor_stop_timer_func;
pdata_motor->slpi_motor_wq =
create_singlethread_workqueue("slpi_motor_wq");
if (pdata_motor->slpi_motor_wq == NULL) {
pr_err("[FACTORY]: %s - could not create motor wq\n", __func__);
kfree(pdata_motor);
return -ENOMEM;
}
INIT_WORK(&pdata_motor->work_slpi_motor, slpi_motor_work_func);
atomic_set(&pdata_motor->motor_state, MOTOR_OFF);
#endif
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
pdata->accel_wq = create_singlethread_workqueue("accel_wq");
INIT_WORK(&pdata->work_accel, accel_work_func);
pdata->lpf_onoff = true;
pdata->st_complete = true;
atomic_set(&pdata->vib_state, MOTOR_OFF);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit lsm6dso_accel_factory_exit(void)
{
adsp_factory_unregister(MSG_ACCEL);
#ifdef CONFIG_SEC_VIB_NOTIFIER
if (atomic_read(&pdata_motor->motor_state) == MOTOR_ON)
hrtimer_cancel(&pdata_motor->motor_stop_timer);
if (pdata_motor != NULL && pdata_motor->slpi_motor_wq != NULL) {
cancel_work_sync(&pdata_motor->work_slpi_motor);
destroy_workqueue(pdata_motor->slpi_motor_wq);
pdata_motor->slpi_motor_wq = NULL;
kfree(pdata_motor);
}
#endif
pr_info("[FACTORY] %s\n", __func__);
}

View File

@@ -0,0 +1,263 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define VENDOR "STM"
#if IS_ENABLED(CONFIG_LSM6DSV_FACTORY)
#define CHIP_ID "LSM6DSV"
#else
#define CHIP_ID "LSM6DSO"
#endif
#define ST_PASS 1
#define ST_FAIL 0
#define STARTUP_BIT_FAIL 2
#define OIS_ST_BIT_SET 3
#define G_ZRL_DELTA_FAIL 4
#define OIS_RW_FAIL 5
#define SFLP_FAIL 6
#define SELFTEST_REVISED 1
static ssize_t gyro_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t gyro_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t selftest_revised_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", SELFTEST_REVISED);
}
static ssize_t gyro_power_off(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY]: %s\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", 1);
}
static ssize_t gyro_power_on(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY]: %s\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", 1);
}
static ssize_t gyro_temp_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_GYRO_TEMP, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_GYRO_TEMP)
&& cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_GYRO_TEMP);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-99\n");
}
pr_info("[FACTORY] %s: gyro_temp = %d\n", __func__,
data->msg_buf[MSG_GYRO_TEMP][0]);
return snprintf(buf, PAGE_SIZE, "%d\n",
data->msg_buf[MSG_GYRO_TEMP][0]);
}
static ssize_t gyro_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int st_diff_res = ST_FAIL;
int st_zro_res = ST_FAIL;
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_DIGITAL_HALL_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#elif IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_REF_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#endif
pr_info("[FACTORY] %s - start\n", __func__);
adsp_unicast(NULL, 0, MSG_GYRO, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_GYRO) &&
cnt++ < TIMEOUT_CNT)
usleep_range(30000, 30100); /* 30 * 200 = 6 sec */
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_GYRO);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
#ifdef CONFIG_SEC_FACTORY
panic("sensor force crash : gyro selftest timeout\n");
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973) ||\
IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE,
"0,0,0,0,0,0,0,0,0,0,0,0,%d,%d\n",
ST_FAIL, ST_FAIL);
}
if (data->msg_buf[MSG_GYRO][1] != 0) {
pr_info("[FACTORY] %s - failed(%d, %d)\n", __func__,
data->msg_buf[MSG_GYRO][1],
data->msg_buf[MSG_GYRO][5]);
pr_info("[FACTORY]: %s - %d,%d,%d\n", __func__,
data->msg_buf[MSG_GYRO][2],
data->msg_buf[MSG_GYRO][3],
data->msg_buf[MSG_GYRO][4]);
if (data->msg_buf[MSG_GYRO][5] == OIS_ST_BIT_SET)
pr_info("[FACTORY] %s - OIS_ST_BIT fail\n", __func__);
else if (data->msg_buf[MSG_GYRO][5] == G_ZRL_DELTA_FAIL)
pr_info("[FACTORY] %s - ZRL Delta fail\n", __func__);
else if (data->msg_buf[MSG_GYRO][5] == OIS_RW_FAIL)
pr_info("[FACTORY] %s - Gyro OIS read write fail\n", __func__);
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973) ||\
IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
data->msg_buf[MSG_GYRO][2],
data->msg_buf[MSG_GYRO][3],
data->msg_buf[MSG_GYRO][4]);
} else {
st_zro_res = ST_PASS;
}
if (!data->msg_buf[MSG_GYRO][5])
st_diff_res = ST_PASS;
else if (data->msg_buf[MSG_GYRO][5] == STARTUP_BIT_FAIL)
pr_info("[FACTORY] %s - Gyro Start Up Bit fail\n", __func__);
else if (data->msg_buf[MSG_GYRO][5] == OIS_RW_FAIL) {
pr_info("[FACTORY] %s - Gyro OIS read write fail\n", __func__);
st_diff_res = OIS_RW_FAIL;
}
else if (data->msg_buf[MSG_GYRO][5] == SFLP_FAIL) {
pr_info("[FACTORY] %s - SFLP sanity test fail\n", __func__);
st_diff_res = SFLP_FAIL;
}
pr_info("[FACTORY] %s - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
__func__,
data->msg_buf[MSG_GYRO][2], data->msg_buf[MSG_GYRO][3],
data->msg_buf[MSG_GYRO][4], data->msg_buf[MSG_GYRO][6],
data->msg_buf[MSG_GYRO][7], data->msg_buf[MSG_GYRO][8],
data->msg_buf[MSG_GYRO][9], data->msg_buf[MSG_GYRO][10],
data->msg_buf[MSG_GYRO][11], data->msg_buf[MSG_GYRO][12],
data->msg_buf[MSG_GYRO][13], data->msg_buf[MSG_GYRO][14],
st_diff_res, st_zro_res);
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973) ||\
IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_GYRO][2], data->msg_buf[MSG_GYRO][3],
data->msg_buf[MSG_GYRO][4], data->msg_buf[MSG_GYRO][6],
data->msg_buf[MSG_GYRO][7], data->msg_buf[MSG_GYRO][8],
data->msg_buf[MSG_GYRO][9], data->msg_buf[MSG_GYRO][10],
data->msg_buf[MSG_GYRO][11], data->msg_buf[MSG_GYRO][12],
data->msg_buf[MSG_GYRO][13], data->msg_buf[MSG_GYRO][14],
st_diff_res, st_zro_res);
}
static ssize_t trimmed_odr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_GYRO, 0, MSG_TYPE_GET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_REGISTER] & 1 << MSG_GYRO)
&& cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_REGISTER] &= ~(1 << MSG_GYRO);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "0\n");
}
pr_info("[FACTORY] %s: 0x63h = 0x%02x, trimmed_odr = %d Hz\n", __func__,
data->msg_buf[MSG_GYRO][0], data->msg_buf[MSG_GYRO][1]);
return snprintf(buf, PAGE_SIZE, "%d\n",
data->msg_buf[MSG_GYRO][1]);
}
static DEVICE_ATTR(name, 0444, gyro_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, gyro_vendor_show, NULL);
static DEVICE_ATTR(selftest, 0440, gyro_selftest_show, NULL);
static DEVICE_ATTR(power_on, 0444, gyro_power_on, NULL);
static DEVICE_ATTR(power_off, 0444, gyro_power_off, NULL);
static DEVICE_ATTR(temperature, 0440, gyro_temp_show, NULL);
static DEVICE_ATTR(selftest_revised, 0440, selftest_revised_show, NULL);
static DEVICE_ATTR(trimmed_odr, 0440, trimmed_odr_show, NULL);
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_revised,
&dev_attr_trimmed_odr,
NULL,
};
int __init lsm6dso_gyro_factory_init(void)
{
adsp_factory_register(MSG_GYRO, gyro_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit lsm6dso_gyro_factory_exit(void)
{
adsp_factory_unregister(MSG_GYRO);
pr_info("[FACTORY] %s\n", __func__);
}

View File

@@ -0,0 +1,694 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define VENDOR "STM"
#if IS_ENABLED(CONFIG_LSM6DSV_FACTORY)
#define CHIP_ID "LSM6DSVW"
#else
#define CHIP_ID "LSM6DSOW"
#endif
#define ACCEL_ST_TRY_CNT 3
#define ACCEL_FACTORY_CAL_CNT 20
#define ACCEL_RAW_DATA_CNT 3
#define MAX_ACCEL_1G 2048
#define PASS 0
#define STM_LSM6DSO_INT_CHECK_RUNNING 4
#define STM_LSM6DSV_INT_CHECK_SKIP_IBI 5
struct sub_accel_data {
struct work_struct work_accel;
struct workqueue_struct *accel_wq;
struct adsp_data *dev_data;
bool is_complete_cal;
bool lpf_onoff;
bool st_complete;
int32_t raw_data[ACCEL_RAW_DATA_CNT];
int32_t avg_data[ACCEL_RAW_DATA_CNT];
};
static struct sub_accel_data *pdata;
static ssize_t sub_accel_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t sub_accel_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t sensor_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", "ADSP");
}
int get_sub_accel_cal_data(struct adsp_data *data, int32_t *cal_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_ACCEL_SUB, 0, MSG_TYPE_GET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_CAL_DATA] & 1 << MSG_ACCEL_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_CAL_DATA] &= ~(1 << MSG_ACCEL_SUB);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return 0;
}
if (data->msg_buf[MSG_ACCEL_SUB][3] != ACCEL_RAW_DATA_CNT) {
pr_err("[FACTORY] %s: Reading Bytes Num %d!!!\n",
__func__, data->msg_buf[MSG_ACCEL_SUB][3]);
return 0;
}
cal_data[0] = data->msg_buf[MSG_ACCEL_SUB][0];
cal_data[1] = data->msg_buf[MSG_ACCEL_SUB][1];
cal_data[2] = data->msg_buf[MSG_ACCEL_SUB][2];
pr_info("[FACTORY] %s: %d, %d, %d, %d\n", __func__,
cal_data[0], cal_data[1], cal_data[2],
data->msg_buf[MSG_ACCEL_SUB][3]);
return data->msg_buf[MSG_ACCEL_SUB][3];
}
void set_sub_accel_cal_data(struct adsp_data *data)
{
uint8_t cnt = 0;
pr_info("[FACTORY] %s(1): %d, %d, %d\n", __func__, pdata->avg_data[0],
pdata->avg_data[1], pdata->avg_data[2]);
adsp_unicast(pdata->avg_data, sizeof(pdata->avg_data),
MSG_ACCEL_SUB, 0, MSG_TYPE_SET_CAL_DATA);
pr_info("[FACTORY] %s(2): %d, %d, %d\n", __func__, pdata->avg_data[0],
pdata->avg_data[1], pdata->avg_data[2]);
while (!(data->ready_flag[MSG_TYPE_SET_CAL_DATA] & 1 << MSG_ACCEL_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_CAL_DATA] &= ~(1 << MSG_ACCEL_SUB);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else if (data->msg_buf[MSG_ACCEL_SUB][0] != ACCEL_RAW_DATA_CNT) {
pr_err("[FACTORY] %s: Write Bytes Num %d!!!\n",
__func__, data->msg_buf[MSG_ACCEL_SUB][0]);
}
}
static ssize_t sub_accel_calibration_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t cal_data[ACCEL_RAW_DATA_CNT] = {0, };
int ret = 0;
mutex_lock(&data->accel_factory_mutex);
ret = get_sub_accel_cal_data(data, cal_data);
mutex_unlock(&data->accel_factory_mutex);
if (ret > 0) {
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
cal_data[0], cal_data[1], cal_data[2]);
if (cal_data[0] == 0 && cal_data[1] == 0 && cal_data[2] == 0)
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n",
0, 0, 0, 0);
else
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n",
true, cal_data[0], cal_data[1], cal_data[2]);
} else {
pr_err("[FACTORY] %s: get_sub_accel_cal_data fail\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n", 0, 0, 0, 0);
}
}
static ssize_t sub_accel_calibration_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
pdata->dev_data = data;
if (sysfs_streq(buf, "0")) {
mutex_lock(&data->accel_factory_mutex);
memset(pdata->avg_data, 0, sizeof(pdata->avg_data));
set_sub_accel_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
} else {
pdata->is_complete_cal = false;
queue_work(pdata->accel_wq, &pdata->work_accel);
while (pdata->is_complete_cal == false) {
pr_info("[FACTORY] %s: In factory cal\n", __func__);
msleep(20);
}
mutex_lock(&data->accel_factory_mutex);
set_sub_accel_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
}
return size;
}
static void sub_accel_work_func(struct work_struct *work)
{
struct sub_accel_data *data = container_of((struct work_struct *)work,
struct sub_accel_data, work_accel);
int i;
mutex_lock(&data->dev_data->accel_factory_mutex);
memset(pdata->avg_data, 0, sizeof(pdata->avg_data));
adsp_unicast(pdata->avg_data, sizeof(pdata->avg_data),
MSG_ACCEL_SUB, 0, MSG_TYPE_SET_CAL_DATA);
msleep(30); /* for init of bias */
for (i = 0; i < ACCEL_FACTORY_CAL_CNT; i++) {
msleep(20);
get_sub_accel_raw_data(pdata->raw_data);
pdata->avg_data[0] += pdata->raw_data[0];
pdata->avg_data[1] += pdata->raw_data[1];
pdata->avg_data[2] += pdata->raw_data[2];
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
pdata->raw_data[0], pdata->raw_data[1],
pdata->raw_data[2]);
}
for (i = 0; i < ACCEL_RAW_DATA_CNT; i++) {
pdata->avg_data[i] /= ACCEL_FACTORY_CAL_CNT;
pr_info("[FACTORY] %s: avg : %d\n",
__func__, pdata->avg_data[i]);
}
if (pdata->avg_data[2] > 0)
pdata->avg_data[2] -= MAX_ACCEL_1G;
else if (pdata->avg_data[2] < 0)
pdata->avg_data[2] += MAX_ACCEL_1G;
mutex_unlock(&data->dev_data->accel_factory_mutex);
pdata->is_complete_cal = true;
}
void sub_accel_cal_work_func(struct work_struct *work)
{
struct adsp_data *data = container_of((struct delayed_work *)work,
struct adsp_data, sub_accel_cal_work);
int ret = 0;
mutex_lock(&data->accel_factory_mutex);
ret = get_sub_accel_cal_data(data, pdata->avg_data);
mutex_unlock(&data->accel_factory_mutex);
if (ret > 0) {
pr_info("[FACTORY] %s: ret(%d) %d, %d, %d\n", __func__, ret,
pdata->avg_data[0],
pdata->avg_data[1],
pdata->avg_data[2]);
mutex_lock(&data->accel_factory_mutex);
set_sub_accel_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
} else {
pr_err("[FACTORY] %s: get_accel_cal_data fail (%d)\n",
__func__, ret);
}
}
static ssize_t sub_accel_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int retry = 0;
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_DIGITAL_HALL_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#elif IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_REF_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#endif
pdata->st_complete = false;
RETRY_ACCEL_SELFTEST:
adsp_unicast(NULL, 0, MSG_ACCEL_SUB, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_ACCEL_SUB) &&
cnt++ < TIMEOUT_CNT)
msleep(26);
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_ACCEL_SUB);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
data->msg_buf[MSG_ACCEL_SUB][1] = -1;
#ifdef CONFIG_SEC_FACTORY
panic("sensor force crash : sub accel selftest timeout\n");
#endif
}
pr_info("[FACTORY] %s : init = %d, result = %d, XYZ = %d, %d, %d, nXYZ = %d, %d, %d\n",
__func__, data->msg_buf[MSG_ACCEL_SUB][0],
data->msg_buf[MSG_ACCEL_SUB][1], data->msg_buf[MSG_ACCEL_SUB][2],
data->msg_buf[MSG_ACCEL_SUB][3], data->msg_buf[MSG_ACCEL_SUB][4],
data->msg_buf[MSG_ACCEL_SUB][5], data->msg_buf[MSG_ACCEL_SUB][6],
data->msg_buf[MSG_ACCEL_SUB][7]);
pr_info("[FACTORY] %s : pre/postP/postN [%d, %d, %d/%d, %d, %d/%d, %d, %d], comm_err_cnt %d/%d/%d\n",
__func__, data->msg_buf[MSG_ACCEL_SUB][8],
data->msg_buf[MSG_ACCEL_SUB][9], data->msg_buf[MSG_ACCEL_SUB][10],
data->msg_buf[MSG_ACCEL_SUB][11], data->msg_buf[MSG_ACCEL_SUB][12],
data->msg_buf[MSG_ACCEL_SUB][13], data->msg_buf[MSG_ACCEL_SUB][14],
data->msg_buf[MSG_ACCEL_SUB][15], data->msg_buf[MSG_ACCEL_SUB][16],
data->msg_buf[MSG_ACCEL_SUB][17], data->msg_buf[MSG_ACCEL_SUB][18],
data->msg_buf[MSG_ACCEL_SUB][19]);
if (data->msg_buf[MSG_ACCEL_SUB][1] == 1) {
pr_info("[FACTORY] %s : Pass - result = %d, retry = %d\n",
__func__, data->msg_buf[MSG_ACCEL_SUB][1], retry);
} else {
data->msg_buf[MSG_ACCEL_SUB][1] = -5;
pr_err("[FACTORY] %s : Fail - result = %d, retry = %d\n",
__func__, data->msg_buf[MSG_ACCEL_SUB][1], retry);
if (retry < ACCEL_ST_TRY_CNT) {
retry++;
msleep(50);
cnt = 0;
pr_info("[FACTORY] %s: retry\n", __func__);
goto RETRY_ACCEL_SELFTEST;
}
}
pdata->st_complete = true;
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973) ||\
IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_ACCEL_SUB][1],
(int)abs(data->msg_buf[MSG_ACCEL_SUB][2]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB][3]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB][4]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB][5]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB][6]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB][7]));
}
static ssize_t sub_accel_raw_data_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t raw_data[ACCEL_RAW_DATA_CNT] = {0, };
static int32_t prev_raw_data[ACCEL_RAW_DATA_CNT] = {0, };
int ret = 0;
#ifdef CONFIG_SEC_FACTORY
static int same_cnt;
#endif
if (pdata->st_complete == false) {
pr_info("[FACTORY] %s: selftest is running\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
raw_data[0], raw_data[1], raw_data[2]);
}
mutex_lock(&data->accel_factory_mutex);
ret = get_sub_accel_raw_data(raw_data);
mutex_unlock(&data->accel_factory_mutex);
#ifdef CONFIG_SEC_FACTORY
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
raw_data[0], raw_data[1], raw_data[2]);
if (prev_raw_data[0] == raw_data[0] &&
prev_raw_data[1] == raw_data[1] &&
prev_raw_data[2] == raw_data[2]) {
same_cnt++;
pr_info("[FACTORY] %s: same_cnt %d\n", __func__, same_cnt);
if (same_cnt >= 20)
panic("sensor force crash : sub accel raw_data stuck\n");
} else
same_cnt = 0;
#endif
if (!ret) {
memcpy(prev_raw_data, raw_data, sizeof(int32_t) * 3);
} else if (!pdata->lpf_onoff) {
pr_err("[FACTORY] %s: using prev data!!!\n", __func__);
memcpy(raw_data, prev_raw_data, sizeof(int32_t) * 3);
} else {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
}
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
raw_data[0], raw_data[1], raw_data[2]);
}
static ssize_t sub_accel_reactive_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
bool success = false;
int32_t msg_buf = 0;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL_SUB,
0, MSG_TYPE_GET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_REGISTER] & 1 << MSG_ACCEL_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_REGISTER] &= ~(1 << MSG_ACCEL_SUB);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", (int)success);
}
pr_info("[FACTORY]: %s - %d\n", __func__,
data->msg_buf[MSG_ACCEL_SUB][0]);
if (data->msg_buf[MSG_ACCEL_SUB][0] == 0)
success = true;
if (data->msg_buf[MSG_ACCEL_SUB][0] == STM_LSM6DSV_INT_CHECK_SKIP_IBI) {
pr_info("[FACTORY]: %s - IBI mode. Ignore Interrupt Check Test\n", __func__);
success = true;
}
return snprintf(buf, PAGE_SIZE, "%d\n", (int)success);
}
static ssize_t sub_accel_reactive_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t msg_buf;
uint8_t cnt = 0;
if (sysfs_streq(buf, "1"))
pr_info("[FACTORY]: %s - on\n", __func__);
else if (sysfs_streq(buf, "0"))
pr_info("[FACTORY]: %s - off\n", __func__);
else if (sysfs_streq(buf, "2")) {
pr_info("[FACTORY]: %s - factory\n", __func__);
msg_buf = 1;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL_SUB,
0, MSG_TYPE_GET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_REGISTER] & 1 << MSG_ACCEL_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_REGISTER] &= ~(1 << MSG_ACCEL_SUB);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return size;
}
if (data->msg_buf[MSG_ACCEL_SUB][0] == STM_LSM6DSO_INT_CHECK_RUNNING)
pr_info("[FACTORY]: %s - STM_LSM6DSO_INT_CHECK_RUNNING\n", __func__);
else if (data->msg_buf[MSG_ACCEL_SUB][0] == STM_LSM6DSV_INT_CHECK_SKIP_IBI)
pr_info("[FACTORY]: %s - IBI mode. Ignore Interrupt Check Test\n", __func__);
else
pr_info("[FACTORY]: %s - Something wrong\n", __func__);
}
return size;
}
static ssize_t sub_accel_lowpassfilter_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int32_t msg_buf;
if (sysfs_streq(buf, "1")) {
msg_buf = 1;
} else if (sysfs_streq(buf, "0")) {
msg_buf = 0;
#ifdef CONFIG_SEC_FACTORY
} else if (sysfs_streq(buf, "2")) {
msg_buf = 2;
pr_info("[FACTORY] %s: Pretest\n", __func__);
#endif
} else {
pr_info("[FACTORY] %s: wrong value\n", __func__);
return size;
}
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL_SUB,
0, MSG_TYPE_SET_ACCEL_LPF);
while (!(data->ready_flag[MSG_TYPE_SET_ACCEL_LPF] & 1 << MSG_ACCEL_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_ACCEL_LPF] &= ~(1 << MSG_ACCEL_SUB);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return size;
}
pdata->lpf_onoff = (bool)data->msg_buf[MSG_ACCEL_SUB][0];
#if IS_ENABLED(CONFIG_LSM6DSV_FACTORY)
pr_info("[FACTORY] %s: %d, 0x0A:%02x 0x0D:%02x 0x18:%02x\n", __func__,
data->msg_buf[MSG_ACCEL_SUB][0], data->msg_buf[MSG_ACCEL_SUB][1],
data->msg_buf[MSG_ACCEL_SUB][2], data->msg_buf[MSG_ACCEL_SUB][3]);
#else
pr_info("[FACTORY] %s: %d, 0x0A:%02x 0x0D:%02x 0x10:%02x\n", __func__,
data->msg_buf[MSG_ACCEL_SUB][0], data->msg_buf[MSG_ACCEL_SUB][1],
data->msg_buf[MSG_ACCEL_SUB][2], data->msg_buf[MSG_ACCEL_SUB][3]);
#endif
return size;
}
static ssize_t sub_accel_dhr_sensor_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
char ctrl1_xl = 0;
uint8_t fullscale = 0;
adsp_unicast(NULL, 0, MSG_ACCEL_SUB, 0, MSG_TYPE_GET_DHR_INFO);
while (!(data->ready_flag[MSG_TYPE_GET_DHR_INFO] & 1 << MSG_ACCEL_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_DHR_INFO] &= ~(1 << MSG_ACCEL_SUB);
if (cnt >= TIMEOUT_CNT)
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
ctrl1_xl = data->msg_buf[MSG_ACCEL_SUB][16];
ctrl1_xl &= 0xC;
switch (ctrl1_xl) {
case 0xC:
fullscale = 8;
break;
case 0x8:
fullscale = 4;
break;
case 0x4:
fullscale = 16;
break;
case 0:
fullscale = 2;
break;
default:
break;
}
pr_info("[FACTORY] %s: f/s %u\n", __func__, fullscale);
return snprintf(buf, PAGE_SIZE, "\"FULL_SCALE\":\"%uG\"\n", fullscale);
}
#if IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
static ssize_t ref_angle_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int32_t result = PASS;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(NULL, 0, MSG_REF_ANGLE, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_REF_ANGLE) &&
cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_REF_ANGLE);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-1\n");
}
pr_info("[FACTORY] %s - st %d/%d, akm %d/%d, lf %d/%d, hall %d/%d/%d(uT)\n",
__func__, data->msg_buf[MSG_REF_ANGLE][0],
data->msg_buf[MSG_REF_ANGLE][1],
data->msg_buf[MSG_REF_ANGLE][2],
data->msg_buf[MSG_REF_ANGLE][3],
data->msg_buf[MSG_REF_ANGLE][4],
data->msg_buf[MSG_REF_ANGLE][5],
data->msg_buf[MSG_REF_ANGLE][6],
data->msg_buf[MSG_REF_ANGLE][7],
data->msg_buf[MSG_REF_ANGLE][8]);
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
data->msg_buf[MSG_REF_ANGLE][0], result);
}
static ssize_t angle_read_data_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(NULL, 0, MSG_REF_ANGLE, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_REF_ANGLE) &&
cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_REF_ANGLE);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-1\n");
}
pr_info("[FACTORY] %s - st %d/%d, akm %d/%d, lf %d/%d, hall %d/%d/%d(uT)\n",
__func__, data->msg_buf[MSG_REF_ANGLE][0],
data->msg_buf[MSG_REF_ANGLE][1],
data->msg_buf[MSG_REF_ANGLE][2],
data->msg_buf[MSG_REF_ANGLE][3],
data->msg_buf[MSG_REF_ANGLE][4],
data->msg_buf[MSG_REF_ANGLE][5],
data->msg_buf[MSG_REF_ANGLE][6],
data->msg_buf[MSG_REF_ANGLE][7],
data->msg_buf[MSG_REF_ANGLE][8]);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_REF_ANGLE][0],
data->msg_buf[MSG_REF_ANGLE][1],
data->msg_buf[MSG_REF_ANGLE][2],
data->msg_buf[MSG_REF_ANGLE][3],
data->msg_buf[MSG_REF_ANGLE][4],
data->msg_buf[MSG_REF_ANGLE][5],
data->msg_buf[MSG_REF_ANGLE][6],
data->msg_buf[MSG_REF_ANGLE][7],
data->msg_buf[MSG_REF_ANGLE][8]);
}
#endif
static DEVICE_ATTR(name, 0444, sub_accel_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, sub_accel_vendor_show, NULL);
static DEVICE_ATTR(type, 0444, sensor_type_show, NULL);
static DEVICE_ATTR(calibration, 0664,
sub_accel_calibration_show, sub_accel_calibration_store);
static DEVICE_ATTR(selftest, 0440,
sub_accel_selftest_show, NULL);
static DEVICE_ATTR(raw_data, 0444, sub_accel_raw_data_show, NULL);
static DEVICE_ATTR(reactive_alert, 0664,
sub_accel_reactive_show, sub_accel_reactive_store);
static DEVICE_ATTR(lowpassfilter, 0220,
NULL, sub_accel_lowpassfilter_store);
#ifdef CONFIG_SEC_FACTORY
static DEVICE_ATTR(dhr_sensor_info, 0444,
sub_accel_dhr_sensor_info_show, NULL);
#else
static DEVICE_ATTR(dhr_sensor_info, 0440,
sub_accel_dhr_sensor_info_show, NULL);
#endif
#if IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
static DEVICE_ATTR(ref_angle, 0444, ref_angle_show, NULL);
static DEVICE_ATTR(read_angle_data, 0444, angle_read_data_show, NULL);
#endif
static struct device_attribute *acc_attrs[] = {
&dev_attr_name,
&dev_attr_vendor,
&dev_attr_type,
&dev_attr_calibration,
&dev_attr_selftest,
&dev_attr_raw_data,
&dev_attr_reactive_alert,
&dev_attr_lowpassfilter,
&dev_attr_dhr_sensor_info,
#if IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
&dev_attr_ref_angle,
&dev_attr_read_angle_data,
#endif
NULL,
};
void sub_accel_factory_init_work(struct adsp_data *data)
{
schedule_delayed_work(&data->sub_accel_cal_work, msecs_to_jiffies(8000));
}
int __init lsm6dso_sub_accel_factory_init(void)
{
adsp_factory_register(MSG_ACCEL_SUB, acc_attrs);
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
pdata->accel_wq = create_singlethread_workqueue("sub_accel_wq");
INIT_WORK(&pdata->work_accel, sub_accel_work_func);
pdata->lpf_onoff = true;
pdata->st_complete = true;
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit lsm6dso_sub_accel_factory_exit(void)
{
adsp_factory_unregister(MSG_ACCEL_SUB);
pr_info("[FACTORY] %s\n", __func__);
}

View File

@@ -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 <linux/init.h>
#include <linux/module.h>
#include "adsp.h"
#define VENDOR "STM"
#if IS_ENABLED(CONFIG_LSM6DSV_FACTORY)
#define CHIP_ID "LSM6DSVW"
#else
#define CHIP_ID "LSM6DSOW"
#endif
#define ST_PASS 1
#define ST_FAIL 0
#define STARTUP_BIT_FAIL 2
#define G_ZRL_DELTA_FAIL 4
#define SFLP_FAIL 6
#define SELFTEST_REVISED 1
static ssize_t sub_gyro_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t sub_gyro_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t selftest_revised_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", SELFTEST_REVISED);
}
static ssize_t gyro_power_off(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY]: %s\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", 1);
}
static ssize_t gyro_power_on(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY]: %s\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", 1);
}
static ssize_t sub_gyro_temp_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_GYRO_SUB_TEMP, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_GYRO_SUB_TEMP)
&& cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_GYRO_SUB_TEMP);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-99\n");
}
pr_info("[FACTORY] %s: sub_gyro_temp = %d\n", __func__,
data->msg_buf[MSG_GYRO_SUB_TEMP][0]);
return snprintf(buf, PAGE_SIZE, "%d\n",
data->msg_buf[MSG_GYRO_SUB_TEMP][0]);
}
static ssize_t sub_gyro_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int st_diff_res = ST_FAIL;
int st_zro_res = ST_FAIL;
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_DIGITAL_HALL_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#elif IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_REF_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#endif
pr_info("[FACTORY] %s - start", __func__);
adsp_unicast(NULL, 0, MSG_GYRO_SUB, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_GYRO_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(30000, 30100); /* 30 * 200 = 6 sec */
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_GYRO_SUB);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
#ifdef CONFIG_SEC_FACTORY
panic("sensor force crash : sub gyro selftest timeout\n");
#endif
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973) ||\
IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE,
"0,0,0,0,0,0,0,0,0,0,0,0,%d,%d\n",
ST_FAIL, ST_FAIL);
}
if (data->msg_buf[MSG_GYRO_SUB][1] != 0) {
pr_info("[FACTORY] %s - failed(%d, %d)\n", __func__,
data->msg_buf[MSG_GYRO_SUB][1],
data->msg_buf[MSG_GYRO_SUB][5]);
pr_info("[FACTORY]: %s - %d,%d,%d\n", __func__,
data->msg_buf[MSG_GYRO_SUB][2],
data->msg_buf[MSG_GYRO_SUB][3],
data->msg_buf[MSG_GYRO_SUB][4]);
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973) ||\
IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
if (data->msg_buf[MSG_GYRO_SUB][5] == G_ZRL_DELTA_FAIL)
pr_info("[FACTORY] %s - ZRL Delta fail\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
data->msg_buf[MSG_GYRO_SUB][2],
data->msg_buf[MSG_GYRO_SUB][3],
data->msg_buf[MSG_GYRO_SUB][4]);
} else {
st_zro_res = ST_PASS;
}
if (!data->msg_buf[MSG_GYRO_SUB][5])
st_diff_res = ST_PASS;
else if (data->msg_buf[MSG_GYRO_SUB][5] == STARTUP_BIT_FAIL)
pr_info("[FACTORY] %s - Gyro Start Up Bit fail\n", __func__);
else if (data->msg_buf[MSG_GYRO_SUB][5] == SFLP_FAIL) {
pr_info("[FACTORY] %s - SFLP sanity test fail\n", __func__);
st_diff_res = SFLP_FAIL;
}
pr_info("[FACTORY]: %s - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
__func__,
data->msg_buf[MSG_GYRO_SUB][2], data->msg_buf[MSG_GYRO_SUB][3],
data->msg_buf[MSG_GYRO_SUB][4], data->msg_buf[MSG_GYRO_SUB][6],
data->msg_buf[MSG_GYRO_SUB][7], data->msg_buf[MSG_GYRO_SUB][8],
data->msg_buf[MSG_GYRO_SUB][9], data->msg_buf[MSG_GYRO_SUB][10],
data->msg_buf[MSG_GYRO_SUB][11], data->msg_buf[MSG_GYRO_SUB][12],
data->msg_buf[MSG_GYRO_SUB][13], data->msg_buf[MSG_GYRO_SUB][14],
st_diff_res, st_zro_res);
#if IS_ENABLED(CONFIG_SUPPORT_AK09973) || defined(CONFIG_SUPPORT_AK09973) ||\
IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_GYRO_SUB][2], data->msg_buf[MSG_GYRO_SUB][3],
data->msg_buf[MSG_GYRO_SUB][4], data->msg_buf[MSG_GYRO_SUB][6],
data->msg_buf[MSG_GYRO_SUB][7], data->msg_buf[MSG_GYRO_SUB][8],
data->msg_buf[MSG_GYRO_SUB][9], data->msg_buf[MSG_GYRO_SUB][10],
data->msg_buf[MSG_GYRO_SUB][11], data->msg_buf[MSG_GYRO_SUB][12],
data->msg_buf[MSG_GYRO_SUB][13], data->msg_buf[MSG_GYRO_SUB][14],
st_diff_res, st_zro_res);
}
static DEVICE_ATTR(name, 0444, sub_gyro_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, sub_gyro_vendor_show, NULL);
static DEVICE_ATTR(selftest, 0440, sub_gyro_selftest_show, NULL);
static DEVICE_ATTR(power_on, 0444, gyro_power_on, NULL);
static DEVICE_ATTR(power_off, 0444, gyro_power_off, NULL);
static DEVICE_ATTR(temperature, 0440, sub_gyro_temp_show, NULL);
static DEVICE_ATTR(selftest_revised, 0440, selftest_revised_show, NULL);
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_revised,
NULL,
};
int __init lsm6dso_sub_gyro_factory_init(void)
{
adsp_factory_register(MSG_GYRO_SUB, gyro_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit lsm6dso_sub_gyro_factory_exit(void)
{
adsp_factory_unregister(MSG_GYRO_SUB);
pr_info("[FACTORY] %s\n", __func__);
}

View File

@@ -0,0 +1,256 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define VENDOR "AKM"
#define CHIP_ID "AK09918"
#define MAG_ST_TRY_CNT 3
#define ABS(x) (((x)>0)?(x):-(x))
#define AKM_ST_FAIL (-1)
static ssize_t sub_mag_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t sub_mag_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t sub_mag_check_cntl(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "OK\n");
}
static ssize_t sub_mag_check_registers(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
static ssize_t sub_mag_get_asa(struct device *dev,
struct device_attribute *attr, char *buf)
{
/* Do not have Fuserom */
return snprintf(buf, PAGE_SIZE, "%u,%u,%u\n", 128, 128, 128);
}
static ssize_t sub_mag_get_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
/* Do not have Fuserom */
return snprintf(buf, PAGE_SIZE, "%s\n", "OK");
}
static ssize_t sub_mag_raw_data_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_MAG_SUB, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_MAG_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_MAG_SUB);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "0,0,0\n");
}
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
data->msg_buf[MSG_MAG_SUB][0],
data->msg_buf[MSG_MAG_SUB][1],
data->msg_buf[MSG_MAG_SUB][2]);
}
static ssize_t sub_mag_raw_data_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
adsp_unicast(NULL, 0, MSG_MAG_CAL_SUB, 0, MSG_TYPE_FACTORY_ENABLE);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL_SUB, 0, MSG_TYPE_SET_CAL_DATA);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL_SUB, 0, MSG_TYPE_FACTORY_DISABLE);
return size;
}
static ssize_t sub_mag_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int retry = 0, i;
int abs_adc_sum = 0, abs_adc_x = 0, abs_adc_y = 0, abs_adc_z = 0;
int st_status = 0;
RETRY_MAG_SELFTEST:
pr_info("[FACTORY] %s - start\n", __func__);
adsp_unicast(NULL, 0, MSG_MAG_SUB, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_MAG_SUB) &&
cnt++ < TIMEOUT_CNT)
msleep(26);
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_MAG_SUB);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
data->msg_buf[MSG_MAG_SUB][0] = -1;
#ifdef CONFIG_SEC_FACTORY
panic("force crash : sensor selftest timeout\n");
#endif
}
if (!(data->msg_buf[MSG_MAG_SUB][0] == 0)) {
if (retry < MAG_ST_TRY_CNT) {
retry++;
for (i = 0; i < 10; i++)
data->msg_buf[MSG_MAG_SUB][i] = 0;
msleep(100);
cnt = 0;
pr_info("[FACTORY] %s - retry %d\n", __func__, retry);
goto RETRY_MAG_SELFTEST;
}
adsp_unicast(NULL, 0, MSG_MAG_CAL_SUB, 0, MSG_TYPE_FACTORY_ENABLE);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL_SUB, 0, MSG_TYPE_SET_CAL_DATA);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL_SUB, 0, MSG_TYPE_FACTORY_DISABLE);
return snprintf(buf, PAGE_SIZE, "-1,0,0,0,0,0,0,0,0,0\n");
}
if (data->msg_buf[MSG_MAG_SUB][1] != 0) {
pr_info("[FACTORY] %s - msg_buf[1] 0x%x\n", __func__, data->msg_buf[MSG_MAG_SUB][1]);
st_status = AKM_ST_FAIL;
}
pr_info("[FACTORY] status=%d, st_status=%d, st_xyz=%d,%d,%d, dac=%d, adc=%d, adc_xyz=%d,%d,%d\n",
data->msg_buf[MSG_MAG_SUB][0], st_status,
data->msg_buf[MSG_MAG_SUB][2], data->msg_buf[MSG_MAG_SUB][3],
data->msg_buf[MSG_MAG_SUB][4], data->msg_buf[MSG_MAG_SUB][5],
data->msg_buf[MSG_MAG_SUB][6], data->msg_buf[MSG_MAG_SUB][7],
data->msg_buf[MSG_MAG_SUB][8], data->msg_buf[MSG_MAG_SUB][9]);
abs_adc_x = ABS(data->msg_buf[MSG_MAG_SUB][7]);
abs_adc_y = ABS(data->msg_buf[MSG_MAG_SUB][8]);
abs_adc_z = ABS(data->msg_buf[MSG_MAG_SUB][9]);
abs_adc_sum = abs_adc_x + abs_adc_y + abs_adc_z;
if (abs_adc_sum >= 26666) {
pr_info("[FACTORY] abs_adc_sum is higher then 40Gauss\n");
st_status = AKM_ST_FAIL;
}
adsp_unicast(NULL, 0, MSG_MAG_CAL_SUB, 0, MSG_TYPE_FACTORY_ENABLE);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL_SUB, 0, MSG_TYPE_SET_CAL_DATA);
msleep(20);
adsp_unicast(NULL, 0, MSG_MAG_CAL_SUB, 0, MSG_TYPE_FACTORY_DISABLE);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_MAG_SUB][0], st_status,
data->msg_buf[MSG_MAG_SUB][2], data->msg_buf[MSG_MAG_SUB][3],
data->msg_buf[MSG_MAG_SUB][4], data->msg_buf[MSG_MAG_SUB][5],
data->msg_buf[MSG_MAG_SUB][6], data->msg_buf[MSG_MAG_SUB][7],
data->msg_buf[MSG_MAG_SUB][8], data->msg_buf[MSG_MAG_SUB][9]);
}
static ssize_t sub_mag_dhr_sensor_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_MAG_SUB, 0, MSG_TYPE_GET_DHR_INFO);
while (!(data->ready_flag[MSG_TYPE_GET_DHR_INFO] & 1 << MSG_MAG_SUB) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_DHR_INFO] &= ~(1 << MSG_MAG_SUB);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else {
pr_info("[FACTORY] %s - [00h-03h] %02x,%02x,%02x,%02x [10h-16h,18h] %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x [30h-32h] %02x,%02x,%02x\n",
__func__,
data->msg_buf[MSG_MAG_SUB][0], data->msg_buf[MSG_MAG_SUB][1],
data->msg_buf[MSG_MAG_SUB][2], data->msg_buf[MSG_MAG_SUB][3],
data->msg_buf[MSG_MAG_SUB][4], data->msg_buf[MSG_MAG_SUB][5],
data->msg_buf[MSG_MAG_SUB][6], data->msg_buf[MSG_MAG_SUB][7],
data->msg_buf[MSG_MAG_SUB][8], data->msg_buf[MSG_MAG_SUB][9],
data->msg_buf[MSG_MAG_SUB][10], data->msg_buf[MSG_MAG_SUB][11],
data->msg_buf[MSG_MAG_SUB][12], data->msg_buf[MSG_MAG_SUB][13],
data->msg_buf[MSG_MAG_SUB][14]);
}
return snprintf(buf, PAGE_SIZE, "%s\n", "Done");
}
static DEVICE_ATTR(name, 0444, sub_mag_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, sub_mag_vendor_show, NULL);
static DEVICE_ATTR(raw_data, 0664, sub_mag_raw_data_show, sub_mag_raw_data_store);
static DEVICE_ATTR(dac, 0444, sub_mag_check_cntl, NULL);
static DEVICE_ATTR(chk_registers, 0444, sub_mag_check_registers, NULL);
static DEVICE_ATTR(selftest, 0440, sub_mag_selftest_show, NULL);
static DEVICE_ATTR(asa, 0444, sub_mag_get_asa, NULL);
static DEVICE_ATTR(status, 0444, sub_mag_get_status, NULL);
#ifdef CONFIG_SEC_FACTORY
static DEVICE_ATTR(dhr_sensor_info, 0444, sub_mag_dhr_sensor_info_show, NULL);
#else
static DEVICE_ATTR(dhr_sensor_info, 0440, sub_mag_dhr_sensor_info_show, NULL);
#endif
static struct device_attribute *sub_mag_attrs[] = {
&dev_attr_name,
&dev_attr_vendor,
&dev_attr_raw_data,
&dev_attr_dac,
&dev_attr_chk_registers,
&dev_attr_selftest,
&dev_attr_asa,
&dev_attr_status,
&dev_attr_dhr_sensor_info,
NULL,
};
int mag_sub_factory_init(void)
{
adsp_factory_register(MSG_MAG_SUB, sub_mag_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void mag_sub_factory_exit(void)
{
adsp_factory_unregister(MSG_MAG_SUB);
pr_info("[FACTORY] %s\n", __func__);
}

View File

@@ -0,0 +1,436 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define CALIBRATION_FILE_PATH "/efs/FactoryApp/baro_delta"
#define PR_MAX 8388607 /* 24 bit 2'compl */
#define PR_MIN -8388608
#define SNS_SUCCESS 0
#define ST_PASS 1
#define ST_FAIL 0
#define PRESS_DEVICE_LIST_MAX 5
enum {
OPTION_TYPE_PRESS_GET_DEVICE_ID,
OPTION_TYPE_PRESS_MAX
};
static int sea_level_pressure;
static int pressure_cal;
static const struct device_id_t press_device_list[PRESS_DEVICE_LIST_MAX] = {
/* ID, Vendor, Name */
{0x00, "Unknown", "Unknown"},
{0xB1, "STM", "LPS22HB"},
{0xB3, "STM", "LPS22HH"},
{0xB4, "STM", "LPS22DF"},
{0x50, "Bosch", "BMP580"}
};
static void press_get_device_id(struct adsp_data *data)
{
int32_t cmd = OPTION_TYPE_PRESS_GET_DEVICE_ID, i;
int32_t device_index = UNKNOWN_INDEX;
uint8_t cnt = 0, device_id = 0;
adsp_unicast(&cmd, sizeof(cmd), MSG_PRESSURE, 0, MSG_TYPE_OPTION_DEFINE);
while (!(data->ready_flag[MSG_TYPE_OPTION_DEFINE]
& 1 << MSG_PRESSURE) && cnt++ < TIMEOUT_CNT)
usleep_range(1000, 1100);
data->ready_flag[MSG_TYPE_OPTION_DEFINE] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT)
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
else
device_id = (uint8_t)data->msg_buf[MSG_PRESSURE][2];
pr_err("[FACTORY] %s: device_id : %d,%d,%d,%d\n", __func__, device_id,
(int)data->msg_buf[MSG_PRESSURE][0],
(int)data->msg_buf[MSG_PRESSURE][1],
(int)data->msg_buf[MSG_PRESSURE][2]);
if (device_id == 0) {
pr_err("[FACTORY] %s: No information\n", __func__);
} else {
for (i = 0; i < PRESS_DEVICE_LIST_MAX; i++)
if (device_id == press_device_list[i].device_id)
break;
if (i >= PRESS_DEVICE_LIST_MAX)
pr_err("[FACTORY] %s: Unknown ID - (0x%x)\n",
__func__, device_id);
else
device_index = i;
}
memcpy(data->press_device_vendor,
press_device_list[device_index].device_vendor,
sizeof(char) * DEVICE_INFO_LENGTH);
memcpy(data->press_device_name,
press_device_list[device_index].device_name,
sizeof(char) * DEVICE_INFO_LENGTH);
pr_info("[FACTORY] %s: Device ID - %s(%s)\n", __func__,
data->press_device_name, data->press_device_vendor);
}
static ssize_t pressure_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
if (!strcmp(data->press_device_vendor, press_device_list[0].device_vendor))
press_get_device_id(data);
return snprintf(buf, PAGE_SIZE, "%s\n", data->press_device_vendor);
}
static ssize_t pressure_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
if (!strcmp(data->press_device_name, press_device_list[0].device_name))
press_get_device_id(data);
return snprintf(buf, PAGE_SIZE, "%s\n", data->press_device_name);
}
static ssize_t sea_level_pressure_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", sea_level_pressure);
}
static ssize_t sea_level_pressure_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
if (sscanf(buf, "%10d", &sea_level_pressure) != 1) {
pr_err("[FACTORY] %s: sscanf error\n", __func__);
return size;
}
sea_level_pressure = sea_level_pressure / 100;
pr_info("[FACTORY] %s: sea_level_pressure = %d\n", __func__,
sea_level_pressure);
return size;
}
/*
int pressure_open_calibration(struct adsp_data *data)
{
int error = 0;
return error;
}
*/
static ssize_t pressure_cabratioin_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
schedule_delayed_work(&data->pressure_cal_work, 0);
return size;
}
static ssize_t pressure_cabratioin_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
//struct adsp_data *data = dev_get_drvdata(dev);
//pressure_open_calibration(data);
return snprintf(buf, PAGE_SIZE, "%d\n", pressure_cal);
}
static ssize_t temperature_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_PRESSURE_TEMP, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] &
1 << MSG_PRESSURE_TEMP) && cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_PRESSURE_TEMP);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-99\n");
}
return snprintf(buf, PAGE_SIZE, "%d\n",
data->msg_buf[MSG_PRESSURE_TEMP][0]);
}
static ssize_t selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_PRESSURE, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &
1 << MSG_PRESSURE) && cnt++ < TIMEOUT_CNT)
msleep(26);
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "0\n");
}
pr_info("[FACTORY] %s : P:%d, T:%d, RES:%d\n",
__func__, data->msg_buf[MSG_PRESSURE][0],
data->msg_buf[MSG_PRESSURE][1], data->msg_buf[MSG_PRESSURE][2]);
if (SNS_SUCCESS == data->msg_buf[MSG_PRESSURE][2])
return snprintf(buf, PAGE_SIZE, "%d\n", ST_PASS);
else
return snprintf(buf, PAGE_SIZE, "%d\n", ST_FAIL);
}
static ssize_t pressure_dhr_sensor_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int i = 0;
adsp_unicast(NULL, 0, MSG_PRESSURE, 0, MSG_TYPE_GET_DHR_INFO);
while (!(data->ready_flag[MSG_TYPE_GET_DHR_INFO] & 1 << MSG_PRESSURE) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_DHR_INFO] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else {
for (i = 0; i < 8; i++) {
pr_info("[FACTORY] %s - %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",
__func__,
data->msg_buf[MSG_PRESSURE][i * 16 + 0],
data->msg_buf[MSG_PRESSURE][i * 16 + 1],
data->msg_buf[MSG_PRESSURE][i * 16 + 2],
data->msg_buf[MSG_PRESSURE][i * 16 + 3],
data->msg_buf[MSG_PRESSURE][i * 16 + 4],
data->msg_buf[MSG_PRESSURE][i * 16 + 5],
data->msg_buf[MSG_PRESSURE][i * 16 + 6],
data->msg_buf[MSG_PRESSURE][i * 16 + 7],
data->msg_buf[MSG_PRESSURE][i * 16 + 8],
data->msg_buf[MSG_PRESSURE][i * 16 + 9],
data->msg_buf[MSG_PRESSURE][i * 16 + 10],
data->msg_buf[MSG_PRESSURE][i * 16 + 11],
data->msg_buf[MSG_PRESSURE][i * 16 + 12],
data->msg_buf[MSG_PRESSURE][i * 16 + 13],
data->msg_buf[MSG_PRESSURE][i * 16 + 14],
data->msg_buf[MSG_PRESSURE][i * 16 + 15]);
}
}
return snprintf(buf, PAGE_SIZE, "%s\n", "Done");
}
static ssize_t pressure_sw_offset_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int input = 0;
int sw_offset = 0;
int ret;
ret = kstrtoint(buf, 10, &input);
if (ret < 0) {
pr_err("[FACTORY] %s: kstrtoint fail\n", __func__);
return -EINVAL;
}
pr_info("[FACTORY] %s: write value = %d\n", __func__, input);
adsp_unicast(&input, sizeof(int),
MSG_PRESSURE, 0, MSG_TYPE_SET_THRESHOLD);
while (!(data->ready_flag[MSG_TYPE_SET_THRESHOLD] & 1 << MSG_PRESSURE) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_THRESHOLD] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else {
sw_offset = data->msg_buf[MSG_PRESSURE][0];
}
pr_info("[FACTORY] %s: sw_offset %d\n", __func__, sw_offset);
return size;
}
static ssize_t pressure_sw_offset_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_PRESSURE, 0, MSG_TYPE_GET_THRESHOLD);
while (!(data->ready_flag[MSG_TYPE_GET_THRESHOLD] &
1 << MSG_PRESSURE) && cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_THRESHOLD] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "0\n");
}
pr_info("[FACTORY] %s : sw_offset %d\n",
__func__, data->msg_buf[MSG_PRESSURE][0]);
return snprintf(buf, PAGE_SIZE, "%d\n", data->msg_buf[MSG_PRESSURE][0]);
}
static ssize_t pressure_esn_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_PRESSURE, 0, MSG_TYPE_GET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_REGISTER] &
1 << MSG_PRESSURE) && cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_REGISTER] &= ~(1 << MSG_PRESSURE);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "0\n");
}
pr_info("[FACTORY] %s : esn %02X%02X%02X%02X%02X%02X%02X%02X\n",
__func__, data->msg_buf[MSG_PRESSURE][0], data->msg_buf[MSG_PRESSURE][1],
data->msg_buf[MSG_PRESSURE][2], data->msg_buf[MSG_PRESSURE][3],
data->msg_buf[MSG_PRESSURE][4], data->msg_buf[MSG_PRESSURE][5],
data->msg_buf[MSG_PRESSURE][6], data->msg_buf[MSG_PRESSURE][7]);
return snprintf(buf, PAGE_SIZE, "%02X%02X%02X%02X%02X%02X%02X%02X\n",
data->msg_buf[MSG_PRESSURE][0], data->msg_buf[MSG_PRESSURE][1],
data->msg_buf[MSG_PRESSURE][2], data->msg_buf[MSG_PRESSURE][3],
data->msg_buf[MSG_PRESSURE][4], data->msg_buf[MSG_PRESSURE][5],
data->msg_buf[MSG_PRESSURE][6], data->msg_buf[MSG_PRESSURE][7]);
}
static DEVICE_ATTR(vendor, 0444, pressure_vendor_show, NULL);
static DEVICE_ATTR(name, 0444, pressure_name_show, NULL);
static DEVICE_ATTR(calibration, 0664,
pressure_cabratioin_show, pressure_cabratioin_store);
static DEVICE_ATTR(sea_level_pressure, 0664,
sea_level_pressure_show, sea_level_pressure_store);
static DEVICE_ATTR(temperature, 0444, temperature_show, NULL);
static DEVICE_ATTR(selftest, 0444, selftest_show, NULL);
#ifdef CONFIG_SEC_FACTORY
static DEVICE_ATTR(dhr_sensor_info, 0444,
pressure_dhr_sensor_info_show, NULL);
#else
static DEVICE_ATTR(dhr_sensor_info, 0440,
pressure_dhr_sensor_info_show, NULL);
#endif
static DEVICE_ATTR(sw_offset, 0664,
pressure_sw_offset_show, pressure_sw_offset_store);
static DEVICE_ATTR(esn, 0440, pressure_esn_show, NULL);
static struct device_attribute *pressure_attrs[] = {
&dev_attr_vendor,
&dev_attr_name,
&dev_attr_calibration,
&dev_attr_sea_level_pressure,
&dev_attr_temperature,
&dev_attr_selftest,
&dev_attr_dhr_sensor_info,
&dev_attr_sw_offset,
&dev_attr_esn,
NULL,
};
void pressure_cal_work_func(struct work_struct *work)
{
struct adsp_data *data = container_of((struct delayed_work *)work,
struct adsp_data, pressure_cal_work);
int cnt = 0;
int temp = 0;
adsp_unicast(&temp, sizeof(temp), MSG_PRESSURE, 0, MSG_TYPE_SET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_SET_CAL_DATA] & 1 << MSG_PRESSURE) &&
cnt++ < 3)
msleep(30);
data->ready_flag[MSG_TYPE_SET_CAL_DATA] &= ~(1 << MSG_PRESSURE);
if (cnt >= 3) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return;
}
pressure_cal = data->msg_buf[MSG_PRESSURE][0];
if (!strcmp(data->press_device_vendor, press_device_list[0].device_vendor) ||
!strcmp(data->press_device_name, press_device_list[0].device_name))
press_get_device_id(data);
pr_info("[FACTORY] %s: pressure_cal = %d (lsb)\n", __func__, data->msg_buf[MSG_PRESSURE][0]);
}
EXPORT_SYMBOL(pressure_cal_work_func);
void pressure_factory_init_work(struct adsp_data *data)
{
memcpy(data->press_device_vendor,
press_device_list[0].device_vendor,
sizeof(char) * DEVICE_INFO_LENGTH);
memcpy(data->press_device_name,
press_device_list[0].device_name,
sizeof(char) * DEVICE_INFO_LENGTH);
schedule_delayed_work(&data->pressure_cal_work, msecs_to_jiffies(8000));
}
EXPORT_SYMBOL(pressure_factory_init_work);
int __init pressure_factory_init(void)
{
adsp_factory_register(MSG_PRESSURE, pressure_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit pressure_factory_exit(void)
{
adsp_factory_unregister(MSG_PRESSURE);
pr_info("[FACTORY] %s\n", __func__);
}

View File

@@ -0,0 +1,991 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#if IS_ENABLED(CONFIG_SUPPORT_CONTROL_PROX_LED_GPIO)
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#define PROX_LED_EN_GPIO 113
#endif
#define PROX_AVG_COUNT 40
#define PROX_ALERT_THRESHOLD 200
#define PROX_TH_READ 0
#define PROX_TH_WRITE 1
#define BUFFER_MAX 128
#define PROX_REG_START 0x80
#define PROX_DETECT_HIGH_TH 16368
#define PROX_DETECT_LOW_TH 1000
struct prox_data {
struct hrtimer prox_timer;
struct work_struct work_prox;
struct workqueue_struct *prox_wq;
struct adsp_data *dev_data;
int min;
int max;
int avg;
int val;
int offset;
int reg_backup[2];
int debug_info_cmd;
short avgwork_check;
short avgtimer_enabled;
};
enum {
PRX_THRESHOLD_DETECT_H,
PRX_THRESHOLD_HIGH_DETECT_L,
PRX_THRESHOLD_HIGH_DETECT_H,
PRX_THRESHOLD_RELEASE_L,
};
enum {
PROX_CMD_TYPE_GET_TRIM_CHECK,
PROX_CMD_TYPE_GET_CAL_DATA,
PROX_CMD_TYPE_INIT_CAL_DATA,
PROX_CMD_TYPE_LED_CONTROL,
PROX_CMD_TYPE_SAVE_CAL_DATA,
PROX_CMD_TYPE_TOUCH_PROX,
PROX_CMD_TYPE_MAX
};
static struct prox_data *pdata;
static int get_prox_sidx(struct adsp_data *data)
{
int ret = MSG_PROX;
#if defined(CONFIG_SUPPORT_DUAL_OPTIC) && !defined(CONFIG_SUPPORT_DUAL_OPTIC_BUT_SUPPORT_SINGLE_PROX)
switch (data->fac_fstate) {
case FSTATE_INACTIVE:
case FSTATE_FAC_INACTIVE:
ret = MSG_PROX;
break;
case FSTATE_ACTIVE:
case FSTATE_FAC_ACTIVE:
case FSTATE_FAC_INACTIVE_2:
ret = MSG_PROX_SUB;
break;
default:
break;
}
#endif
return ret;
}
#if IS_ENABLED(CONFIG_SUPPORT_PROX_CALIBRATION)
void prox_send_cal_data(struct adsp_data *data, uint16_t prox_idx, bool fac_cal)
{
int32_t msg = -1, cnt = 0, prox_cal;
#if IS_ENABLED(CONFIG_SUPPORT_CONTROL_PROX_LED_GPIO)
if (prox_idx == MSG_PROX) {
int led_gpio, ret;
struct device_node *np = of_find_node_by_name(NULL, "ssc_prox_led_en_gpio");
if (np == NULL) {
pr_info("[SSC_FAC] %s: ssc_prox_led_en_gpio is NULL\n", __func__);
} else {
led_gpio = of_get_named_gpio_flags(np, "qcom,prox_led-en-gpio",
0, NULL);
if (led_gpio >= 0) {
ret = gpio_request(led_gpio, NULL);
if (ret >= 0) {
pr_info("[SSC_FAC] %s: prox_led_en_gpio set\n",
__func__);
gpio_direction_output(led_gpio, 1);
gpio_free(led_gpio);
} else {
pr_err("[SSC_FAC] %s - gpio_request fail(%d)\n",
__func__, ret);
}
} else {
pr_err("[SSC_FAC] %s: prox_led_en_gpio fail(%d)\n",
__func__, led_gpio);
}
}
}
#endif
if (prox_idx == MSG_PROX)
prox_cal = data->prox_cal;
else
prox_cal = data->prox_sub_cal;
if (!fac_cal || (prox_cal == 0)) {
#if IS_ENABLED(CONFIG_SEC_FACTORY)
pr_info("[SSC_FAC] %s[%d]: No cal data (%d)\n",
__func__, (int)prox_idx - MSG_PROX, prox_cal);
#else
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(&msg, sizeof(int32_t),
prox_idx, 0, MSG_TYPE_SET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_SET_CAL_DATA] &
1 << prox_idx) && cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s[%d]: Timeout!!!\n",
__func__, prox_idx);
data->ready_flag[MSG_TYPE_SET_CAL_DATA] &= ~(1 << prox_idx);
mutex_unlock(&data->prox_factory_mutex);
pr_info("[SSC_FAC] %s[%d]: Excute in-use cal\n",
__func__, (int)prox_idx - MSG_PROX);
#endif
} else if (prox_cal > 0) {
mutex_lock(&data->prox_factory_mutex);
msg = prox_cal;
adsp_unicast(&msg, sizeof(int32_t),
prox_idx, 0, MSG_TYPE_SET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_SET_CAL_DATA] &
1 << prox_idx) && cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s[%d]: Timeout!!!\n",
__func__, (int)prox_idx - MSG_PROX);
data->ready_flag[MSG_TYPE_SET_CAL_DATA] &= ~(1 << prox_idx);
mutex_unlock(&data->prox_factory_mutex);
pr_info("[SSC_FAC] %s[%d]: Cal data: %d\n", __func__,
(int)prox_idx - MSG_PROX, msg);
} else {
pr_info("[SSC_FAC] %s[%d]: No cal data\n",
__func__, (int)prox_idx - MSG_PROX);
}
}
void prox_cal_init_work(struct adsp_data *data)
{
data->prox_cal = 0;
data->prox_sub_cal = 0;
}
#endif
static ssize_t prox_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
#if IS_ENABLED(CONFIG_LIGHT_FACTORY)
struct adsp_data *data = dev_get_drvdata(dev);
int32_t display_idx = (get_prox_sidx(data) == MSG_PROX) ? 0 : 1;
return snprintf(buf, PAGE_SIZE, "%s\n",
data->light_device_vendor[display_idx]);
#else
return snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
#endif
}
static ssize_t prox_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
#if IS_ENABLED(CONFIG_LIGHT_FACTORY)
struct adsp_data *data = dev_get_drvdata(dev);
int32_t display_idx = (get_prox_sidx(data) == MSG_PROX) ? 0 : 1;
return snprintf(buf, PAGE_SIZE, "%s\n",
data->light_device_name[display_idx]);
#else
return snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
#endif
}
int get_prox_raw_data(struct adsp_data *data, int *raw_data, int *offset)
{
uint8_t cnt = 0;
uint16_t prox_idx = get_prox_sidx(data);
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(NULL, 0, prox_idx, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << prox_idx);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
mutex_unlock(&data->prox_factory_mutex);
return -1;
}
*raw_data = data->msg_buf[prox_idx][0];
*offset = data->msg_buf[prox_idx][1];
mutex_unlock(&data->prox_factory_mutex);
return 0;
}
static ssize_t prox_raw_data_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
if (pdata->avgwork_check == 0)
get_prox_raw_data(data, &pdata->val, &pdata->offset);
return snprintf(buf, PAGE_SIZE, "%d\n", pdata->val);
}
static ssize_t prox_avg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", pdata->min,
pdata->avg, pdata->max);
}
static ssize_t prox_avg_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int new_value;
if (sysfs_streq(buf, "0"))
new_value = 0;
else
new_value = 1;
if (new_value == pdata->avgtimer_enabled)
return size;
if (new_value == 0) {
pdata->avgtimer_enabled = 0;
hrtimer_cancel(&pdata->prox_timer);
cancel_work_sync(&pdata->work_prox);
} else {
pdata->avgtimer_enabled = 1;
pdata->dev_data = data;
hrtimer_start(&pdata->prox_timer,
ns_to_ktime(2000 * NSEC_PER_MSEC),
HRTIMER_MODE_REL);
}
return size;
}
static void prox_work_func(struct work_struct *work)
{
int min = 0, max = 0, avg = 0;
int i;
pdata->avgwork_check = 1;
for (i = 0; i < PROX_AVG_COUNT; i++) {
msleep(20);
get_prox_raw_data(pdata->dev_data, &pdata->val, &pdata->offset);
avg += pdata->val;
if (!i)
min = pdata->val;
else if (pdata->val < min)
min = pdata->val;
if (pdata->val > max)
max = pdata->val;
}
avg /= PROX_AVG_COUNT;
pdata->min = min;
pdata->avg = avg;
pdata->max = max;
pdata->avgwork_check = 0;
}
static enum hrtimer_restart prox_timer_func(struct hrtimer *timer)
{
queue_work(pdata->prox_wq, &pdata->work_prox);
hrtimer_forward_now(&pdata->prox_timer,
ns_to_ktime(2000 * NSEC_PER_MSEC));
return HRTIMER_RESTART;
}
static void prox_led_control(struct adsp_data *data, int led_number)
{
uint16_t prox_idx = get_prox_sidx(data);
int cnt = 0;
int32_t msg[2];
msg[0] = PROX_CMD_TYPE_LED_CONTROL;
msg[1] = led_number;
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(&msg, sizeof(msg), prox_idx, 0, MSG_TYPE_GET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_CAL_DATA] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_CAL_DATA] &= ~(1 << prox_idx);
mutex_unlock(&data->prox_factory_mutex);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s: Timeout!!!\n", __func__);
}
static ssize_t prox_led_test_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int data_buf, offset = 0, ret = 0, result = 1;
prox_led_control(data, 0);
msleep(200);
ret = get_prox_raw_data(data, &data_buf, &offset);
prox_led_control(data, 4);
if (ret != 0)
result = -1;
pr_info("[SSC_FAC] %s: [%d] %d\n", __func__, result, data_buf);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d\n", result,
data_buf, data_buf, data_buf, data_buf);
}
static int prox_get_threshold(struct adsp_data *data, int type)
{
uint8_t cnt = 0;
uint16_t prox_idx = get_prox_sidx(data);
int32_t msg_buf[2];
int ret = 0;
msg_buf[0] = type;
msg_buf[1] = 0;
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf),
prox_idx, 0, MSG_TYPE_GET_THRESHOLD);
while (!(data->ready_flag[MSG_TYPE_GET_THRESHOLD] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_THRESHOLD] &= ~(1 << prox_idx);
if (cnt >= TIMEOUT_CNT) {
pr_err("[SSC_FAC] %s: Timeout!!!\n", __func__);
mutex_unlock(&data->prox_factory_mutex);
return ret;
}
ret = data->msg_buf[prox_idx][0];
mutex_unlock(&data->prox_factory_mutex);
return ret;
}
static void prox_set_threshold(struct adsp_data *data, int type, int val)
{
uint8_t cnt = 0;
uint16_t prox_idx = get_prox_sidx(data);
int32_t msg_buf[2];
msg_buf[0] = type;
msg_buf[1] = val;
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf),
prox_idx, 0, MSG_TYPE_SET_THRESHOLD);
while (!(data->ready_flag[MSG_TYPE_SET_THRESHOLD] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_THRESHOLD] &= ~(1 << prox_idx);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s: Timeout!!!\n", __func__);
mutex_unlock(&data->prox_factory_mutex);
}
static ssize_t prox_cal_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
#if IS_ENABLED(CONFIG_SUPPORT_PROX_CALIBRATION)
struct adsp_data *data = dev_get_drvdata(dev);
if (get_prox_sidx(data) == MSG_PROX)
return snprintf(buf, PAGE_SIZE, "%d,0,0\n", data->prox_cal);
else
return snprintf(buf, PAGE_SIZE, "%d,0,0\n", data->prox_sub_cal);
#else
return snprintf(buf, PAGE_SIZE, "0,0,0\n");
#endif
}
static ssize_t prox_cal_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
#if IS_ENABLED(CONFIG_SUPPORT_PROX_CALIBRATION)
struct adsp_data *data = dev_get_drvdata(dev);
int32_t cmd, msg_buf[2], cnt = 0;
uint16_t prox_idx = get_prox_sidx(data);
if (sysfs_streq(buf, "1")) {
cmd = PROX_CMD_TYPE_GET_CAL_DATA;
} else if (sysfs_streq(buf, "0")) {
cmd = PROX_CMD_TYPE_INIT_CAL_DATA;
} else {
pr_err("[SSC_FAC] %s: wrong value\n", __func__);
return size;
}
pr_info("[SSC_FAC] %s[%d]: msg %d\n",
__func__, (int)prox_idx - MSG_PROX, cmd);
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(&cmd, sizeof(int32_t), prox_idx, 0, MSG_TYPE_GET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_CAL_DATA] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_CAL_DATA] &= ~(1 << prox_idx);
mutex_unlock(&data->prox_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[SSC_FAC] %s[%d]: Timeout!!!\n", __func__,
(int)prox_idx - MSG_PROX);
return size;
} else if (data->msg_buf[prox_idx][0] < 0) {
pr_err("[SSC_FAC] %s[%d]: fail! %d\n", __func__,
(int)prox_idx - MSG_PROX,
data->msg_buf[prox_idx][0]);
return size;
}
cnt = 0;
msg_buf[0] = PROX_CMD_TYPE_SAVE_CAL_DATA;
msg_buf[1] = data->msg_buf[prox_idx][0];
if (prox_idx == MSG_PROX)
data->prox_cal = data->msg_buf[prox_idx][0];
else
data->prox_sub_cal = data->msg_buf[prox_idx][0];
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf), prox_idx, 0,
MSG_TYPE_SET_TEMPORARY_MSG);
while (!(data->ready_flag[MSG_TYPE_SET_TEMPORARY_MSG] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
msleep(20);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s[%d]: SAVE_CAL_DATA Timeout!!!\n",
__func__, (int)prox_idx - MSG_PROX);
data->ready_flag[MSG_TYPE_SET_TEMPORARY_MSG] &= ~(1 << prox_idx);
mutex_unlock(&data->prox_factory_mutex);
if ((prox_idx == MSG_PROX) && (data->prox_cal > 0))
prox_send_cal_data(data, prox_idx, true);
#if IS_ENABLED(CONFIG_SUPPORT_DUAL_OPTIC)
else if ((prox_idx == MSG_PROX_SUB) && (data->prox_sub_cal > 0))
prox_send_cal_data(data, prox_idx, true);
#endif
#else
pr_info("[SSC_FAC] %s: unsupported prox cal!\n", __func__);
#endif
return size;
}
static ssize_t prox_thresh_high_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int thd;
thd = prox_get_threshold(data, PRX_THRESHOLD_DETECT_H);
pr_info("[SSC_FAC] %s: %d\n", __func__, thd);
return snprintf(buf, PAGE_SIZE, "%d\n", thd);
}
static ssize_t prox_thresh_high_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int thd = 0;
if (kstrtoint(buf, 10, &thd)) {
pr_err("[SSC_FAC] %s: kstrtoint fail\n", __func__);
return size;
}
prox_set_threshold(data, PRX_THRESHOLD_DETECT_H, thd);
pr_info("[SSC_FAC] %s: %d\n", __func__, thd);
return size;
}
static ssize_t prox_thresh_low_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int thd;
thd = prox_get_threshold(data, PRX_THRESHOLD_RELEASE_L);
pr_info("[SSC_FAC] %s: %d\n", __func__, thd);
return snprintf(buf, PAGE_SIZE, "%d\n", thd);
}
static ssize_t prox_thresh_low_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int thd = 0;
if (kstrtoint(buf, 10, &thd)) {
pr_err("[SSC_FAC] %s: kstrtoint fail\n", __func__);
return size;
}
prox_set_threshold(data, PRX_THRESHOLD_RELEASE_L, thd);
pr_info("[SSC_FAC] %s: %d\n", __func__, thd);
return size;
}
static ssize_t prox_thresh_detect_high_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int thd;
thd = prox_get_threshold(data, PRX_THRESHOLD_HIGH_DETECT_H);
pr_info("[SSC_FAC] %s: %d\n", __func__, thd);
return snprintf(buf, PAGE_SIZE, "%d\n", thd);
}
static ssize_t prox_thresh_detect_high_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int thd = 0;
if (kstrtoint(buf, 10, &thd)) {
pr_err("[SSC_FAC] %s: kstrtoint fail\n", __func__);
return size;
}
prox_set_threshold(data, PRX_THRESHOLD_HIGH_DETECT_H, thd);
pr_info("[SSC_FAC] %s: %d\n", __func__, thd);
return size;
}
static ssize_t prox_thresh_detect_low_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int thd;
thd = prox_get_threshold(data, PRX_THRESHOLD_HIGH_DETECT_L);
pr_info("[SSC_FAC] %s: %d\n", __func__, thd);
return snprintf(buf, PAGE_SIZE, "%d\n", thd);
}
static ssize_t prox_thresh_detect_low_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int thd = 0;
if (kstrtoint(buf, 10, &thd)) {
pr_err("[SSC_FAC] %s: kstrtoint fail\n", __func__);
return size;
}
prox_set_threshold(data, PRX_THRESHOLD_HIGH_DETECT_L, thd);
pr_info("[SSC_FAC] %s: %d\n", __func__, thd);
return size;
}
static ssize_t prox_cancel_pass_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
#if IS_ENABLED(CONFIG_SUPPORT_PROX_CALIBRATION)
struct adsp_data *data = dev_get_drvdata(dev);
if (get_prox_sidx(data) == MSG_PROX)
return snprintf(buf, PAGE_SIZE, "%d\n",
(data->prox_cal > 0) ? 1 : 0);
else
return snprintf(buf, PAGE_SIZE, "%d\n",
(data->prox_sub_cal > 0) ? 1 : 0);
#else
return snprintf(buf, PAGE_SIZE, "1\n");
#endif
}
static ssize_t prox_default_trim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", pdata->offset);
}
static ssize_t prox_alert_thresh_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", PROX_ALERT_THRESHOLD);
}
static ssize_t prox_register_read_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint16_t prox_idx = get_prox_sidx(data);
int cnt = 0;
int32_t msg_buf[1];
msg_buf[0] = pdata->reg_backup[0];
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf),
prox_idx, 0, MSG_TYPE_GET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_REGISTER] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_REGISTER] &= ~(1 << prox_idx);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s: Timeout!!!\n", __func__);
pdata->reg_backup[1] = data->msg_buf[prox_idx][0];
pr_info("[SSC_FAC] %s: [0x%x]: %d\n",
__func__, pdata->reg_backup[0], pdata->reg_backup[1]);
mutex_unlock(&data->prox_factory_mutex);
return snprintf(buf, PAGE_SIZE, "%d\n", pdata->reg_backup[1]);
}
static ssize_t prox_register_read_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int reg = 0;
if (sscanf(buf, "%3d", &reg) != 1) {
pr_err("[SSC_FAC]: %s - The number of data are wrong\n",
__func__);
return -EINVAL;
}
pdata->reg_backup[0] = reg;
pr_info("[SSC_FAC] %s: [0x%x]\n", __func__, pdata->reg_backup[0]);
return size;
}
static ssize_t prox_register_write_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint16_t prox_idx = get_prox_sidx(data);
int cnt = 0;
int32_t msg_buf[2];
if (sscanf(buf, "%3d,%5d", &msg_buf[0], &msg_buf[1]) != 2) {
pr_err("[SSC_FAC]: %s - The number of data are wrong\n",
__func__);
return -EINVAL;
}
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf),
prox_idx, 0, MSG_TYPE_SET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_SET_REGISTER] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_REGISTER] &= ~(1 << prox_idx);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s: Timeout!!!\n", __func__);
pdata->reg_backup[0] = msg_buf[0];
pr_info("[SSC_FAC] %s: 0x%x - %d\n",
__func__, msg_buf[0], data->msg_buf[prox_idx][0]);
mutex_unlock(&data->prox_factory_mutex);
return size;
}
static ssize_t prox_touch_prox_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint16_t prox_idx = get_prox_sidx(data);
int cnt = 0;
int32_t msg_buf[2];
if (sscanf(buf, "%2d", &msg_buf[1]) != 1) {
pr_err("[SSC_FAC]: %s - The number of data are wrong\n",
__func__);
return -EINVAL;
}
msg_buf[0] = PROX_CMD_TYPE_TOUCH_PROX;
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf), prox_idx, 0, MSG_TYPE_GET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_CAL_DATA] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_CAL_DATA] &= ~(1 << prox_idx);
pr_info("[SSC_FAC] %s: event: %d\n", __func__, msg_buf[1]);
mutex_unlock(&data->prox_factory_mutex);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s: Timeout!!!\n", __func__);
return size;
}
static ssize_t prox_debug_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint16_t prox_idx = get_prox_sidx(data);
int cnt = 0;
int32_t msg_buf[1];
msg_buf[0] = pdata->debug_info_cmd;
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(msg_buf, sizeof(msg_buf),
prox_idx, 0, MSG_TYPE_GET_DUMP_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_DUMP_REGISTER] & 1 << prox_idx)
&& cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_DUMP_REGISTER] &= ~(1 << prox_idx);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s: Timeout!!!\n", __func__);
mutex_unlock(&data->prox_factory_mutex);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[prox_idx][0], data->msg_buf[prox_idx][1],
data->msg_buf[prox_idx][2], data->msg_buf[prox_idx][3],
data->msg_buf[prox_idx][4], data->msg_buf[prox_idx][5],
data->msg_buf[prox_idx][6], data->msg_buf[prox_idx][7],
data->msg_buf[prox_idx][8], data->msg_buf[prox_idx][9],
data->msg_buf[prox_idx][10], data->msg_buf[prox_idx][11]);
}
static ssize_t prox_debug_info_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
int reg = 0;
if (sscanf(buf, "%3d", &reg) != 1) {
pr_err("[SSC_FAC]: %s - The number of data are wrong\n",
__func__);
return -EINVAL;
}
pdata->debug_info_cmd = reg;
return size;
}
static ssize_t prox_light_get_dhr_sensor_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint16_t prox_idx = get_prox_sidx(data);
uint8_t cnt = 0;
int offset = 0;
int32_t *info = data->msg_buf[prox_idx];
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(NULL, 0, prox_idx, 0, MSG_TYPE_GET_DHR_INFO);
while (!(data->ready_flag[MSG_TYPE_GET_DHR_INFO] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_DHR_INFO] &= ~(1 << prox_idx);
if (cnt >= TIMEOUT_CNT)
pr_err("[SSC_FAC] %s: Timeout!!!\n", __func__);
pr_info("[SSC_FAC] %d,%d,%d,%d,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%d\n",
info[0], info[1], info[2], info[3], info[4], info[5],
info[6], info[7], info[8], info[9], info[10], info[11]);
offset += snprintf(buf + offset, PAGE_SIZE - offset,
"\"THD\":\"%d %d %d %d\",", info[0], info[1], info[2], info[3]);
offset += snprintf(buf + offset, PAGE_SIZE - offset,
"\"PDRIVE_CURRENT\":\"%02x\",", info[4]);
offset += snprintf(buf + offset, PAGE_SIZE - offset,
"\"PERSIST_TIME\":\"%02x\",", info[5]);
offset += snprintf(buf + offset, PAGE_SIZE - offset,
"\"PPULSE\":\"%02x\",", info[6]);
offset += snprintf(buf + offset, PAGE_SIZE - offset,
"\"PGAIN\":\"%02x\",", info[7]);
offset += snprintf(buf + offset, PAGE_SIZE - offset,
"\"PTIME\":\"%02x\",", info[8]);
offset += snprintf(buf + offset, PAGE_SIZE - offset,
"\"PPLUSE_LEN\":\"%02x\",", info[9]);
offset += snprintf(buf + offset, PAGE_SIZE - offset,
"\"ATIME\":\"%02x\",", info[10]);
offset += snprintf(buf + offset, PAGE_SIZE - offset,
"\"POFFSET\":\"%d\"\n", info[11]);
mutex_unlock(&data->prox_factory_mutex);
return offset;
}
static ssize_t prox_wakelock_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
return size;
}
static ssize_t prox_trim_check_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint16_t prox_idx = get_prox_sidx(data);
int cnt = 0;
int32_t msg = PROX_CMD_TYPE_GET_TRIM_CHECK;
mutex_lock(&data->prox_factory_mutex);
adsp_unicast(&msg, sizeof(int32_t), prox_idx, 0, MSG_TYPE_GET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_CAL_DATA] & 1 << prox_idx) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_CAL_DATA] &= ~(1 << prox_idx);
mutex_unlock(&data->prox_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[SSC_FAC] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "NG\n");
}
pr_info("[SSC_FAC] %s: [%s]: 0x%x, 0x%x\n",
__func__, (data->msg_buf[prox_idx][0] > 0) ? "TRIM" : "UNTRIM",
(uint16_t)data->msg_buf[prox_idx][1],
(uint16_t)data->msg_buf[prox_idx][2]);
return snprintf(buf, PAGE_SIZE, "%s\n",
(data->msg_buf[prox_idx][0] > 0) ? "TRIM" : "UNTRIM");
}
static DEVICE_ATTR(vendor, 0444, prox_vendor_show, NULL);
static DEVICE_ATTR(name, 0444, prox_name_show, NULL);
static DEVICE_ATTR(state, 0444, prox_raw_data_show, NULL);
static DEVICE_ATTR(raw_data, 0444, prox_raw_data_show, NULL);
static DEVICE_ATTR(prox_led_test, 0444, prox_led_test_show, NULL);
static DEVICE_ATTR(prox_avg, 0664,
prox_avg_show, prox_avg_store);
static DEVICE_ATTR(prox_cal, 0664,
prox_cal_show, prox_cal_store);
static DEVICE_ATTR(thresh_high, 0664,
prox_thresh_high_show, prox_thresh_high_store);
static DEVICE_ATTR(thresh_low, 0664,
prox_thresh_low_show, prox_thresh_low_store);
static DEVICE_ATTR(register_write, 0220,
NULL, prox_register_write_store);
static DEVICE_ATTR(register_read, 0664,
prox_register_read_show, prox_register_read_store);
static DEVICE_ATTR(prox_offset_pass, 0444, prox_cancel_pass_show, NULL);
static DEVICE_ATTR(prox_trim, 0444, prox_default_trim_show, NULL);
static DEVICE_ATTR(thresh_detect_high, 0664,
prox_thresh_detect_high_show, prox_thresh_detect_high_store);
static DEVICE_ATTR(thresh_detect_low, 0664,
prox_thresh_detect_low_show, prox_thresh_detect_low_store);
static DEVICE_ATTR(prox_alert_thresh, 0444, prox_alert_thresh_show, NULL);
static DEVICE_ATTR(dhr_sensor_info, 0440,
prox_light_get_dhr_sensor_info_show, NULL);
static DEVICE_ATTR(prox_wakelock, 0220, NULL, prox_wakelock_store);
static DEVICE_ATTR(trim_check, 0444, prox_trim_check_show, NULL);
static DEVICE_ATTR(debug_info, 0664,
prox_debug_info_show, prox_debug_info_store);
static DEVICE_ATTR(touch_prox, 0220, NULL, prox_touch_prox_store);
static struct device_attribute *prox_attrs[] = {
&dev_attr_vendor,
&dev_attr_name,
&dev_attr_state,
&dev_attr_raw_data,
&dev_attr_prox_led_test,
&dev_attr_prox_avg,
&dev_attr_prox_cal,
&dev_attr_thresh_high,
&dev_attr_thresh_low,
&dev_attr_prox_offset_pass,
&dev_attr_prox_trim,
&dev_attr_thresh_detect_high,
&dev_attr_thresh_detect_low,
&dev_attr_prox_alert_thresh,
&dev_attr_dhr_sensor_info,
&dev_attr_register_write,
&dev_attr_register_read,
&dev_attr_prox_wakelock,
&dev_attr_trim_check,
&dev_attr_debug_info,
&dev_attr_touch_prox,
NULL,
};
int prox_factory_init(void)
{
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
adsp_factory_register(MSG_PROX, prox_attrs);
pr_info("[SSC_FAC] %s\n", __func__);
hrtimer_init(&pdata->prox_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pdata->prox_timer.function = prox_timer_func;
pdata->prox_wq = create_singlethread_workqueue("prox_wq");
/* this is the thread function we run on the work queue */
INIT_WORK(&pdata->work_prox, prox_work_func);
pdata->avgwork_check = 0;
pdata->avgtimer_enabled = 0;
pdata->avg = 0;
pdata->min = 0;
pdata->max = 0;
pdata->offset = 0;
pdata->debug_info_cmd = 0;
return 0;
}
void prox_factory_exit(void)
{
if (pdata->avgtimer_enabled == 1) {
hrtimer_cancel(&pdata->prox_timer);
cancel_work_sync(&pdata->work_prox);
}
destroy_workqueue(pdata->prox_wq);
adsp_factory_unregister(MSG_PROX);
kfree(pdata);
pr_info("[SSC_FAC] %s\n", __func__);
}

1980
drivers/adsp_factory/ssc_core.c Executable file

File diff suppressed because it is too large Load Diff

685
drivers/adsp_factory/sub2_accel.c Executable file
View File

@@ -0,0 +1,685 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define VENDOR "STM"
#define CHIP_ID "LSM6DSVW"
#define ACCEL_ST_TRY_CNT 3
#define ACCEL_FACTORY_CAL_CNT 20
#define ACCEL_RAW_DATA_CNT 3
#define MAX_ACCEL_1G 2048
#define PASS 0
#define STM_LSM6DSV_INT_CHECK_RUNNING 4
#define STM_LSM6DSV_INT_CHECK_SKIP_IBI 5
struct sub2_accel_data {
struct work_struct work_accel;
struct workqueue_struct *accel_wq;
struct adsp_data *dev_data;
bool is_complete_cal;
bool lpf_onoff;
bool st_complete;
int32_t raw_data[ACCEL_RAW_DATA_CNT];
int32_t avg_data[ACCEL_RAW_DATA_CNT];
};
static struct sub2_accel_data *pdata;
static ssize_t sub2_accel_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t sub2_accel_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t sensor_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", "ADSP");
}
int get_sub2_accel_cal_data(struct adsp_data *data, int32_t *cal_data)
{
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_ACCEL_SUB2, 0, MSG_TYPE_GET_CAL_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_CAL_DATA] & 1 << MSG_ACCEL_SUB2) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_CAL_DATA] &= ~(1 << MSG_ACCEL_SUB2);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return 0;
}
if (data->msg_buf[MSG_ACCEL_SUB2][3] != ACCEL_RAW_DATA_CNT) {
pr_err("[FACTORY] %s: Reading Bytes Num %d!!!\n",
__func__, data->msg_buf[MSG_ACCEL_SUB2][3]);
return 0;
}
cal_data[0] = data->msg_buf[MSG_ACCEL_SUB2][0];
cal_data[1] = data->msg_buf[MSG_ACCEL_SUB2][1];
cal_data[2] = data->msg_buf[MSG_ACCEL_SUB2][2];
pr_info("[FACTORY] %s: %d, %d, %d, %d\n", __func__,
cal_data[0], cal_data[1], cal_data[2],
data->msg_buf[MSG_ACCEL_SUB2][3]);
return data->msg_buf[MSG_ACCEL_SUB2][3];
}
void set_sub2_accel_cal_data(struct adsp_data *data)
{
uint8_t cnt = 0;
pr_info("[FACTORY] %s(1): %d, %d, %d\n", __func__, pdata->avg_data[0],
pdata->avg_data[1], pdata->avg_data[2]);
adsp_unicast(pdata->avg_data, sizeof(pdata->avg_data),
MSG_ACCEL_SUB2, 0, MSG_TYPE_SET_CAL_DATA);
pr_info("[FACTORY] %s(2): %d, %d, %d\n", __func__, pdata->avg_data[0],
pdata->avg_data[1], pdata->avg_data[2]);
while (!(data->ready_flag[MSG_TYPE_SET_CAL_DATA] & 1 << MSG_ACCEL_SUB2) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_CAL_DATA] &= ~(1 << MSG_ACCEL_SUB2);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
} else if (data->msg_buf[MSG_ACCEL_SUB2][0] != ACCEL_RAW_DATA_CNT) {
pr_err("[FACTORY] %s: Write Bytes Num %d!!!\n",
__func__, data->msg_buf[MSG_ACCEL_SUB2][0]);
}
}
static ssize_t sub2_accel_calibration_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t cal_data[ACCEL_RAW_DATA_CNT] = {0, };
int ret = 0;
mutex_lock(&data->accel_factory_mutex);
ret = get_sub2_accel_cal_data(data, cal_data);
mutex_unlock(&data->accel_factory_mutex);
if (ret > 0) {
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
cal_data[0], cal_data[1], cal_data[2]);
if (cal_data[0] == 0 && cal_data[1] == 0 && cal_data[2] == 0)
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n",
0, 0, 0, 0);
else
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n",
true, cal_data[0], cal_data[1], cal_data[2]);
} else {
pr_err("[FACTORY] %s: get_sub2_accel_cal_data fail\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d\n", 0, 0, 0, 0);
}
}
static ssize_t sub2_accel_calibration_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
pdata->dev_data = data;
if (sysfs_streq(buf, "0")) {
mutex_lock(&data->accel_factory_mutex);
memset(pdata->avg_data, 0, sizeof(pdata->avg_data));
set_sub2_accel_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
} else {
pdata->is_complete_cal = false;
queue_work(pdata->accel_wq, &pdata->work_accel);
while (pdata->is_complete_cal == false) {
pr_info("[FACTORY] %s: In factory cal\n", __func__);
msleep(20);
}
mutex_lock(&data->accel_factory_mutex);
set_sub2_accel_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
}
return size;
}
static void sub2_accel_work_func(struct work_struct *work)
{
struct sub2_accel_data *data = container_of((struct work_struct *)work,
struct sub2_accel_data, work_accel);
int i;
mutex_lock(&data->dev_data->accel_factory_mutex);
memset(pdata->avg_data, 0, sizeof(pdata->avg_data));
adsp_unicast(pdata->avg_data, sizeof(pdata->avg_data),
MSG_ACCEL_SUB2, 0, MSG_TYPE_SET_CAL_DATA);
msleep(30); /* for init of bias */
for (i = 0; i < ACCEL_FACTORY_CAL_CNT; i++) {
msleep(20);
get_sub2_accel_raw_data(pdata->raw_data);
pdata->avg_data[0] += pdata->raw_data[0];
pdata->avg_data[1] += pdata->raw_data[1];
pdata->avg_data[2] += pdata->raw_data[2];
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
pdata->raw_data[0], pdata->raw_data[1],
pdata->raw_data[2]);
}
for (i = 0; i < ACCEL_RAW_DATA_CNT; i++) {
pdata->avg_data[i] /= ACCEL_FACTORY_CAL_CNT;
pr_info("[FACTORY] %s: avg : %d\n",
__func__, pdata->avg_data[i]);
}
if (pdata->avg_data[2] > 0)
pdata->avg_data[2] -= MAX_ACCEL_1G;
else if (pdata->avg_data[2] < 0)
pdata->avg_data[2] += MAX_ACCEL_1G;
mutex_unlock(&data->dev_data->accel_factory_mutex);
pdata->is_complete_cal = true;
}
void sub2_accel_cal_work_func(struct work_struct *work)
{
struct adsp_data *data = container_of((struct delayed_work *)work,
struct adsp_data, sub2_accel_cal_work);
int ret = 0;
mutex_lock(&data->accel_factory_mutex);
ret = get_sub2_accel_cal_data(data, pdata->avg_data);
mutex_unlock(&data->accel_factory_mutex);
if (ret > 0) {
pr_info("[FACTORY] %s: ret(%d) %d, %d, %d\n", __func__, ret,
pdata->avg_data[0],
pdata->avg_data[1],
pdata->avg_data[2]);
mutex_lock(&data->accel_factory_mutex);
set_sub2_accel_cal_data(data);
mutex_unlock(&data->accel_factory_mutex);
} else {
pr_err("[FACTORY] %s: get_accel_cal_data fail (%d)\n",
__func__, ret);
}
}
static ssize_t sub2_accel_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int retry = 0;
#if 0 //IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_REF_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#endif
pdata->st_complete = false;
RETRY_ACCEL_SELFTEST:
adsp_unicast(NULL, 0, MSG_ACCEL_SUB2, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_ACCEL_SUB2) &&
cnt++ < TIMEOUT_CNT)
msleep(26);
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_ACCEL_SUB2);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
data->msg_buf[MSG_ACCEL_SUB2][1] = -1;
#ifdef CONFIG_SEC_FACTORY
panic("sensor force crash : sub2 accel selftest timeout\n");
#endif
}
pr_info("[FACTORY] %s : init = %d, result = %d, XYZ = %d, %d, %d, nXYZ = %d, %d, %d\n",
__func__, data->msg_buf[MSG_ACCEL_SUB2][0],
data->msg_buf[MSG_ACCEL_SUB2][1], data->msg_buf[MSG_ACCEL_SUB2][2],
data->msg_buf[MSG_ACCEL_SUB2][3], data->msg_buf[MSG_ACCEL_SUB2][4],
data->msg_buf[MSG_ACCEL_SUB2][5], data->msg_buf[MSG_ACCEL_SUB2][6],
data->msg_buf[MSG_ACCEL_SUB2][7]);
pr_info("[FACTORY] %s : pre/postP/postN [%d, %d, %d/%d, %d, %d/%d, %d, %d], comm_err_cnt %d/%d/%d\n",
__func__, data->msg_buf[MSG_ACCEL_SUB2][8],
data->msg_buf[MSG_ACCEL_SUB2][9], data->msg_buf[MSG_ACCEL_SUB2][10],
data->msg_buf[MSG_ACCEL_SUB2][11], data->msg_buf[MSG_ACCEL_SUB2][12],
data->msg_buf[MSG_ACCEL_SUB2][13], data->msg_buf[MSG_ACCEL_SUB2][14],
data->msg_buf[MSG_ACCEL_SUB2][15], data->msg_buf[MSG_ACCEL_SUB2][16],
data->msg_buf[MSG_ACCEL_SUB2][17], data->msg_buf[MSG_ACCEL_SUB2][18],
data->msg_buf[MSG_ACCEL_SUB2][19]);
if (data->msg_buf[MSG_ACCEL_SUB2][1] == 1) {
pr_info("[FACTORY] %s : Pass - result = %d, retry = %d\n",
__func__, data->msg_buf[MSG_ACCEL_SUB2][1], retry);
} else {
data->msg_buf[MSG_ACCEL_SUB2][1] = -5;
pr_err("[FACTORY] %s : Fail - result = %d, retry = %d\n",
__func__, data->msg_buf[MSG_ACCEL_SUB2][1], retry);
if (retry < ACCEL_ST_TRY_CNT) {
retry++;
msleep(50);
cnt = 0;
pr_info("[FACTORY] %s: retry\n", __func__);
goto RETRY_ACCEL_SELFTEST;
}
}
pdata->st_complete = true;
#if 0 //IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_ACCEL_SUB2][1],
(int)abs(data->msg_buf[MSG_ACCEL_SUB2][2]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB2][3]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB2][4]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB2][5]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB2][6]),
(int)abs(data->msg_buf[MSG_ACCEL_SUB2][7]));
}
static ssize_t sub2_accel_raw_data_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t raw_data[ACCEL_RAW_DATA_CNT] = {0, };
static int32_t prev_raw_data[ACCEL_RAW_DATA_CNT] = {0, };
int ret = 0;
#ifdef CONFIG_SEC_FACTORY
static int same_cnt;
#endif
if (pdata->st_complete == false) {
pr_info("[FACTORY] %s: selftest is running\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
raw_data[0], raw_data[1], raw_data[2]);
}
mutex_lock(&data->accel_factory_mutex);
ret = get_sub2_accel_raw_data(raw_data);
mutex_unlock(&data->accel_factory_mutex);
#ifdef CONFIG_SEC_FACTORY
pr_info("[FACTORY] %s: %d, %d, %d\n", __func__,
raw_data[0], raw_data[1], raw_data[2]);
if (prev_raw_data[0] == raw_data[0] &&
prev_raw_data[1] == raw_data[1] &&
prev_raw_data[2] == raw_data[2]) {
same_cnt++;
pr_info("[FACTORY] %s: same_cnt %d\n", __func__, same_cnt);
if (same_cnt >= 20)
panic("sensor force crash : sub2 accel raw_data stuck\n");
} else
same_cnt = 0;
#endif
if (!ret) {
memcpy(prev_raw_data, raw_data, sizeof(int32_t) * 3);
} else if (!pdata->lpf_onoff) {
pr_err("[FACTORY] %s: using prev data!!!\n", __func__);
memcpy(raw_data, prev_raw_data, sizeof(int32_t) * 3);
} else {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
}
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
raw_data[0], raw_data[1], raw_data[2]);
}
static ssize_t sub2_accel_reactive_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
bool success = false;
int32_t msg_buf = 0;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL_SUB2,
0, MSG_TYPE_GET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_REGISTER] & 1 << MSG_ACCEL_SUB2) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_REGISTER] &= ~(1 << MSG_ACCEL_SUB2);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", (int)success);
}
pr_info("[FACTORY]: %s - %d\n", __func__,
data->msg_buf[MSG_ACCEL_SUB2][0]);
if (data->msg_buf[MSG_ACCEL_SUB2][0] == 0)
success = true;
if (data->msg_buf[MSG_ACCEL_SUB2][0] == STM_LSM6DSV_INT_CHECK_SKIP_IBI) {
pr_info("[FACTORY]: %s - IBI mode. Ignore Interrupt Check Test\n", __func__);
success = true;
}
return snprintf(buf, PAGE_SIZE, "%d\n", (int)success);
}
static ssize_t sub2_accel_reactive_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
int32_t msg_buf;
uint8_t cnt = 0;
if (sysfs_streq(buf, "1"))
pr_info("[FACTORY]: %s - on\n", __func__);
else if (sysfs_streq(buf, "0"))
pr_info("[FACTORY]: %s - off\n", __func__);
else if (sysfs_streq(buf, "2")) {
pr_info("[FACTORY]: %s - factory\n", __func__);
msg_buf = 1;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL_SUB2,
0, MSG_TYPE_GET_REGISTER);
while (!(data->ready_flag[MSG_TYPE_GET_REGISTER] & 1 << MSG_ACCEL_SUB2) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_REGISTER] &= ~(1 << MSG_ACCEL_SUB2);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return size;
}
if (data->msg_buf[MSG_ACCEL_SUB2][0] == STM_LSM6DSV_INT_CHECK_RUNNING)
pr_info("[FACTORY]: %s - STM_LSM6DSV_INT_CHECK_RUNNING\n", __func__);
else if (data->msg_buf[MSG_ACCEL_SUB2][0] == STM_LSM6DSV_INT_CHECK_SKIP_IBI)
pr_info("[FACTORY]: %s - IBI mode. Ignore Interrupt Check Test\n", __func__);
else
pr_info("[FACTORY]: %s - Something wrong\n", __func__);
}
return size;
}
static ssize_t sub2_accel_lowpassfilter_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int32_t msg_buf;
if (sysfs_streq(buf, "1")) {
msg_buf = 1;
} else if (sysfs_streq(buf, "0")) {
msg_buf = 0;
#ifdef CONFIG_SEC_FACTORY
} else if (sysfs_streq(buf, "2")) {
msg_buf = 2;
pr_info("[FACTORY] %s: Pretest\n", __func__);
#endif
} else {
pr_info("[FACTORY] %s: wrong value\n", __func__);
return size;
}
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(&msg_buf, sizeof(int32_t), MSG_ACCEL_SUB2,
0, MSG_TYPE_SET_ACCEL_LPF);
while (!(data->ready_flag[MSG_TYPE_SET_ACCEL_LPF] & 1 << MSG_ACCEL_SUB2) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_SET_ACCEL_LPF] &= ~(1 << MSG_ACCEL_SUB2);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return size;
}
pdata->lpf_onoff = (bool)data->msg_buf[MSG_ACCEL_SUB2][0];
#if IS_ENABLED(CONFIG_LSM6DSV_FACTORY)
pr_info("[FACTORY] %s: %d, 0x0A:%02x 0x0D:%02x 0x18:%02x\n", __func__,
data->msg_buf[MSG_ACCEL_SUB2][0], data->msg_buf[MSG_ACCEL_SUB2][1],
data->msg_buf[MSG_ACCEL_SUB2][2], data->msg_buf[MSG_ACCEL_SUB2][3]);
#else
pr_info("[FACTORY] %s: %d, 0x0A:%02x 0x0D:%02x 0x10:%02x\n", __func__,
data->msg_buf[MSG_ACCEL_SUB2][0], data->msg_buf[MSG_ACCEL_SUB2][1],
data->msg_buf[MSG_ACCEL_SUB2][2], data->msg_buf[MSG_ACCEL_SUB2][3]);
#endif
return size;
}
static ssize_t sub2_accel_dhr_sensor_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
char ctrl1_xl = 0;
uint8_t fullscale = 0;
adsp_unicast(NULL, 0, MSG_ACCEL_SUB2, 0, MSG_TYPE_GET_DHR_INFO);
while (!(data->ready_flag[MSG_TYPE_GET_DHR_INFO] & 1 << MSG_ACCEL_SUB2) &&
cnt++ < TIMEOUT_CNT)
usleep_range(500, 550);
data->ready_flag[MSG_TYPE_GET_DHR_INFO] &= ~(1 << MSG_ACCEL_SUB2);
if (cnt >= TIMEOUT_CNT)
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
ctrl1_xl = data->msg_buf[MSG_ACCEL_SUB2][16];
ctrl1_xl &= 0xC;
switch (ctrl1_xl) {
case 0xC:
fullscale = 8;
break;
case 0x8:
fullscale = 4;
break;
case 0x4:
fullscale = 16;
break;
case 0:
fullscale = 2;
break;
default:
break;
}
pr_info("[FACTORY] %s: f/s %u\n", __func__, fullscale);
return snprintf(buf, PAGE_SIZE, "\"FULL_SCALE\":\"%uG\"\n", fullscale);
}
#if 0 //IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
static ssize_t ref_angle_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int32_t result = PASS;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(NULL, 0, MSG_REF_ANGLE, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_REF_ANGLE) &&
cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_REF_ANGLE);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-1\n");
}
pr_info("[FACTORY] %s - st %d/%d, akm %d/%d, lf %d/%d, hall %d/%d/%d(uT)\n",
__func__, data->msg_buf[MSG_REF_ANGLE][0],
data->msg_buf[MSG_REF_ANGLE][1],
data->msg_buf[MSG_REF_ANGLE][2],
data->msg_buf[MSG_REF_ANGLE][3],
data->msg_buf[MSG_REF_ANGLE][4],
data->msg_buf[MSG_REF_ANGLE][5],
data->msg_buf[MSG_REF_ANGLE][6],
data->msg_buf[MSG_REF_ANGLE][7],
data->msg_buf[MSG_REF_ANGLE][8]);
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
data->msg_buf[MSG_REF_ANGLE][0], result);
}
static ssize_t angle_read_data_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
mutex_lock(&data->accel_factory_mutex);
adsp_unicast(NULL, 0, MSG_REF_ANGLE, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_REF_ANGLE) &&
cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_REF_ANGLE);
mutex_unlock(&data->accel_factory_mutex);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-1\n");
}
pr_info("[FACTORY] %s - st %d/%d, akm %d/%d, lf %d/%d, hall %d/%d/%d(uT)\n",
__func__, data->msg_buf[MSG_REF_ANGLE][0],
data->msg_buf[MSG_REF_ANGLE][1],
data->msg_buf[MSG_REF_ANGLE][2],
data->msg_buf[MSG_REF_ANGLE][3],
data->msg_buf[MSG_REF_ANGLE][4],
data->msg_buf[MSG_REF_ANGLE][5],
data->msg_buf[MSG_REF_ANGLE][6],
data->msg_buf[MSG_REF_ANGLE][7],
data->msg_buf[MSG_REF_ANGLE][8]);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_REF_ANGLE][0],
data->msg_buf[MSG_REF_ANGLE][1],
data->msg_buf[MSG_REF_ANGLE][2],
data->msg_buf[MSG_REF_ANGLE][3],
data->msg_buf[MSG_REF_ANGLE][4],
data->msg_buf[MSG_REF_ANGLE][5],
data->msg_buf[MSG_REF_ANGLE][6],
data->msg_buf[MSG_REF_ANGLE][7],
data->msg_buf[MSG_REF_ANGLE][8]);
}
#endif
static DEVICE_ATTR(name, 0444, sub2_accel_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, sub2_accel_vendor_show, NULL);
static DEVICE_ATTR(type, 0444, sensor_type_show, NULL);
static DEVICE_ATTR(calibration, 0664,
sub2_accel_calibration_show, sub2_accel_calibration_store);
static DEVICE_ATTR(selftest, 0440,
sub2_accel_selftest_show, NULL);
static DEVICE_ATTR(raw_data, 0444, sub2_accel_raw_data_show, NULL);
static DEVICE_ATTR(reactive_alert, 0664,
sub2_accel_reactive_show, sub2_accel_reactive_store);
static DEVICE_ATTR(lowpassfilter, 0220,
NULL, sub2_accel_lowpassfilter_store);
#ifdef CONFIG_SEC_FACTORY
static DEVICE_ATTR(dhr_sensor_info, 0444,
sub2_accel_dhr_sensor_info_show, NULL);
#else
static DEVICE_ATTR(dhr_sensor_info, 0440,
sub2_accel_dhr_sensor_info_show, NULL);
#endif
#if 0 //IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
static DEVICE_ATTR(ref_angle, 0444, ref_angle_show, NULL);
static DEVICE_ATTR(read_angle_data, 0444, angle_read_data_show, NULL);
#endif
static struct device_attribute *acc_attrs[] = {
&dev_attr_name,
&dev_attr_vendor,
&dev_attr_type,
&dev_attr_calibration,
&dev_attr_selftest,
&dev_attr_raw_data,
&dev_attr_reactive_alert,
&dev_attr_lowpassfilter,
&dev_attr_dhr_sensor_info,
#if 0 //IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
&dev_attr_ref_angle,
&dev_attr_read_angle_data,
#endif
NULL,
};
void sub2_accel_factory_init_work(struct adsp_data *data)
{
schedule_delayed_work(&data->sub2_accel_cal_work, msecs_to_jiffies(8000));
}
int __init sub2_accel_factory_init(void)
{
adsp_factory_register(MSG_ACCEL_SUB2, acc_attrs);
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
pdata->accel_wq = create_singlethread_workqueue("sub2_accel_wq");
INIT_WORK(&pdata->work_accel, sub2_accel_work_func);
pdata->lpf_onoff = true;
pdata->st_complete = true;
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit sub2_accel_factory_exit(void)
{
adsp_factory_unregister(MSG_ACCEL_SUB2);
pr_info("[FACTORY] %s\n", __func__);
}

211
drivers/adsp_factory/sub2_gyro.c Executable file
View File

@@ -0,0 +1,211 @@
/*
* 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/init.h>
#include <linux/module.h>
#include "adsp.h"
#define VENDOR "STM"
#define CHIP_ID "LSM6DSVW"
#define ST_PASS 1
#define ST_FAIL 0
#define STARTUP_BIT_FAIL 2
#define G_ZRL_DELTA_FAIL 4
#define SFLP_FAIL 6
#define SELFTEST_REVISED 1
static ssize_t sub2_gyro_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR);
}
static ssize_t sub2_gyro_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", CHIP_ID);
}
static ssize_t selftest_revised_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", SELFTEST_REVISED);
}
static ssize_t gyro_power_off(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY]: %s\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", 1);
}
static ssize_t gyro_power_on(struct device *dev,
struct device_attribute *attr, char *buf)
{
pr_info("[FACTORY]: %s\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d\n", 1);
}
static ssize_t sub2_gyro_temp_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
adsp_unicast(NULL, 0, MSG_GYRO_SUB2_TEMP, 0, MSG_TYPE_GET_RAW_DATA);
while (!(data->ready_flag[MSG_TYPE_GET_RAW_DATA] & 1 << MSG_GYRO_SUB2_TEMP)
&& cnt++ < TIMEOUT_CNT)
msleep(20);
data->ready_flag[MSG_TYPE_GET_RAW_DATA] &= ~(1 << MSG_GYRO_SUB2_TEMP);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
return snprintf(buf, PAGE_SIZE, "-99\n");
}
pr_info("[FACTORY] %s: sub2_gyro_temp = %d\n", __func__,
data->msg_buf[MSG_GYRO_SUB2_TEMP][0]);
return snprintf(buf, PAGE_SIZE, "%d\n",
data->msg_buf[MSG_GYRO_SUB2_TEMP][0]);
}
static ssize_t sub2_gyro_selftest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t cnt = 0;
int st_diff_res = ST_FAIL;
int st_zro_res = ST_FAIL;
#if 0 //IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
int msg_buf = LSM6DSO_SELFTEST_TRUE;
adsp_unicast(&msg_buf, sizeof(msg_buf),
MSG_REF_ANGLE, 0, MSG_TYPE_OPTION_DEFINE);
#endif
pr_info("[FACTORY] %s - start", __func__);
adsp_unicast(NULL, 0, MSG_GYRO_SUB2, 0, MSG_TYPE_ST_SHOW_DATA);
while (!(data->ready_flag[MSG_TYPE_ST_SHOW_DATA] & 1 << MSG_GYRO_SUB2) &&
cnt++ < TIMEOUT_CNT)
usleep_range(30000, 30100); /* 30 * 200 = 6 sec */
data->ready_flag[MSG_TYPE_ST_SHOW_DATA] &= ~(1 << MSG_GYRO_SUB2);
if (cnt >= TIMEOUT_CNT) {
pr_err("[FACTORY] %s: Timeout!!!\n", __func__);
#if 0 //IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE,
"0,0,0,0,0,0,0,0,0,0,0,0,%d,%d\n",
ST_FAIL, ST_FAIL);
}
if (data->msg_buf[MSG_GYRO_SUB2][1] != 0) {
pr_info("[FACTORY] %s - failed(%d, %d)\n", __func__,
data->msg_buf[MSG_GYRO_SUB2][1],
data->msg_buf[MSG_GYRO_SUB2][5]);
pr_info("[FACTORY]: %s - %d,%d,%d\n", __func__,
data->msg_buf[MSG_GYRO_SUB2][2],
data->msg_buf[MSG_GYRO_SUB2][3],
data->msg_buf[MSG_GYRO_SUB2][4]);
#if 0 //IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
if (data->msg_buf[MSG_GYRO_SUB2][5] == G_ZRL_DELTA_FAIL)
pr_info("[FACTORY] %s - ZRL Delta fail\n", __func__);
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
data->msg_buf[MSG_GYRO_SUB2][2],
data->msg_buf[MSG_GYRO_SUB2][3],
data->msg_buf[MSG_GYRO_SUB2][4]);
} else {
st_zro_res = ST_PASS;
}
if (!data->msg_buf[MSG_GYRO_SUB2][5])
st_diff_res = ST_PASS;
else if (data->msg_buf[MSG_GYRO_SUB2][5] == STARTUP_BIT_FAIL)
pr_info("[FACTORY] %s - Gyro Start Up Bit fail\n", __func__);
else if (data->msg_buf[MSG_GYRO_SUB2][5] == SFLP_FAIL) {
pr_info("[FACTORY] %s - SFLP sanity test fail\n", __func__);
st_diff_res = SFLP_FAIL;
}
pr_info("[FACTORY]: %s - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
__func__,
data->msg_buf[MSG_GYRO_SUB2][2], data->msg_buf[MSG_GYRO_SUB2][3],
data->msg_buf[MSG_GYRO_SUB2][4], data->msg_buf[MSG_GYRO_SUB2][6],
data->msg_buf[MSG_GYRO_SUB2][7], data->msg_buf[MSG_GYRO_SUB2][8],
data->msg_buf[MSG_GYRO_SUB2][9], data->msg_buf[MSG_GYRO_SUB2][10],
data->msg_buf[MSG_GYRO_SUB2][11], data->msg_buf[MSG_GYRO_SUB2][12],
data->msg_buf[MSG_GYRO_SUB2][13], data->msg_buf[MSG_GYRO_SUB2][14],
st_diff_res, st_zro_res);
#if 0 //IS_ENABLED(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL) || defined(CONFIG_SUPPORT_REF_ANGLE_WITHOUT_DIGITAL_HALL)
schedule_delayed_work(&data->lsm6dso_selftest_stop_work, msecs_to_jiffies(300));
#endif
return snprintf(buf, PAGE_SIZE,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
data->msg_buf[MSG_GYRO_SUB2][2], data->msg_buf[MSG_GYRO_SUB2][3],
data->msg_buf[MSG_GYRO_SUB2][4], data->msg_buf[MSG_GYRO_SUB2][6],
data->msg_buf[MSG_GYRO_SUB2][7], data->msg_buf[MSG_GYRO_SUB2][8],
data->msg_buf[MSG_GYRO_SUB2][9], data->msg_buf[MSG_GYRO_SUB2][10],
data->msg_buf[MSG_GYRO_SUB2][11], data->msg_buf[MSG_GYRO_SUB2][12],
data->msg_buf[MSG_GYRO_SUB2][13], data->msg_buf[MSG_GYRO_SUB2][14],
st_diff_res, st_zro_res);
}
static DEVICE_ATTR(name, 0444, sub2_gyro_name_show, NULL);
static DEVICE_ATTR(vendor, 0444, sub2_gyro_vendor_show, NULL);
static DEVICE_ATTR(selftest, 0440, sub2_gyro_selftest_show, NULL);
static DEVICE_ATTR(power_on, 0444, gyro_power_on, NULL);
static DEVICE_ATTR(power_off, 0444, gyro_power_off, NULL);
static DEVICE_ATTR(temperature, 0440, sub2_gyro_temp_show, NULL);
static DEVICE_ATTR(selftest_revised, 0440, selftest_revised_show, NULL);
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_revised,
NULL,
};
int __init sub2_gyro_factory_init(void)
{
adsp_factory_register(MSG_GYRO_SUB2, gyro_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
void __exit sub2_gyro_factory_exit(void)
{
adsp_factory_unregister(MSG_GYRO_SUB2);
pr_info("[FACTORY] %s\n", __func__);
}