diff options
Diffstat (limited to 'drivers/sensorhub/atmel/magnetic_ak8963c.c')
-rwxr-xr-x | drivers/sensorhub/atmel/magnetic_ak8963c.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/drivers/sensorhub/atmel/magnetic_ak8963c.c b/drivers/sensorhub/atmel/magnetic_ak8963c.c new file mode 100755 index 0000000..ccd1723 --- /dev/null +++ b/drivers/sensorhub/atmel/magnetic_ak8963c.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "AKM" +#define CHIP_ID "AK8963C" + +#define GYROSCOPE_DATA_SPEC_MIN -6500 +#define GYROSCOPE_DATA_SPEC_MAX 6500 + +#define GYROSCOPE_SELFTEST_X_SPEC_MIN -200 +#define GYROSCOPE_SELFTEST_X_SPEC_MAX 200 + +#define GYROSCOPE_SELFTEST_Y_SPEC_MIN -200 +#define GYROSCOPE_SELFTEST_Y_SPEC_MAX 200 + +#define GYROSCOPE_SELFTEST_Z_SPEC_MIN -3200 +#define GYROSCOPE_SELFTEST_Z_SPEC_MAX -800 + +static ssize_t magnetic_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t magnetic_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +static ssize_t raw_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", + data->buf[GEOMAGNETIC_SENSOR].x, + data->buf[GEOMAGNETIC_SENSOR].y, + data->buf[GEOMAGNETIC_SENSOR].z); +} + +static int check_data_spec(struct ssp_data *data) +{ + if ((data->buf[GEOMAGNETIC_SENSOR].x == 0) && + (data->buf[GEOMAGNETIC_SENSOR].y == 0) && + (data->buf[GEOMAGNETIC_SENSOR].z == 0)) + return FAIL; + else if ((data->buf[GEOMAGNETIC_SENSOR].x > GYROSCOPE_DATA_SPEC_MAX) || + (data->buf[GEOMAGNETIC_SENSOR].x < GYROSCOPE_DATA_SPEC_MIN) || + (data->buf[GEOMAGNETIC_SENSOR].y > GYROSCOPE_DATA_SPEC_MAX) || + (data->buf[GEOMAGNETIC_SENSOR].y < GYROSCOPE_DATA_SPEC_MIN) || + (data->buf[GEOMAGNETIC_SENSOR].z > GYROSCOPE_DATA_SPEC_MAX) || + (data->buf[GEOMAGNETIC_SENSOR].z < GYROSCOPE_DATA_SPEC_MIN)) + return FAIL; + else + return SUCCESS; +} + +static ssize_t adc_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + u8 chTempbuf[2] = {1, 20}; + s16 iSensorBuf[3] = {0, }; + int iRetries = 20; + struct ssp_data *data = dev_get_drvdata(dev); + + data->buf[GEOMAGNETIC_SENSOR].x = 0; + data->buf[GEOMAGNETIC_SENSOR].y = 0; + data->buf[GEOMAGNETIC_SENSOR].z = 0; + + if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_SENSOR))) + send_instruction(data, ADD_SENSOR, GEOMAGNETIC_SENSOR, + chTempbuf, 2); + + do { + msleep(50); + if (check_data_spec(data) == SUCCESS) + break; + } while (--iRetries); + + if (iRetries > 0) + bSuccess = true; + + iSensorBuf[0] = data->buf[GEOMAGNETIC_SENSOR].x; + iSensorBuf[1] = data->buf[GEOMAGNETIC_SENSOR].y; + iSensorBuf[2] = data->buf[GEOMAGNETIC_SENSOR].z; + + if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_SENSOR))) + send_instruction(data, REMOVE_SENSOR, GEOMAGNETIC_SENSOR, + chTempbuf, 2); + + pr_info("[SSP]: %s - x = %d, y = %d, z = %d\n", __func__, + iSensorBuf[0], iSensorBuf[1], iSensorBuf[2]); + + return sprintf(buf, "%s,%d,%d,%d\n", (bSuccess ? "OK" : "NG"), + iSensorBuf[0], iSensorBuf[1], iSensorBuf[2]); +} + +static ssize_t magnetic_get_asa(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%d,%d,%d\n", (s16)data->uFuseRomData[0], + (s16)data->uFuseRomData[1], (s16)data->uFuseRomData[2]); +} + +static ssize_t magnetic_get_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess; + struct ssp_data *data = dev_get_drvdata(dev); + + if ((data->uFuseRomData[0] == 0) || + (data->uFuseRomData[0] == 0xff) || + (data->uFuseRomData[1] == 0) || + (data->uFuseRomData[1] == 0xff) || + (data->uFuseRomData[2] == 0) || + (data->uFuseRomData[2] == 0xff)) + bSuccess = false; + else + bSuccess = true; + + return sprintf(buf, "%s,%u\n", (bSuccess ? "OK" : "NG"), bSuccess); +} + +static ssize_t magnetic_get_selftest(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSelftestPassed = false; + char chTempBuf[2] = { 0, 10 }; + s16 iSF_X = 0, iSF_Y = 0, iSF_Z = 0; + int iDelayCnt = 0, iRet = 0, iTimeoutReties = 0, iSpecOutReties = 0; + struct ssp_data *data = dev_get_drvdata(dev); + +reties: + iDelayCnt = 0; + data->uFactorydataReady = 0; + memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX); + + iRet = send_instruction(data, FACTORY_MODE, GEOMAGNETIC_FACTORY, + chTempBuf, 2); + + while (!(data->uFactorydataReady & (1 << GEOMAGNETIC_FACTORY)) + && (iDelayCnt++ < 50) + && (iRet == SUCCESS)) + msleep(20); + + if ((iDelayCnt >= 50) || (iRet != SUCCESS)) { + pr_err("[SSP]: %s - Magnetic Selftest Timeout!! %d\n", + __func__, iRet); + if (iTimeoutReties++ < 3) + goto reties; + else + goto exit; + } + + mdelay(5); + + iSF_X = (s16)((data->uFactorydata[0] << 8) + data->uFactorydata[1]); + iSF_Y = (s16)((data->uFactorydata[2] << 8) + data->uFactorydata[3]); + iSF_Z = (s16)((data->uFactorydata[4] << 8) + data->uFactorydata[5]); + + iSF_X = (s16)(((int)iSF_X * ((int)data->uFuseRomData[0] + 128)) >> 8); + iSF_Y = (s16)(((int)iSF_Y * ((int)data->uFuseRomData[1] + 128)) >> 8); + iSF_Z = (s16)(((int)iSF_Z * ((int)data->uFuseRomData[2] + 128)) >> 8); + + pr_info("[SSP] %s: self test x = %d, y = %d, z = %d\n", + __func__, iSF_X, iSF_Y, iSF_Z); + if ((iSF_X >= GYROSCOPE_SELFTEST_X_SPEC_MIN) + && (iSF_X <= GYROSCOPE_SELFTEST_X_SPEC_MAX)) + pr_info("[SSP] x passed self test, expect -200<=x<=200\n"); + else + pr_info("[SSP] x failed self test, expect -200<=x<=200\n"); + if ((iSF_Y >= GYROSCOPE_SELFTEST_Y_SPEC_MIN) + && (iSF_Y <= GYROSCOPE_SELFTEST_Y_SPEC_MAX)) + pr_info("[SSP] y passed self test, expect -200<=y<=200\n"); + else + pr_info("[SSP] y failed self test, expect -200<=y<=200\n"); + if ((iSF_Z >= GYROSCOPE_SELFTEST_Z_SPEC_MIN) + && (iSF_Z <= GYROSCOPE_SELFTEST_Z_SPEC_MAX)) + pr_info("[SSP] z passed self test, expect -3200<=z<=-800\n"); + else + pr_info("[SSP] z failed self test, expect -3200<=z<=-800\n"); + + if ((iSF_X >= GYROSCOPE_SELFTEST_X_SPEC_MIN) + && (iSF_X <= GYROSCOPE_SELFTEST_X_SPEC_MAX) + && (iSF_Y >= GYROSCOPE_SELFTEST_Y_SPEC_MIN) + && (iSF_Y <= GYROSCOPE_SELFTEST_Y_SPEC_MAX) + && (iSF_Z >= GYROSCOPE_SELFTEST_Z_SPEC_MIN) + && (iSF_Z <= GYROSCOPE_SELFTEST_Z_SPEC_MAX)) + bSelftestPassed = true; + + if ((bSelftestPassed == false) && (iSpecOutReties++ < 5)) + goto reties; +exit: + return sprintf(buf, "%u,%d,%d,%d\n", + bSelftestPassed, iSF_X, iSF_Y, iSF_Z); +} + +static ssize_t magnetic_check_registers(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 uBuf[13] = {0,}; + + return sprintf(buf, "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n", + uBuf[0], uBuf[1], uBuf[2], uBuf[3], uBuf[4], uBuf[5], + uBuf[6], uBuf[7], uBuf[8], uBuf[9], uBuf[10], uBuf[11], + uBuf[12]); +} + +static ssize_t magnetic_check_cntl(struct device *dev, + struct device_attribute *attr, char *strbuf) +{ + bool bSuccess = false; + + return sprintf(strbuf, "%s,%d,%d,%d\n", + (!bSuccess ? "OK" : "NG"), 0, 0, 0); +} + +static DEVICE_ATTR(name, S_IRUGO, magnetic_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, magnetic_vendor_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, raw_data_read, NULL); +static DEVICE_ATTR(status, S_IRUGO, magnetic_get_status, NULL); +static DEVICE_ATTR(adc, S_IRUGO, adc_data_read, NULL); +static DEVICE_ATTR(dac, S_IRUGO, magnetic_check_cntl, NULL); +static DEVICE_ATTR(selftest, S_IRUGO, magnetic_get_selftest, NULL); +static DEVICE_ATTR(ak8963_asa, S_IRUGO, magnetic_get_asa, NULL); +static DEVICE_ATTR(ak8963_chk_registers, S_IRUGO, + magnetic_check_registers, NULL); + +static struct device_attribute *mag_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_adc, + &dev_attr_raw_data, + &dev_attr_status, + &dev_attr_selftest, + &dev_attr_ak8963_asa, + &dev_attr_ak8963_chk_registers, + &dev_attr_dac, + NULL, +}; + +void initialize_magnetic_factorytest(struct ssp_data *data) +{ + sensors_register(data->mag_device, data, mag_attrs, "magnetic_sensor"); +} + +void remove_magnetic_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->mag_device, mag_attrs); +} |