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