aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sensor
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sensor')
-rw-r--r--drivers/sensor/Kconfig19
-rw-r--r--drivers/sensor/Makefile26
-rw-r--r--drivers/sensor/ak8963-reg.h48
-rw-r--r--drivers/sensor/ak8963.c880
-rw-r--r--drivers/sensor/ak8975.c6
-rw-r--r--drivers/sensor/al3201.c697
-rw-r--r--drivers/sensor/cm3663.c113
-rw-r--r--drivers/sensor/cm36651.c30
-rw-r--r--drivers/sensor/gp2a_light.c103
-rw-r--r--drivers/sensor/gp2a_proximity.c226
-rw-r--r--drivers/sensor/k3dh.c14
-rw-r--r--drivers/sensor/lps331ap.c20
-rw-r--r--drivers/sensor/lsm330dlc_accel.c17
-rw-r--r--drivers/sensor/lsm330dlc_gyro.c210
14 files changed, 2206 insertions, 203 deletions
diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig
index 4b0190a..f7888b9 100644
--- a/drivers/sensor/Kconfig
+++ b/drivers/sensor/Kconfig
@@ -19,6 +19,14 @@ config SENSORS_AK8975C
If you say yes here you get support for Asahi Kasei's
orientation sensor AK8975.
+config SENSORS_AK8963C
+ tristate "AK8963 compass support"
+ default n
+ depends on I2C
+ help
+ If you say yes here you get support for Asahi Kasei's
+ orientation sensor AK8963.
+
config SENSORS_BMP180
depends on I2C && SYSFS
tristate "BMP180 digital pressure sensor"
@@ -93,6 +101,17 @@ config SENSORS_BH1721
Say N here if you do not use BH1721.
+config SENSORS_AL3201
+ depends on I2C
+ tristate "AL3201 driver"
+ default n
+ help
+ Say Y here if you use AL3201.
+ This option enables light sensor using
+ ROHM AL3201 device driver.
+
+ Say N here if you do not use AL3201.
+
config SENSORS_K3DH
tristate "K3DH acceleration sensor support"
depends on I2C
diff --git a/drivers/sensor/Makefile b/drivers/sensor/Makefile
index 862074d..44adf31 100644
--- a/drivers/sensor/Makefile
+++ b/drivers/sensor/Makefile
@@ -5,18 +5,26 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_SENSORS_CORE) += sensors_core.o
-obj-$(CONFIG_SENSORS_AK8975C) += ak8975.o
-obj-$(CONFIG_SENSORS_BMP180) += bmp180.o
-obj-$(CONFIG_SENSORS_CM3663) += cm3663.o
-obj-$(CONFIG_SENSORS_BMA254) += bma254_driver.o
+# accelerometer_sensor
+obj-$(CONFIG_SENSORS_K3DH) += k3dh.o
+obj-$(CONFIG_SENSORS_BMA254) += bma254_driver.o
+# gyro_sensor
+obj-$(CONFIG_SENSORS_K3G) += k3g.o
+# combo chipset
+obj-$(CONFIG_SENSORS_LSM330DLC) += lsm330dlc_accel.o lsm330dlc_gyro.o
+# magnetic_sensor
+obj-$(CONFIG_SENSORS_AK8975C) += ak8975.o
+obj-$(CONFIG_SENSORS_AK8963C) += ak8963.o
+# optical_sensor
+obj-$(CONFIG_SENSORS_CM3663) += cm3663.o
obj-$(CONFIG_SENSORS_TAOS) += taos.o
obj-$(CONFIG_SENSORS_GP2A) += gp2a_proximity.o gp2a_light.o
obj-$(CONFIG_SENSORS_GP2A_ANALOG) += gp2a_analog.o
-obj-$(CONFIG_SENSORS_K3G) += k3g.o
-obj-$(CONFIG_SENSORS_K3DH) += k3dh.o
-obj-$(CONFIG_SENSORS_LSM330DLC) += lsm330dlc_accel.o lsm330dlc_gyro.o
-obj-$(CONFIG_SENSORS_LPS331) += lps331ap.o
obj-$(CONFIG_SENSORS_CM36651) += cm36651.o
+obj-$(CONFIG_SENSORS_BH1721) += bh1721.o
+obj-$(CONFIG_SENSORS_AL3201) += al3201.o
+# barometer_sensor
+obj-$(CONFIG_SENSORS_BMP180) += bmp180.o
+obj-$(CONFIG_SENSORS_LPS331) += lps331ap.o
# VE_GROUP
obj-$(CONFIG_SENSORS_PAS2M110) += pas2m110.o
-obj-$(CONFIG_SENSORS_BH1721) += bh1721.o
diff --git a/drivers/sensor/ak8963-reg.h b/drivers/sensor/ak8963-reg.h
new file mode 100644
index 0000000..067c250
--- /dev/null
+++ b/drivers/sensor/ak8963-reg.h
@@ -0,0 +1,48 @@
+/* linux/drivers/misc/AK8963-reg.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#ifndef __AK8963_REG__
+#define __AK8963_REG__
+
+/* Compass device dependent definition */
+#define AK8963_CNTL1_SNG_MEASURE 0x11
+#define AK8963_CNTL1_SELF_TEST 0x18
+#define AK8963_CNTL1_FUSE_ACCESS 0x1F
+#define AK8963_CNTL1_POWER_DOWN 0x10
+
+/* Rx buffer size. i.e ST,TMPS,H1X,H1Y,H1Z*/
+#define SENSOR_DATA_SIZE 8
+
+/* Read/Write buffer size.*/
+#define RWBUF_SIZE 16
+
+/* AK8963 register address */
+#define AK8963_REG_WIA 0x00
+#define AK8963_REG_INFO 0x01
+#define AK8963_REG_ST1 0x02
+#define AK8963_REG_HXL 0x03
+#define AK8963_REG_HXH 0x04
+#define AK8963_REG_HYL 0x05
+#define AK8963_REG_HYH 0x06
+#define AK8963_REG_HZL 0x07
+#define AK8963_REG_HZH 0x08
+#define AK8963_REG_ST2 0x09
+#define AK8963_REG_CNTL1 0x0A
+#define AK8963_REG_CNTL2 0x0B
+#define AK8963_REG_ASTC 0x0C
+#define AK8963_REG_TS1 0x0D
+#define AK8963_REG_TS2 0x0E
+#define AK8963_REG_I2CDIS 0x0F
+
+/* AK8963 fuse-rom address */
+#define AK8963_FUSE_ASAX 0x10
+#define AK8963_FUSE_ASAY 0x11
+#define AK8963_FUSE_ASAZ 0x12
+
+#endif /* __AK8963_REG__ */
diff --git a/drivers/sensor/ak8963.c b/drivers/sensor/ak8963.c
new file mode 100644
index 0000000..674deee
--- /dev/null
+++ b/drivers/sensor/ak8963.c
@@ -0,0 +1,880 @@
+/*
+ * Copyright (C) 2010, 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/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/sensor/ak8963.h>
+#include <linux/completion.h>
+#include "ak8963-reg.h"
+#include <linux/sensor/sensors_core.h>
+
+#if defined(CONFIG_SLP) || defined(CONFIG_MACH_GC1)
+#define FACTORY_TEST
+#else
+#undef FACTORY_TEST
+#endif
+#undef MAGNETIC_LOGGING
+
+#define VENDOR "AKM"
+#define CHIP_ID "AK8963C"
+
+
+struct akm8963_data {
+ struct i2c_client *this_client;
+ struct akm8963_platform_data *pdata;
+ struct mutex lock;
+ struct miscdevice akmd_device;
+ struct completion data_ready;
+ struct device *dev;
+ wait_queue_head_t state_wq;
+ u8 asa[3];
+ int irq;
+};
+
+
+static s32 akm8963_ecs_set_mode_power_down(struct akm8963_data *akm)
+{
+ s32 ret;
+ ret = i2c_smbus_write_byte_data(akm->this_client,
+ AK8963_REG_CNTL1, AK8963_CNTL1_POWER_DOWN);
+ return ret;
+}
+
+static int akm8963_ecs_set_mode(struct akm8963_data *akm, char mode)
+{
+ s32 ret;
+
+ switch (mode) {
+ case AK8963_CNTL1_SNG_MEASURE:
+ ret = i2c_smbus_write_byte_data(akm->this_client,
+ AK8963_REG_CNTL1, AK8963_CNTL1_SNG_MEASURE);
+ break;
+ case AK8963_CNTL1_FUSE_ACCESS:
+ ret = i2c_smbus_write_byte_data(akm->this_client,
+ AK8963_REG_CNTL1, AK8963_CNTL1_FUSE_ACCESS);
+ break;
+ case AK8963_CNTL1_POWER_DOWN:
+ ret = akm8963_ecs_set_mode_power_down(akm);
+ break;
+ case AK8963_CNTL1_SELF_TEST:
+ ret = i2c_smbus_write_byte_data(akm->this_client,
+ AK8963_REG_CNTL1, AK8963_CNTL1_SELF_TEST);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ /* Wait at least 300us after changing mode. */
+ udelay(300);
+
+ return 0;
+}
+
+static int akm8963_Reset(struct akm8963_data *akm)
+{
+ int err = 0;
+
+ gpio_set_value(GPIO_MSENSE_RST_N, 0);
+ udelay(5);
+ gpio_set_value(GPIO_MSENSE_RST_N, 1);
+ /* Device will be accessible 100 us after */
+ udelay(100);
+
+ return err;
+}
+
+static int akmd_copy_in(unsigned int cmd, void __user *argp,
+ void *buf, size_t buf_size)
+{
+ if (!(cmd & IOC_IN))
+ return 0;
+ if (_IOC_SIZE(cmd) > buf_size)
+ return -EINVAL;
+ if (copy_from_user(buf, argp, _IOC_SIZE(cmd)))
+ return -EFAULT;
+ return 0;
+}
+
+static int akmd_copy_out(unsigned int cmd, void __user *argp,
+ void *buf, size_t buf_size)
+{
+ if (!(cmd & IOC_OUT))
+ return 0;
+ if (_IOC_SIZE(cmd) > buf_size)
+ return -EINVAL;
+ if (copy_to_user(argp, buf, _IOC_SIZE(cmd)))
+ return -EFAULT;
+ return 0;
+}
+
+static void akm8963_disable_irq(struct akm8963_data *akm)
+{
+ disable_irq(akm->irq);
+ if (try_wait_for_completion(&akm->data_ready)) {
+ /* we actually got the interrupt before we could disable it
+ * so we need to enable again to undo our disable since the
+ * irq_handler already disabled it
+ */
+ enable_irq(akm->irq);
+ }
+}
+
+static irqreturn_t akm8963_irq_handler(int irq, void *data)
+{
+ struct akm8963_data *akm = data;
+ disable_irq_nosync(irq);
+ complete(&akm->data_ready);
+ return IRQ_HANDLED;
+}
+
+static int akm8963_wait_for_data_ready(struct akm8963_data *akm)
+{
+ int data_ready = gpio_get_value(akm->pdata->gpio_data_ready_int);
+ int err;
+
+ if (data_ready)
+ return 0;
+
+ enable_irq(akm->irq);
+
+ err = wait_for_completion_timeout(&akm->data_ready, 2*HZ);
+ if (err > 0)
+ return 0;
+
+ akm8963_disable_irq(akm);
+
+ if (err == 0) {
+ pr_err("akm: wait timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ pr_err("akm: wait restart\n");
+ return err;
+}
+
+static ssize_t akmd_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct akm8963_data *akm = container_of(file->private_data,
+ struct akm8963_data, akmd_device);
+ short x = 0, y = 0, z = 0;
+ int ret;
+ u8 data[8];
+
+ mutex_lock(&akm->lock);
+ ret = akm8963_ecs_set_mode(akm, AK8963_CNTL1_SNG_MEASURE);
+ if (ret) {
+ mutex_unlock(&akm->lock);
+ goto done;
+ }
+ ret = akm8963_wait_for_data_ready(akm);
+ if (ret) {
+ mutex_unlock(&akm->lock);
+ goto done;
+ }
+ ret = i2c_smbus_read_i2c_block_data(akm->this_client, AK8963_REG_ST1,
+ sizeof(data), data);
+ mutex_unlock(&akm->lock);
+
+ if (ret != sizeof(data)) {
+ pr_err("%s: failed to read %d bytes of mag data\n",
+ __func__, sizeof(data));
+ goto done;
+ }
+
+ if (data[0] & 0x01) {
+ x = (data[2] << 8) + data[1];
+ y = (data[4] << 8) + data[3];
+ z = (data[6] << 8) + data[5];
+ } else
+ pr_err("%s: invalid raw data(st1 = %d)\n",
+ __func__, data[0] & 0x01);
+
+done:
+ return sprintf(buf, "%d,%d,%d\n", x, y, z);
+}
+
+static long akmd_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct akm8963_data *akm = container_of(file->private_data,
+ struct akm8963_data, akmd_device);
+ int ret;
+ #ifdef MAGNETIC_LOGGING
+ short x, y, z;
+ #endif
+ union {
+ char raw[RWBUF_SIZE];
+ int status;
+ char mode;
+ u8 data[8];
+ } rwbuf;
+
+ ret = akmd_copy_in(cmd, argp, rwbuf.raw, sizeof(rwbuf));
+ if (ret)
+ return ret;
+
+ switch (cmd) {
+ case ECS_IOCTL_WRITE:
+ if ((rwbuf.raw[0] < 2) || (rwbuf.raw[0] > (RWBUF_SIZE - 1)))
+ return -EINVAL;
+ if (copy_from_user(&rwbuf.raw[2], argp+2, rwbuf.raw[0]-1))
+ return -EFAULT;
+
+ ret = i2c_smbus_write_i2c_block_data(akm->this_client,
+ rwbuf.raw[1],
+ rwbuf.raw[0] - 1,
+ &rwbuf.raw[2]);
+ break;
+ case ECS_IOCTL_READ:
+ if ((rwbuf.raw[0] < 1) || (rwbuf.raw[0] > (RWBUF_SIZE - 1)))
+ return -EINVAL;
+
+ ret = i2c_smbus_read_i2c_block_data(akm->this_client,
+ rwbuf.raw[1],
+ rwbuf.raw[0],
+ &rwbuf.raw[1]);
+ if (ret < 0)
+ return ret;
+ if (copy_to_user(argp+1, rwbuf.raw+1, rwbuf.raw[0]))
+ return -EFAULT;
+ return 0;
+ case ECS_IOCTL_SET_MODE:
+ mutex_lock(&akm->lock);
+ ret = akm8963_ecs_set_mode(akm, rwbuf.mode);
+ mutex_unlock(&akm->lock);
+ break;
+ case ECS_IOCTL_RESET:
+ akm8963_Reset(akm);
+ break;
+ case ECS_IOCTL_GETDATA:
+ mutex_lock(&akm->lock);
+ ret = akm8963_wait_for_data_ready(akm);
+ if (ret) {
+ mutex_unlock(&akm->lock);
+ return ret;
+ }
+ ret = i2c_smbus_read_i2c_block_data(akm->this_client,
+ AK8963_REG_ST1,
+ sizeof(rwbuf.data),
+ rwbuf.data);
+
+ #ifdef MAGNETIC_LOGGING
+ x = (rwbuf.data[2] << 8) + rwbuf.data[1];
+ y = (rwbuf.data[4] << 8) + rwbuf.data[3];
+ z = (rwbuf.data[6] << 8) + rwbuf.data[5];
+
+ pr_info("%s:ST1=%d, x=%d, y=%d, z=%d, ST2=%d\n",
+ __func__, rwbuf.data[0], x, y, z, rwbuf.data[7]);
+ #endif
+
+ mutex_unlock(&akm->lock);
+ if (ret != sizeof(rwbuf.data)) {
+ pr_err("%s : failed to read %d bytes of mag data\n",
+ __func__, sizeof(rwbuf.data));
+ return -EIO;
+ }
+ break;
+ default:
+ return -ENOTTY;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return akmd_copy_out(cmd, argp, rwbuf.raw, sizeof(rwbuf));
+}
+
+static const struct file_operations akmd_fops = {
+ .owner = THIS_MODULE,
+ .open = nonseekable_open,
+ .read = akmd_read,
+ .unlocked_ioctl = akmd_ioctl,
+};
+
+static int akm8963_setup_irq(struct akm8963_data *akm)
+{
+ int rc = -EIO;
+ struct akm8963_platform_data *pdata = akm->pdata;
+ int irq;
+
+ if (akm->this_client->irq)
+ irq = akm->this_client->irq;
+ else {
+ rc = gpio_request(pdata->gpio_data_ready_int, "gpio_akm_int");
+ if (rc < 0) {
+ pr_err("%s: gpio %d request failed (%d)\n",
+ __func__, pdata->gpio_data_ready_int, rc);
+ return rc;
+ }
+
+ rc = gpio_direction_input(pdata->gpio_data_ready_int);
+ if (rc < 0) {
+ pr_err("%s: failed to set gpio %d as input (%d)\n",
+ __func__, pdata->gpio_data_ready_int, rc);
+ goto err_request_irq;
+ }
+
+ irq = gpio_to_irq(pdata->gpio_data_ready_int);
+ }
+ /* trigger high so we don't miss initial interrupt if it
+ * is already pending
+ */
+ rc = request_irq(irq, akm8963_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "akm_int", akm);
+ if (rc < 0) {
+ pr_err("%s: request_irq(%d) failed for gpio %d (%d)\n",
+ __func__, irq,
+ pdata->gpio_data_ready_int, rc);
+ goto err_request_irq;
+ }
+
+ /* start with interrupt disabled until the driver is enabled */
+ akm->irq = irq;
+ akm8963_disable_irq(akm);
+
+ goto done;
+
+err_request_irq:
+ gpio_free(pdata->gpio_data_ready_int);
+done:
+ return rc;
+}
+
+#ifdef FACTORY_TEST
+static int ak8963c_selftest(struct akm8963_data *ak_data, int *sf)
+{
+ u8 buf[6];
+ s16 x, y, z;
+
+ /* read device info */
+ i2c_smbus_read_i2c_block_data(ak_data->this_client,
+ AK8963_REG_WIA, 2, buf);
+ pr_info("%s: device id = 0x%x, info = 0x%x\n",
+ __func__, buf[0], buf[1]);
+
+ /* set ATSC self test bit to 1 */
+ i2c_smbus_write_byte_data(ak_data->this_client,
+ AK8963_REG_ASTC, 0x40);
+
+ /* start self test */
+ i2c_smbus_write_byte_data(ak_data->this_client,
+ AK8963_REG_CNTL1,
+ AK8963_CNTL1_SELF_TEST);
+
+ /* wait for data ready */
+ while (1) {
+ msleep(20);
+ if (i2c_smbus_read_byte_data(ak_data->this_client,
+ AK8963_REG_ST1) == 1) {
+ break;
+ }
+ }
+
+ i2c_smbus_read_i2c_block_data(ak_data->this_client,
+ AK8963_REG_HXL, sizeof(buf), buf);
+
+ /* set ATSC self test bit to 0 */
+ i2c_smbus_write_byte_data(ak_data->this_client,
+ AK8963_REG_ASTC, 0x00);
+
+ x = buf[0] | (buf[1] << 8);
+ y = buf[2] | (buf[3] << 8);
+ z = buf[4] | (buf[5] << 8);
+
+ /* Hadj = (H*(Asa+128))/256 */
+ x = (x*(ak_data->asa[0] + 128)) >> 8;
+ y = (y*(ak_data->asa[1] + 128)) >> 8;
+ z = (z*(ak_data->asa[2] + 128)) >> 8;
+
+ pr_info("%s: self test x = %d, y = %d, z = %d\n",
+ __func__, x, y, z);
+ if ((x >= -200) && (x <= 200))
+ pr_info("%s: x passed self test, expect -200<=x<=200\n",
+ __func__);
+ else
+ pr_info("%s: x failed self test, expect -200<=x<=200\n",
+ __func__);
+ if ((y >= -200) && (y <= 200))
+ pr_info("%s: y passed self test, expect -200<=y<=200\n",
+ __func__);
+ else
+ pr_info("%s: y failed self test, expect -200<=y<=200\n",
+ __func__);
+ if ((z >= -3200) && (z <= -800))
+ pr_info("%s: z passed self test, expect -3200<=z<=-800\n",
+ __func__);
+ else
+ pr_info("%s: z failed self test, expect -3200<=z<=-800\n",
+ __func__);
+
+ sf[0] = x;
+ sf[1] = y;
+ sf[2] = z;
+
+ if (((x >= -200) && (x <= 200)) &&
+ ((y >= -200) && (y <= 200)) &&
+ ((z >= -3200) && (z <= -800)))
+ return 1;
+ else
+ return 0;
+}
+
+static ssize_t ak8963c_get_asa(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct akm8963_data *ak_data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d, %d, %d\n", ak_data->asa[0],
+ ak_data->asa[1], ak_data->asa[2]);
+}
+
+static ssize_t ak8963c_get_selftest(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret = 0;
+ int sf[3] = {0,};
+
+ ret = ak8963c_selftest(dev_get_drvdata(dev), sf);
+ return sprintf(buf, "%d, %d, %d, %d\n", ret, sf[0], sf[1], sf[2]);
+}
+
+static ssize_t ak8963c_check_registers(struct device *dev,
+ struct device_attribute *attr, char *strbuf)
+{
+ struct akm8963_data *ak_data = dev_get_drvdata(dev);
+ u8 buf[13];
+
+ /* power down */
+ i2c_smbus_write_byte_data(ak_data->this_client,
+ AK8963_REG_CNTL1, AK8963_CNTL1_POWER_DOWN);
+
+ /* get the value */
+ i2c_smbus_read_i2c_block_data(ak_data->this_client,
+ AK8963_REG_WIA, 11, buf);
+
+ buf[11] = i2c_smbus_read_byte_data(ak_data->this_client,
+ AK8963_REG_ASTC);
+ buf[12] = i2c_smbus_read_byte_data(ak_data->this_client,
+ AK8963_REG_I2CDIS);
+
+
+ return sprintf(strbuf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
+ buf[6], buf[7], buf[8], buf[9], buf[10], buf[11],
+ buf[12]);
+}
+
+static ssize_t ak8963c_check_cntl(struct device *dev,
+ struct device_attribute *attr, char *strbuf)
+{
+ struct akm8963_data *ak_data = dev_get_drvdata(dev);
+ u8 buf;
+ int err;
+
+ /* power down */
+ err = i2c_smbus_write_byte_data(ak_data->this_client,
+ AK8963_REG_CNTL1, AK8963_CNTL1_POWER_DOWN);
+
+ buf = i2c_smbus_read_byte_data(ak_data->this_client,
+ AK8963_REG_CNTL1);
+
+ return sprintf(strbuf, "%s\n",
+ ((buf == AK8963_CNTL1_POWER_DOWN) ? "OK" : "NG"));
+}
+
+static ssize_t ak8963c_get_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct akm8963_data *ak_data = dev_get_drvdata(dev);
+ int success;
+
+ if ((ak_data->asa[0] == 0) | (ak_data->asa[0] == 0xff)
+ | (ak_data->asa[1] == 0) | (ak_data->asa[1] == 0xff)
+ | (ak_data->asa[2] == 0) | (ak_data->asa[2] == 0xff))
+ success = 0;
+ else
+ success = 1;
+
+ return sprintf(buf, "%s\n", (success ? "OK" : "NG"));
+}
+
+static ssize_t ak8963_adc(struct device *dev,
+ struct device_attribute *attr, char *strbuf)
+{
+ struct akm8963_data *ak_data = dev_get_drvdata(dev);
+ u8 buf[8];
+ s16 x, y, z;
+ int err, success;
+
+ /* start ADC conversion */
+ err = i2c_smbus_write_byte_data(ak_data->this_client,
+ AK8963_REG_CNTL1, AK8963_CNTL1_SNG_MEASURE);
+
+ /* wait for ADC conversion to complete */
+ err = akm8963_wait_for_data_ready(ak_data);
+ if (err) {
+ pr_err("%s: wait for data ready failed\n", __func__);
+ return err;
+ }
+ msleep(20);
+ /* get the value and report it */
+ err = i2c_smbus_read_i2c_block_data(ak_data->this_client,
+ AK8963_REG_ST1, sizeof(buf), buf);
+ if (err != sizeof(buf)) {
+ pr_err("%s: read data over i2c failed\n", __func__);
+ return err;
+ }
+
+ /* buf[0] is status1, buf[7] is status2 */
+ if ((buf[0] == 0) | (buf[7] == 1))
+ success = 0;
+ else
+ success = 1;
+
+ x = buf[1] | (buf[2] << 8);
+ y = buf[3] | (buf[4] << 8);
+ z = buf[5] | (buf[6] << 8);
+
+ pr_info("raw x = %d, y = %d, z = %d\n", x, y, z);
+ return sprintf(strbuf,
+ "%s, %d, %d, %d\n", (success ? "OK" : "NG"), x, y, z);
+}
+#endif
+
+static ssize_t ak8963_show_raw_data(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct akm8963_data *akm = dev_get_drvdata(dev);
+ short x = 0, y = 0, z = 0;
+ int ret;
+ u8 data[8] = {0,};
+
+ mutex_lock(&akm->lock);
+ ret = akm8963_ecs_set_mode(akm, AK8963_CNTL1_SNG_MEASURE);
+ if (ret) {
+ mutex_unlock(&akm->lock);
+ goto done;
+ }
+ ret = akm8963_wait_for_data_ready(akm);
+ if (ret) {
+ mutex_unlock(&akm->lock);
+ goto done;
+ }
+ ret = i2c_smbus_read_i2c_block_data(akm->this_client, AK8963_REG_ST1,
+ sizeof(data), data);
+ mutex_unlock(&akm->lock);
+
+ if (ret != sizeof(data)) {
+ pr_err("%s: failed to read %d bytes of mag data\n",
+ __func__, sizeof(data));
+ goto done;
+ }
+
+ if (data[0] & 0x01) {
+ x = (data[2] << 8) + data[1];
+ y = (data[4] << 8) + data[3];
+ z = (data[6] << 8) + data[5];
+ } else
+ pr_err("%s: invalid raw data(st1 = %d)\n",
+ __func__, data[0] & 0x01);
+
+done:
+ return sprintf(buf, "%d,%d,%d\n", x, y, z);
+}
+
+static ssize_t ak8963_show_vendor(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", VENDOR);
+}
+
+static ssize_t ak8963_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", CHIP_ID);
+}
+
+static DEVICE_ATTR(raw_data, 0664,
+ ak8963_show_raw_data, NULL);
+static DEVICE_ATTR(vendor, 0664,
+ ak8963_show_vendor, NULL);
+static DEVICE_ATTR(name, 0664,
+ ak8963_show_name, NULL);
+
+#ifdef FACTORY_TEST
+static DEVICE_ATTR(asa, 0664,
+ ak8963c_get_asa, NULL);
+static DEVICE_ATTR(selftest, 0664,
+ ak8963c_get_selftest, NULL);
+static DEVICE_ATTR(chk_registers, 0664,
+ ak8963c_check_registers, NULL);
+static DEVICE_ATTR(dac, 0664,
+ ak8963c_check_cntl, NULL);
+static DEVICE_ATTR(status, 0664,
+ ak8963c_get_status, NULL);
+static DEVICE_ATTR(adc, 0664,
+ ak8963_adc, NULL);
+#endif
+
+int akm8963_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct akm8963_data *akm;
+ int err;
+
+ pr_info("%s is called.\n", __func__);
+ if (client->dev.platform_data == NULL && client->irq == 0) {
+ dev_err(&client->dev, "platform data & irq are NULL.\n");
+ err = -ENODEV;
+ goto exit_platform_data_null;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "I2C check failed, exiting.\n");
+ err = -ENODEV;
+ goto exit_check_functionality_failed;
+ }
+
+ akm = kzalloc(sizeof(struct akm8963_data), GFP_KERNEL);
+ if (!akm) {
+ dev_err(&client->dev,
+ "failed to allocate memory for module data\n");
+ err = -ENOMEM;
+ goto exit_alloc_data_failed;
+ }
+
+ akm->pdata = client->dev.platform_data;
+ mutex_init(&akm->lock);
+ init_completion(&akm->data_ready);
+
+ i2c_set_clientdata(client, akm);
+ akm->this_client = client;
+
+ err = akm8963_ecs_set_mode_power_down(akm);
+ if (err < 0) {
+ pr_err("%s: akm8963_ecs_set_mode_power_down fail(err=%d)\n",
+ __func__, err);
+ goto exit_set_mode_power_down_failed;
+ }
+
+ err = akm8963_setup_irq(akm);
+ if (err) {
+ pr_err("%s: could not setup irq\n", __func__);
+ goto exit_setup_irq;
+ }
+
+ akm->akmd_device.minor = MISC_DYNAMIC_MINOR;
+ akm->akmd_device.name = "akm8963";
+ akm->akmd_device.fops = &akmd_fops;
+
+ err = misc_register(&akm->akmd_device);
+ if (err) {
+ pr_err("%s, misc_register failed.\n", __func__);
+ goto exit_akmd_device_register_failed;
+ }
+
+ init_waitqueue_head(&akm->state_wq);
+
+ /* put into fuse access mode to read asa data */
+ err = i2c_smbus_write_byte_data(client, AK8963_REG_CNTL1,
+ AK8963_CNTL1_FUSE_ACCESS);
+ if (err) {
+ pr_err("%s: unable to enter fuse rom mode\n", __func__);
+ goto exit_i2c_failed;
+ }
+
+ err = i2c_smbus_read_i2c_block_data(client, AK8963_FUSE_ASAX,
+ sizeof(akm->asa), akm->asa);
+ if (err != sizeof(akm->asa)) {
+ pr_err("%s: unable to load factory sensitivity adjust values\n",
+ __func__);
+ goto exit_i2c_failed;
+ } else
+ pr_info("%s: asa_x = %d, asa_y = %d, asa_z = %d\n", __func__,
+ akm->asa[0], akm->asa[1], akm->asa[2]);
+
+ err = i2c_smbus_write_byte_data(client, AK8963_REG_CNTL1,
+ AK8963_CNTL1_POWER_DOWN);
+ if (err) {
+ dev_err(&client->dev, "Error in setting power down mode\n");
+ goto exit_i2c_failed;
+ }
+
+ akm->dev = sensors_classdev_register("magnetic_sensor");
+ if (IS_ERR(akm->dev)) {
+ pr_err("Failed to create device!");
+ goto exit_class_create_failed;
+ }
+
+ if (device_create_file(akm->dev, &dev_attr_raw_data) < 0) {
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_raw_data.attr.name);
+ goto exit_device_create_raw_data;
+ }
+
+ if (device_create_file(akm->dev, &dev_attr_vendor) < 0) {
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_name.attr.name);
+ goto exit_device_create_vendor;
+ }
+
+ if (device_create_file(akm->dev, &dev_attr_name) < 0) {
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_raw_data.attr.name);
+ goto exit_device_create_name;
+ }
+
+#ifdef FACTORY_TEST
+ if (device_create_file(akm->dev, &dev_attr_adc) < 0) {
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_adc.attr.name);
+ goto exit_device_create_file1;
+ }
+
+ if (device_create_file(akm->dev, &dev_attr_status) < 0) {
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_status.attr.name);
+ goto exit_device_create_file2;
+ }
+
+ if (device_create_file(akm->dev, &dev_attr_asa) < 0) {
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_asa.attr.name);
+ goto exit_device_create_file3;
+ }
+ if (device_create_file(akm->dev, &dev_attr_selftest) < 0) {
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_selftest.attr.name);
+ goto exit_device_create_file4;
+ }
+ if (device_create_file(akm->dev,
+ &dev_attr_chk_registers) < 0) {
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_chk_registers.attr.name);
+ goto exit_device_create_file5;
+ }
+ if (device_create_file(akm->dev, &dev_attr_dac) < 0) {
+ pr_err("Failed to create device file(%s)!\n",
+ dev_attr_dac.attr.name);
+ goto exit_device_create_file6;
+ }
+#endif
+ dev_set_drvdata(akm->dev, akm);
+
+pr_info("%s is successful.\n", __func__);
+return 0;
+
+#ifdef FACTORY_TEST
+exit_device_create_file6:
+ device_remove_file(akm->dev, &dev_attr_chk_registers);
+exit_device_create_file5:
+ device_remove_file(akm->dev, &dev_attr_selftest);
+exit_device_create_file4:
+ device_remove_file(akm->dev, &dev_attr_asa);
+exit_device_create_file3:
+ device_remove_file(akm->dev, &dev_attr_status);
+exit_device_create_file2:
+ device_remove_file(akm->dev, &dev_attr_adc);
+exit_device_create_file1:
+ device_remove_file(akm->dev, &dev_attr_name);
+#endif
+exit_device_create_name:
+ device_remove_file(akm->dev, &dev_attr_vendor);
+exit_device_create_vendor:
+ device_remove_file(akm->dev, &dev_attr_raw_data);
+exit_device_create_raw_data:
+ sensors_classdev_unregister(akm->dev);
+exit_class_create_failed:
+exit_i2c_failed:
+ misc_deregister(&akm->akmd_device);
+exit_akmd_device_register_failed:
+ free_irq(akm->irq, akm);
+ gpio_free(akm->pdata->gpio_data_ready_int);
+exit_setup_irq:
+exit_set_mode_power_down_failed:
+ mutex_destroy(&akm->lock);
+ kfree(akm);
+exit_alloc_data_failed:
+exit_check_functionality_failed:
+exit_platform_data_null:
+ return err;
+}
+
+static int __devexit akm8963_remove(struct i2c_client *client)
+{
+ struct akm8963_data *akm = i2c_get_clientdata(client);
+
+ #ifdef FACTORY_TEST
+ device_remove_file(akm->dev, &dev_attr_adc);
+ device_remove_file(akm->dev, &dev_attr_status);
+ device_remove_file(akm->dev, &dev_attr_asa);
+ device_remove_file(akm->dev, &dev_attr_selftest);
+ device_remove_file(akm->dev, &dev_attr_chk_registers);
+ device_remove_file(akm->dev, &dev_attr_dac);
+ #endif
+ device_remove_file(akm->dev, &dev_attr_name);
+ device_remove_file(akm->dev, &dev_attr_vendor);
+ device_remove_file(akm->dev, &dev_attr_raw_data);
+ sensors_classdev_unregister(akm->dev);
+ misc_deregister(&akm->akmd_device);
+ free_irq(akm->irq, akm);
+ gpio_free(akm->pdata->gpio_data_ready_int);
+ mutex_destroy(&akm->lock);
+ kfree(akm);
+ return 0;
+}
+
+static const struct i2c_device_id akm8963_id[] = {
+ {AKM8963_I2C_NAME, 0 },
+ { }
+};
+
+static struct i2c_driver akm8963_driver = {
+ .probe = akm8963_probe,
+ .remove = akm8963_remove,
+ .id_table = akm8963_id,
+ .driver = {
+ .name = AKM8963_I2C_NAME,
+ },
+};
+
+static int __init akm8963_init(void)
+{
+ return i2c_add_driver(&akm8963_driver);
+}
+
+static void __exit akm8963_exit(void)
+{
+ i2c_del_driver(&akm8963_driver);
+}
+
+module_init(akm8963_init);
+module_exit(akm8963_exit);
+
+MODULE_DESCRIPTION("AKM8963 compass driver");
+MODULE_AUTHOR("Samsung Electronics");
+MODULE_LICENSE("GPL");
diff --git a/drivers/sensor/ak8975.c b/drivers/sensor/ak8975.c
index 3d90128..57ab5cf 100644
--- a/drivers/sensor/ak8975.c
+++ b/drivers/sensor/ak8975.c
@@ -27,7 +27,11 @@
#include "ak8975-reg.h"
#include <linux/sensor/sensors_core.h>
+#ifdef CONFIG_SLP
+#define FACTORY_TEST
+#else
#undef FACTORY_TEST
+#endif
#undef MAGNETIC_LOGGING
#define VENDOR "AKM"
@@ -744,8 +748,6 @@ int akm8975_probe(struct i2c_client *client,
}
#ifdef FACTORY_TEST
- ak8975c_selftest(akm);
-
if (device_create_file(akm->dev, &dev_attr_adc) < 0) {
printk(KERN_ERR "Failed to create device file(%s)!\n",
dev_attr_adc.attr.name);
diff --git a/drivers/sensor/al3201.c b/drivers/sensor/al3201.c
new file mode 100644
index 0000000..a225b1a
--- /dev/null
+++ b/drivers/sensor/al3201.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/sensor/sensors_core.h>
+
+#undef LSC_DBG
+
+#define SENSOR_AL3201_ADDR 0x1c
+#define SENSOR_BH1721FVC_ADDR 0x23
+
+#define VENDOR_NAME "LIGHTON"
+#define CHIP_NAME "AL3201"
+#define DRIVER_VERSION "1.0"
+
+#define LUX_MIN_VALUE 0
+#define LUX_MAX_VALUE 65535
+#define DARK_COUNT 5
+
+#define AL3201_RAN_COMMAND 0x01
+#define AL3201_RAN_MASK 0x01
+#define AL3201_RAN_SHIFT (0)
+#define AL3201_RST_MASK 0x03
+#define AL3201_RST_SHIFT (2)
+
+#define AL3201_RT_COMMAND 0x02
+#define AL3201_RT_MASK 0x03
+#define AL3201_RT_SHIFT (0)
+
+#define AL3201_POW_COMMAND 0x00
+#define AL3201_POW_MASK 0x03
+#define AL3201_POW_UP 0x03
+#define AL3201_POW_DOWN 0x00
+#define AL3201_POW_SHIFT (0)
+
+#define AL3201_ADC_LSB 0x0c
+#define AL3201_ADC_MSB 0x0d
+
+#define AL3201_NUM_CACHABLE_REGS 5
+
+static const u8 al3201_reg[AL3201_NUM_CACHABLE_REGS] = {
+ 0x00,
+ 0x01,
+ 0x02,
+ 0x0c,
+ 0x0d
+};
+
+enum SENSOR_STATE {
+ OFF = 0,
+ ON = 1,
+};
+
+struct al3201_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ struct input_dev *input;
+ struct work_struct work_light;
+ struct workqueue_struct *wq;
+ struct hrtimer timer;
+ struct device *light_dev;
+
+ ktime_t light_poll_delay;
+
+ u8 reg_cache[AL3201_NUM_CACHABLE_REGS];
+ int state;
+};
+
+/*
+ * register access helpers
+ */
+static int al3201_read_reg(struct i2c_client *client,
+ u32 reg, u8 mask, u8 shift)
+{
+ struct al3201_data *data = i2c_get_clientdata(client);
+
+ return (data->reg_cache[reg] & mask) >> shift;
+}
+
+static int al3201_write_reg(struct i2c_client *client,
+ u32 reg, u8 mask, u8 shift, u8 val)
+{
+ u8 tmp;
+ int ret = 0;
+ struct al3201_data *data = i2c_get_clientdata(client);
+
+ if (reg >= AL3201_NUM_CACHABLE_REGS)
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ tmp = data->reg_cache[reg];
+ tmp &= ~mask;
+ tmp |= val << shift;
+
+ ret = i2c_smbus_write_byte_data(client, reg, tmp);
+ if (!ret)
+ data->reg_cache[reg] = tmp;
+ else
+ pr_err("%s: I2C read failed!\n", __func__);
+
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+/*
+ * internally used functions
+ */
+
+/* range */
+/*
+static int al3201_sw_reset(struct i2c_client *client)
+{
+ al3201_write_reg(client, AL3201_RAN_COMMAND,
+ AL3201_RST_MASK, AL3201_RST_SHIFT, 0x02);
+ msleep(20);
+ al3201_write_reg(client, AL3201_RAN_COMMAND,
+ AL3201_RST_MASK, AL3201_RST_SHIFT, 0x00);
+ return 0;
+}
+*/
+
+static int al3201_get_range(struct i2c_client *client)
+{
+ int tmp;
+ tmp = al3201_read_reg(client, AL3201_RAN_COMMAND,
+ AL3201_RAN_MASK, AL3201_RAN_SHIFT);
+ return tmp;
+}
+
+static int al3201_set_range(struct i2c_client *client, int range)
+{
+ return al3201_write_reg(client, AL3201_RAN_COMMAND,
+ AL3201_RAN_MASK, AL3201_RAN_SHIFT, range);
+}
+
+/* Response time */
+static int al3201_set_response_time(struct i2c_client *client, int time)
+{
+ return al3201_write_reg(client, AL3201_RT_COMMAND,
+ AL3201_RT_MASK, AL3201_RT_SHIFT, time);
+}
+
+/* power_state */
+static int al3201_set_power_state(struct i2c_client *client, int state)
+{
+ return al3201_write_reg(client, AL3201_POW_COMMAND,
+ AL3201_POW_MASK, AL3201_POW_SHIFT,
+ state ? AL3201_POW_UP : AL3201_POW_DOWN);
+}
+/*
+static int al3201_get_power_state(struct i2c_client *client)
+{
+ u8 cmdreg;
+ struct al3201_data *data = i2c_get_clientdata(client);
+
+ cmdreg = data->reg_cache[AL3201_POW_COMMAND];
+ return (cmdreg & AL3201_POW_MASK) >> AL3201_POW_SHIFT;
+} */
+
+/* power & timer enable */
+static int al3201_enable(struct al3201_data *data)
+{
+ int err;
+
+ err = al3201_set_power_state(data->client, ON);
+ if (err) {
+ pr_err("%s: Failed to write byte (POWER_UP)\n", __func__);
+ return err;
+ }
+
+ hrtimer_start(&data->timer, ns_to_ktime(300000000), HRTIMER_MODE_REL);
+
+ return err;
+}
+
+/* power & timer disable */
+static int al3201_disable(struct al3201_data *data)
+{
+ int err;
+
+ hrtimer_cancel(&data->timer);
+ cancel_work_sync(&data->work_light);
+
+ err = al3201_set_power_state(data->client, OFF);
+ if (unlikely(err != 0))
+ pr_err("%s: Failed to write byte (POWER_DOWN)\n", __func__);
+
+ return err;
+}
+
+static int al3201_get_adc_value(struct i2c_client *client)
+{
+ int lsb, msb, range;
+ u32 val;
+ struct al3201_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->lock);
+
+ lsb = i2c_smbus_read_byte_data(client, AL3201_ADC_LSB);
+ if (lsb < 0) {
+ mutex_unlock(&data->lock);
+ return lsb;
+ }
+
+ msb = i2c_smbus_read_byte_data(client, AL3201_ADC_MSB);
+
+ mutex_unlock(&data->lock);
+
+ if (msb < 0)
+ return msb;
+
+ range = al3201_get_range(client);
+ val = (u32) (msb << 8 | lsb);
+ if (val <= DARK_COUNT)
+ val = 0;
+
+ return val;
+}
+
+static void al3201_work_func_light(struct work_struct *work)
+{
+ int result = 0;
+
+ struct al3201_data *data =
+ container_of(work, struct al3201_data, work_light);
+
+ result = al3201_get_adc_value(data->client);
+
+ if (result == 0)
+ result = -1;
+#ifdef LSC_DBG
+ pr_info("%s, value = %d\n", __func__, result);
+#endif
+ input_report_rel(data->input, REL_MISC, result);
+ input_sync(data->input);
+
+}
+
+static enum hrtimer_restart al3201_timer_func(struct hrtimer *timer)
+{
+ struct al3201_data *data =
+ container_of(timer, struct al3201_data, timer);
+
+ queue_work(data->wq, &data->work_light);
+ hrtimer_forward_now(&data->timer, data->light_poll_delay);
+
+ return HRTIMER_RESTART;
+}
+
+/*
+ * sysfs layer
+ */
+static ssize_t al3201_raw_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int result;
+ struct input_dev *input = to_input_dev(dev);
+ struct al3201_data *data = input_get_drvdata(input);
+
+ /* No LUX data if not operational */
+ if (data->state == OFF) {
+ al3201_set_power_state(data->client, ON);
+ msleep(180);
+ }
+
+ result = al3201_get_adc_value(data->client);
+
+ if (data->state == OFF)
+ al3201_set_power_state(data->client, OFF);
+
+ return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t get_vendor_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", VENDOR_NAME);
+}
+
+static ssize_t get_chip_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", CHIP_NAME);
+}
+
+static DEVICE_ATTR(raw_data, 0644, al3201_raw_data_show, NULL);
+static DEVICE_ATTR(vendor, 0644, get_vendor_name, NULL);
+static DEVICE_ATTR(name, 0644, get_chip_name, NULL);
+
+/* factory test*/
+#ifdef LSC_DBG
+/* engineer mode */
+static ssize_t al3201_em_read(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 tmp;
+ int i;
+ struct input_dev *input = to_input_dev(dev);
+ struct al3201_data *data = input_get_drvdata(input);
+
+ for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
+ mutex_lock(&data->lock);
+ tmp = i2c_smbus_read_byte_data(data->client, al3201_reg[i]);
+ mutex_unlock(&data->lock);
+
+ pr_info("%s, Reg[0x%x] Val[0x%x]\n", __func__,
+ al3201_reg[i], tmp);
+ }
+ return 0;
+}
+
+static ssize_t al3201_em_write(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret = 0;
+ u32 addr, val;
+ struct input_dev *input = to_input_dev(dev);
+ struct al3201_data *data = input_get_drvdata(input);
+
+ sscanf(buf, "%x%x", &addr, &val);
+ pr_info("%s, Write [%x] to Reg[%x]...\n", __func__, val, addr);
+
+ mutex_lock(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(data->client, addr, val);
+ if (!ret)
+ data->reg_cache[addr] = val;
+
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(em, S_IWUSR | S_IRUGO, al3201_em_read, al3201_em_write);
+#endif
+
+static ssize_t al3201_poll_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct al3201_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%lld\n", ktime_to_ns(data->light_poll_delay));
+}
+
+static ssize_t al3201_poll_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int err;
+ int64_t new_delay;
+ struct al3201_data *data = dev_get_drvdata(dev);
+
+ err = strict_strtoll(buf, 10, &new_delay);
+ if (err < 0)
+ return err;
+
+ pr_info("%s, new delay = %lldns, old delay = %lldns\n", __func__,
+ new_delay, ktime_to_ns(data->light_poll_delay));
+
+ if (new_delay != ktime_to_ns(data->light_poll_delay)) {
+ data->light_poll_delay = ns_to_ktime(new_delay);
+ if (data->state) {
+ al3201_disable(data);
+ al3201_enable(data);
+ }
+ }
+
+ return size;
+}
+
+static DEVICE_ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
+ al3201_poll_delay_show, al3201_poll_delay_store);
+
+static ssize_t al3201_light_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct al3201_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", data->state);
+}
+
+static ssize_t al3201_light_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ bool new_value = false;
+ int err = 0;
+ struct al3201_data *data = dev_get_drvdata(dev);
+
+ if (sysfs_streq(buf, "1")) {
+ new_value = true;
+ } else if (sysfs_streq(buf, "0")) {
+ new_value = false;
+ } else {
+ pr_err("%s: invalid value %d\n", __func__, *buf);
+ return -EINVAL;
+ }
+
+ pr_info("%s, new_value = %d, old state = %d\n",
+ __func__, new_value, data->state);
+
+ if (new_value && (!data->state)) {
+ err = al3201_enable(data);
+ if (!err) {
+ data->state = ON;
+ } else {
+ pr_err("%s: couldn't enable", __func__);
+ data->state = OFF;
+ }
+ } else if (!new_value && (data->state)) {
+ err = al3201_disable(data);
+ if (!err)
+ data->state = OFF;
+ else
+ pr_err("%s: couldn't disable", __func__);
+ }
+
+ return size;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP,
+ al3201_light_enable_show, al3201_light_enable_store);
+
+static struct attribute *al3201_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_poll_delay.attr,
+
+#ifdef LSC_DBG
+ &dev_attr_em.attr,
+#endif
+ NULL
+};
+
+static const struct attribute_group al3201_attribute_group = {
+ .attrs = al3201_attributes,
+};
+
+static int al3201_init_client(struct i2c_client *client)
+{
+ int i;
+ struct al3201_data *data = i2c_get_clientdata(client);
+
+ /* read all the registers once to fill the cache.
+ * if one of the reads fails, we consider the init failed */
+ for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
+ int v = i2c_smbus_read_byte_data(client, al3201_reg[i]);
+ if (v < 0)
+ return -ENODEV;
+ data->reg_cache[i] = v;
+ }
+
+ /*
+ * 0 : Low resolution range, 0 to 32768 lux
+ * 1 : High resolution range, 0 to 8192 lux
+ */
+ al3201_set_range(client, 1);
+ /* 0x02 : Response time 200ms low pass fillter */
+ al3201_set_response_time(client, 0x02);
+ /* chip power off */
+ al3201_set_power_state(client, OFF);
+
+ return 0;
+}
+
+static int __devinit al3201_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err = 0;
+ struct al3201_data *data;
+ struct input_dev *input_dev;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+
+ pr_info("%s: start\n", __func__);
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ return -EIO;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ pr_err("%s, failed to alloc memory for module data\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ data->client = client;
+ i2c_set_clientdata(client, data);
+
+ mutex_init(&data->lock);
+
+ /* initialize the AL3201 chip */
+ err = al3201_init_client(client);
+ if (err) {
+ pr_err("%s: No such device\n", __func__);
+ goto err_initializ_chip;
+ }
+
+ hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ data->light_poll_delay = ns_to_ktime(200 * NSEC_PER_MSEC);
+ data->timer.function = al3201_timer_func;
+ data->state = OFF;
+
+ data->wq = alloc_workqueue("al3201_wq", WQ_UNBOUND | WQ_RESCUER, 1);
+ if (!data->wq) {
+ err = -ENOMEM;
+ pr_err("%s: could not create workqueue\n", __func__);
+ goto err_create_workqueue;
+ }
+
+ INIT_WORK(&data->work_light, al3201_work_func_light);
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ pr_err("%s: could not allocate input device\n", __func__);
+ err = -ENOMEM;
+ goto err_input_allocate_device_light;
+ }
+
+ input_set_drvdata(input_dev, data);
+ input_dev->name = "light_sensor";
+ input_set_capability(input_dev, EV_REL, REL_MISC);
+
+ err = input_register_device(input_dev);
+ if (err < 0) {
+ pr_err("%s: could not register input device\n", __func__);
+ input_free_device(input_dev);
+ goto err_input_register_device_light;
+ }
+
+ data->input = input_dev;
+
+ err = sysfs_create_group(&input_dev->dev.kobj, &al3201_attribute_group);
+ if (err) {
+ pr_err("%s: could not create sysfs group\n", __func__);
+ goto err_sysfs_create_group_light;
+ }
+
+ /* set sysfs for light sensor */
+ data->light_dev = sensors_classdev_register("light_sensor");
+ if (IS_ERR(data->light_dev)) {
+ pr_err("%s: could not create light_dev\n", __func__);
+ goto err_light_device_create;
+ }
+
+ if (device_create_file(data->light_dev, &dev_attr_raw_data) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_raw_data.attr.name);
+ goto err_light_device_create_file1;
+ }
+
+ if (device_create_file(data->light_dev, &dev_attr_vendor) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_vendor.attr.name);
+ goto err_light_device_create_file2;
+ }
+
+ if (device_create_file(data->light_dev, &dev_attr_name) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_name.attr.name);
+ goto err_light_device_create_file3;
+ }
+
+ dev_set_drvdata(data->light_dev, data);
+ pr_info("%s: success!\n", __func__);
+ goto done;
+
+ err_light_device_create_file3:
+ device_remove_file(data->light_dev, &dev_attr_vendor);
+err_light_device_create_file2:
+ device_remove_file(data->light_dev, &dev_attr_raw_data);
+err_light_device_create_file1:
+ sensors_classdev_unregister(data->light_dev);
+ err_light_device_create:
+ sysfs_remove_group(&data->input->dev.kobj, &al3201_attribute_group);
+ err_sysfs_create_group_light:
+ input_unregister_device(data->input);
+ err_input_register_device_light:
+ err_input_allocate_device_light:
+ destroy_workqueue(data->wq);
+ err_create_workqueue:
+ err_initializ_chip:
+ mutex_destroy(&data->lock);
+ kfree(data);
+ done:
+ return err;
+}
+
+static int al3201_remove(struct i2c_client *client)
+{
+ struct al3201_data *data = i2c_get_clientdata(client);
+
+ sysfs_remove_group(&data->input->dev.kobj, &al3201_attribute_group);
+ input_unregister_device(data->input);
+
+ al3201_set_power_state(client, OFF);
+
+ if (data->state)
+ al3201_disable(data);
+
+ destroy_workqueue(data->wq);
+ mutex_destroy(&data->lock);
+ kfree(data);
+
+ return 0;
+}
+
+static int al3201_suspend(struct device *dev)
+{
+ int err = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct al3201_data *data = i2c_get_clientdata(client);
+
+ if (data->state) {
+ err = al3201_disable(data);
+ if (err)
+ pr_err("%s: could not disable\n", __func__);
+ }
+
+ return err;
+}
+
+static int al3201_resume(struct device *dev)
+{
+ int err = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct al3201_data *data = i2c_get_clientdata(client);
+
+ if (data->state) {
+ err = al3201_enable(data);
+ if (err)
+ pr_err("%s: could not enable\n", __func__);
+ }
+ return err;
+}
+
+static const struct i2c_device_id al3201_id[] = {
+ {CHIP_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, al3201_id);
+
+static const struct dev_pm_ops al3201_pm_ops = {
+ .suspend = al3201_suspend,
+ .resume = al3201_resume,
+};
+
+static struct i2c_driver al3201_driver = {
+ .driver = {
+ .name = CHIP_NAME,
+ .owner = THIS_MODULE,
+ .pm = &al3201_pm_ops,
+ },
+ .probe = al3201_probe,
+ .remove = al3201_remove,
+ .id_table = al3201_id,
+};
+
+static int __init al3201_init(void)
+{
+ return i2c_add_driver(&al3201_driver);
+}
+
+static void __exit al3201_exit(void)
+{
+ i2c_del_driver(&al3201_driver);
+}
+
+MODULE_AUTHOR("Kyusung Kim <gs0816.kim@samsung.com>");
+MODULE_DESCRIPTION("AL3201 Ambient light sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
+module_init(al3201_init);
+module_exit(al3201_exit);
diff --git a/drivers/sensor/cm3663.c b/drivers/sensor/cm3663.c
index c2228fb..25bf4ba 100644
--- a/drivers/sensor/cm3663.c
+++ b/drivers/sensor/cm3663.c
@@ -30,9 +30,6 @@
#include <linux/workqueue.h>
#include <linux/uaccess.h>
#include <linux/sensor/cm3663.h>
-#if defined(CONFIG_MACH_S2PLUS)
-#include <linux/sensor/sensors_core.h>
-#endif
#define PROX_READ_NUM 40
@@ -151,23 +148,19 @@ int cm3663_i2c_write(struct cm3663_data *cm3663, u8 addr, u8 val)
static void cm3663_light_enable(struct cm3663_data *cm3663)
{
u8 tmp;
-#if defined(CONFIG_MACH_S2PLUS)
- printk(KERN_INFO "[%s]\n", __func__);
-#endif
+ int64_t temp_time = 0;
cm3663_i2c_read(cm3663, REGS_ARA, &tmp);
cm3663_i2c_read(cm3663, REGS_ARA, &tmp);
cm3663_i2c_read(cm3663, REGS_ARA, &tmp);
cm3663_i2c_write(cm3663, REGS_INIT, reg_defaults[3]);
cm3663_i2c_write(cm3663, REGS_ALS_CMD, reg_defaults[1]);
- hrtimer_start(&cm3663->light_timer, cm3663->light_poll_delay,
+ temp_time = ktime_to_ns(cm3663->light_poll_delay) + 100000000;
+ hrtimer_start(&cm3663->light_timer, ns_to_ktime(temp_time),
HRTIMER_MODE_REL);
}
static void cm3663_light_disable(struct cm3663_data *cm3663)
{
-#if defined(CONFIG_MACH_S2PLUS)
- printk(KERN_INFO "[%s]\n", __func__);
-#endif
cm3663_i2c_write(cm3663, REGS_ALS_CMD, 0x01);
hrtimer_cancel(&cm3663->light_timer);
cancel_work_sync(&cm3663->work_light);
@@ -338,9 +331,6 @@ static ssize_t proximity_enable_store(struct device *dev,
struct cm3663_data *cm3663 = dev_get_drvdata(dev);
bool new_value;
u8 tmp;
-#if defined(CONFIG_MACH_S2PLUS)
- u8 val = 1;
-#endif
if (sysfs_streq(buf, "1"))
new_value = true;
@@ -362,25 +352,6 @@ static ssize_t proximity_enable_store(struct device *dev,
cm3663_i2c_write(cm3663, REGS_PS_THD, reg_defaults[7]);
cm3663_i2c_write(cm3663, REGS_PS_CMD, reg_defaults[5]);
-#if defined(CONFIG_MACH_S2PLUS)
- /* report the first value */
- val = gpio_get_value(cm3663->i2c_client->irq);
- if (val < 0) {
- pr_err("%s: gpio_get_value error %d\n", __func__, val);
- return IRQ_HANDLED;
- }
-
- cm3663_i2c_read(cm3663, REGS_PS_DATA, &tmp);
- printk(KERN_INFO "%s: proximity value = %d, val = %d\n",
- __func__, tmp, val);
-
- /* 0 is close, 1 is far */
- input_report_abs(cm3663->proximity_input_dev,
- ABS_DISTANCE, val);
- input_sync(cm3663->proximity_input_dev);
- wake_lock_timeout(&cm3663->prx_wake_lock, 3*HZ);
-#endif
-
enable_irq(cm3663->irq);
enable_irq_wake(cm3663->irq);
} else if (!new_value && (cm3663->power_state & PROXIMITY_ENABLED)) {
@@ -440,21 +411,12 @@ static ssize_t proximity_avg_store(struct device *dev,
return size;
}
-#if defined(CONFIG_MACH_S2PLUS)
-static DEVICE_ATTR(prox_avg, 0644,
- proximity_avg_show, proximity_avg_store);
-static DEVICE_ATTR(state, 0644, proximity_state_show, NULL);
-
-static DEVICE_ATTR(lux, 0644, lightsensor_file_state_show,
- NULL);
-#else
static DEVICE_ATTR(proximity_avg, 0644,
proximity_avg_show, proximity_avg_store);
static DEVICE_ATTR(proximity_state, 0644, proximity_state_show, NULL);
static DEVICE_ATTR(lightsensor_file_state, 0644, lightsensor_file_state_show,
NULL);
-#endif
static DEVICE_ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP,
poll_delay_show, poll_delay_store);
@@ -488,19 +450,13 @@ static struct attribute_group proximity_attribute_group = {
static void cm3663_work_func_light(struct work_struct *work)
{
- int i;
int als;
struct cm3663_data *cm3663 = container_of(work, struct cm3663_data,
work_light);
als = lightsensor_get_alsvalue(cm3663);
-#if defined(CONFIG_MACH_S2PLUS)
- input_report_rel(cm3663->light_input_dev,
- REL_MISC, als + 1);
-#else
input_report_abs(cm3663->light_input_dev,
ABS_MISC, als + 1);
-#endif
input_sync(cm3663->light_input_dev);
}
@@ -716,12 +672,8 @@ static int cm3663_i2c_probe(struct i2c_client *client,
}
input_set_drvdata(input_dev, cm3663);
input_dev->name = "light_sensor";
-#if defined(CONFIG_MACH_S2PLUS)
- input_set_capability(input_dev, EV_REL, REL_MISC);
-#else
input_set_capability(input_dev, EV_ABS, ABS_MISC);
input_set_abs_params(input_dev, ABS_MISC, 0, 1, 0, 0);
-#endif
ret = input_register_device(input_dev);
if (ret < 0) {
@@ -737,43 +689,6 @@ static int cm3663_i2c_probe(struct i2c_client *client,
goto err_sysfs_create_group_light;
}
-#if defined(CONFIG_MACH_S2PLUS)
- /* set sysfs for proximity sensor */
- cm3663->proximity_dev = sensors_classdev_register("proximity_sensor");
- if (IS_ERR(cm3663->proximity_dev)) {
- pr_err("%s: could not create proximity_dev\n", __func__);
- goto err_proximity_classdev_create;
- }
-
- if (device_create_file(cm3663->proximity_dev,
- &dev_attr_state) < 0) {
- pr_err("%s: could not create device file(%s)!\n", __func__,
- dev_attr_state.attr.name);
- goto err_proximity_device_create_file1;
- }
-
- if (device_create_file(cm3663->proximity_dev,
- &dev_attr_prox_avg) < 0) {
- pr_err("%s: could not create device file(%s)!\n", __func__,
- dev_attr_prox_avg.attr.name);
- goto err_proximity_device_create_file2;
- }
- dev_set_drvdata(cm3663->proximity_dev, cm3663);
-
- /* set sysfs for light sensor */
- cm3663->switch_cmd_dev = sensors_classdev_register("light_sensor");
- if (IS_ERR(cm3663->switch_cmd_dev)) {
- pr_err("%s: could not create switch_cmd_dev\n", __func__);
- goto err_light_classdev_create;
- }
- if (device_create_file(cm3663->switch_cmd_dev,
- &dev_attr_lux) < 0) {
- pr_err("%s: could not create device file(%s)!\n", __func__,
- dev_attr_lux.attr.name);
- goto err_light_device_create_file;
- }
- dev_set_drvdata(cm3663->switch_cmd_dev, cm3663);
-#else
/* set sysfs for proximity sensor */
cm3663->proximity_class = class_create(THIS_MODULE, "proximity");
if (IS_ERR(cm3663->proximity_class)) {
@@ -824,22 +739,10 @@ static int cm3663_i2c_probe(struct i2c_client *client,
goto err_light_device_create_file;
}
dev_set_drvdata(cm3663->switch_cmd_dev, cm3663);
-#endif
goto done;
/* error, unwind it all */
-#if defined(CONFIG_MACH_S2PLUS)
-err_light_device_create_file:
- sensors_classdev_unregister(cm3663->switch_cmd_dev);
-err_light_classdev_create:
- device_remove_file(cm3663->proximity_dev, &dev_attr_prox_avg);
-err_proximity_device_create_file2:
- device_remove_file(cm3663->proximity_dev, &dev_attr_state);
-err_proximity_device_create_file1:
- sensors_classdev_unregister(cm3663->proximity_dev);
-err_proximity_classdev_create:
-#else
err_light_device_create_file:
device_destroy(cm3663->lightsensor_class, 0);
err_light_device_create:
@@ -853,7 +756,6 @@ err_proximity_device_create_file1:
err_proximity_device_create:
class_destroy(cm3663->proximity_class);
err_proximity_class_create:
-#endif
sysfs_remove_group(&input_dev->dev.kobj,
&light_attribute_group);
err_sysfs_create_group_light:
@@ -910,14 +812,6 @@ static int cm3663_i2c_remove(struct i2c_client *client)
{
struct cm3663_data *cm3663 = i2c_get_clientdata(client);
-#if defined(CONFIG_MACH_S2PLUS)
- device_remove_file(cm3663->switch_cmd_dev,
- &dev_attr_lux);
- sensors_classdev_unregister(cm3663->switch_cmd_dev);
- device_remove_file(cm3663->proximity_dev, &dev_attr_prox_avg);
- device_remove_file(cm3663->proximity_dev, &dev_attr_state);
- sensors_classdev_unregister(cm3663->proximity_dev);
-#else
device_remove_file(cm3663->proximity_dev,
&dev_attr_proximity_avg);
device_remove_file(cm3663->switch_cmd_dev,
@@ -928,7 +822,6 @@ static int cm3663_i2c_remove(struct i2c_client *client)
device_remove_file(cm3663->proximity_dev, &dev_attr_proximity_state);
device_destroy(cm3663->proximity_class, 0);
class_destroy(cm3663->proximity_class);
-#endif
sysfs_remove_group(&cm3663->light_input_dev->dev.kobj,
&light_attribute_group);
input_unregister_device(cm3663->light_input_dev);
diff --git a/drivers/sensor/cm36651.c b/drivers/sensor/cm36651.c
index e607ca5..8cf11ac 100644
--- a/drivers/sensor/cm36651.c
+++ b/drivers/sensor/cm36651.c
@@ -78,13 +78,18 @@
/* Intelligent Cancelation*/
#define CM36651_CANCELATION
#ifdef CM36651_CANCELATION
+#ifdef CONFIG_SLP
+#define CANCELATION_FILE_PATH "/csa/sensor/prox_cal_data"
+#else
#define CANCELATION_FILE_PATH "/efs/prox_cal"
+#endif
#define CANCELATION_THRESHOLD 9
#endif
#define PROX_READ_NUM 40
/*lightsnesor log time 6SEC 200mec X 30*/
#define LIGHT_LOG_TIME 30
+#define LIGHT_ADD_STARTTIME 300000000
enum {
LIGHT_ENABLED = BIT(0),
PROXIMITY_ENABLED = BIT(1),
@@ -237,13 +242,21 @@ int cm36651_i2c_write_byte(struct cm36651_data *cm36651, u8 addr, u8 command,
static void cm36651_light_enable(struct cm36651_data *cm36651)
{
/* enable setting */
+ int64_t start_add_time = 0;
+ start_add_time = ktime_to_ns(cm36651->light_poll_delay)\
+ + LIGHT_ADD_STARTTIME;
cm36651_i2c_write_byte(cm36651, CM36651_ALS, CS_CONF1,
als_reg_setting[0][1]);
cm36651_i2c_write_byte(cm36651, CM36651_ALS, CS_CONF2,
als_reg_setting[1][1]);
-
+#if defined(CONFIG_MACH_C1_KOR_SKT) || defined(CONFIG_MACH_C1_KOR_KT)\
+|| defined(CONFIG_MACH_C1_KOR_LGT)
+ hrtimer_start(&cm36651->light_timer, ns_to_ktime(start_add_time),
+ HRTIMER_MODE_REL);
+#else
hrtimer_start(&cm36651->light_timer, cm36651->light_poll_delay,
- HRTIMER_MODE_REL);
+ HRTIMER_MODE_REL);
+#endif
}
static void cm36651_light_disable(struct cm36651_data *cm36651)
@@ -736,6 +749,9 @@ irqreturn_t cm36651_irq_thread_fn(int irq, void *data)
input_report_abs(cm36651->proximity_input_dev, ABS_DISTANCE, val);
input_sync(cm36651->proximity_input_dev);
wake_lock_timeout(&cm36651->prx_wake_lock, 3 * HZ);
+#ifdef CONFIG_SLP
+ pm_wakeup_event(cm36651->proximity_dev, 0);
+#endif
pr_info("%s: val = %d, ps_data = %d (close:0, far:1)\n",
__func__, val, ps_data);
@@ -783,7 +799,7 @@ static int cm36651_setup_reg(struct cm36651_data *cm36651)
/* turn off */
cm36651_i2c_write_byte(cm36651, CM36651_ALS, CS_CONF1, 0x01);
- cm36651_i2c_write_byte(cm36651, CM36651_ALS, PS_CONF1, 0x01);
+ cm36651_i2c_write_byte(cm36651, CM36651_PS, PS_CONF1, 0x01);
pr_info("%s is success.", __func__);
return err;
@@ -1164,6 +1180,10 @@ static int cm36651_i2c_probe(struct i2c_client *client,
goto err_light_device_create_file4;
}
+#ifdef CONFIG_SLP
+ device_init_wakeup(cm36651->proximity_dev, true);
+#endif
+
dev_set_drvdata(cm36651->light_dev, cm36651);
pr_info("%s is success.\n", __func__);
@@ -1251,6 +1271,10 @@ static int cm36651_i2c_remove(struct i2c_client *client)
destroy_workqueue(cm36651->light_wq);
destroy_workqueue(cm36651->prox_wq);
+#ifdef CONFIG_SLP
+ device_init_wakeup(cm36651->proximity_dev, false);
+#endif
+
/* sysfs destroy */
device_remove_file(cm36651->light_dev, &dev_attr_name);
device_remove_file(cm36651->light_dev, &dev_attr_vendor);
diff --git a/drivers/sensor/gp2a_light.c b/drivers/sensor/gp2a_light.c
index 8b20814..e8828eb 100644
--- a/drivers/sensor/gp2a_light.c
+++ b/drivers/sensor/gp2a_light.c
@@ -35,6 +35,9 @@
/* for debugging */
#undef DEBUG
+#define VENDOR "SHARP"
+#define CHIP_ID "GP2AP"
+
/*********** for debug ***************************/
#if 1
#define gprintk(fmt, x...) printk(KERN_INFO "%s(%d): " fmt\
@@ -191,9 +194,39 @@ light_enable_store(struct device *dev, struct device_attribute *attr,
return count;
}
+
+/* sysfs for vendor & name */
+static ssize_t lightsensor_vendor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", VENDOR);
+}
+
+static ssize_t lightsensor_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return is_gp2a030a() ? sprintf(buf, "%s030\n", CHIP_ID)
+ : sprintf(buf, "%s020\n", CHIP_ID);
+}
+
+static ssize_t lightsensor_raw_data_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int adc = 0;
+
+ adc = lightsensor_get_adcvalue();
+
+ return sprintf(buf, "%d\n", adc);
+}
+
static DEVICE_ATTR(poll_delay, 0664, light_delay_show, light_delay_store);
static DEVICE_ATTR(enable, 0664, light_enable_show, light_enable_store);
static DEVICE_ATTR(lux, 0664, lightsensor_file_state_show, NULL);
+static DEVICE_ATTR(vendor, 0664, lightsensor_vendor_show, NULL);
+static DEVICE_ATTR(name, 0664, lightsensor_name_show, NULL);
+static DEVICE_ATTR(raw_data, 0664, lightsensor_raw_data_show, NULL);
+
static struct attribute *lightsensor_attributes[] = {
&dev_attr_poll_delay.attr,
@@ -264,19 +297,35 @@ int lightsensor_get_adc(void)
D0_raw_data = (get_data[1] << 8) | get_data[0]; /* clear */
D1_raw_data = (get_data[3] << 8) | get_data[2]; /* IR */
if (is_gp2a030a()) {
- if (100 * D1_raw_data <= 41 * D0_raw_data) {
- light_alpha = 736;
- light_beta = 0;
- } else if (100 * D1_raw_data <= 62 * D0_raw_data) {
- light_alpha = 1855;
- light_beta = 2693;
- } else if (100 * D1_raw_data <= d0_boundary * D0_raw_data) {
- light_alpha = 544;
- light_beta = 595;
- } else {
- light_alpha = 0;
- light_beta = 0;
- }
+ #if defined(CONFIG_MACH_GRANDE)
+ if (100 * D1_raw_data <= 41 * D0_raw_data) {
+ light_alpha = 1186;
+ light_beta = 0;
+ } else if (100 * D1_raw_data <= 62 * D0_raw_data) {
+ light_alpha = 2930;
+ light_beta = 4252;
+ } else if (100 * D1_raw_data <= d0_boundary * D0_raw_data) {
+ light_alpha = 924;
+ light_beta = 1015;
+ } else {
+ light_alpha = 0;
+ light_beta = 0;
+ }
+ #else
+ if (100 * D1_raw_data <= 41 * D0_raw_data) {
+ light_alpha = 736;
+ light_beta = 0;
+ } else if (100 * D1_raw_data <= 62 * D0_raw_data) {
+ light_alpha = 1855;
+ light_beta = 2693;
+ } else if (100 * D1_raw_data <= d0_boundary * D0_raw_data) {
+ light_alpha = 544;
+ light_beta = 595;
+ } else {
+ light_alpha = 0;
+ light_beta = 0;
+ }
+ #endif
} else {
if (lightsensor_mode) { /* HIGH_MODE */
if (100 * D1_raw_data <= 32 * D0_raw_data) {
@@ -614,6 +663,25 @@ static int lightsensor_probe(struct platform_device *pdev)
dev_attr_lux.attr.name);
goto err_light_device_create_file;
}
+
+ if (device_create_file(data->light_dev, &dev_attr_vendor) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_vendor.attr.name);
+ goto err_light_device_create_file1;
+ }
+
+ if (device_create_file(data->light_dev, &dev_attr_name) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_name.attr.name);
+ goto err_light_device_create_file2;
+ }
+
+ if (device_create_file(data->light_dev, &dev_attr_raw_data) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_raw_data.attr.name);
+ goto err_light_device_create_file3;
+ }
+
dev_set_drvdata(data->light_dev, data);
data->wq = create_singlethread_workqueue("gp2a_wq");
@@ -634,6 +702,12 @@ static int lightsensor_probe(struct platform_device *pdev)
goto done;
/* error, unwind it all */
+err_light_device_create_file3:
+ device_remove_file(data->light_dev, &dev_attr_raw_data);
+err_light_device_create_file2:
+ device_remove_file(data->light_dev, &dev_attr_name);
+err_light_device_create_file1:
+ device_remove_file(data->light_dev, &dev_attr_vendor);
err_create_workqueue:
device_remove_file(data->light_dev, &dev_attr_lux);
err_light_device_create_file:
@@ -662,6 +736,9 @@ static int lightsensor_remove(struct platform_device *pdev)
&lightsensor_attribute_group);
device_remove_file(data->light_dev, &dev_attr_lux);
+ device_remove_file(data->light_dev, &dev_attr_vendor);
+ device_remove_file(data->light_dev, &dev_attr_name);
+ device_remove_file(data->light_dev, &dev_attr_raw_data);
sensors_classdev_unregister(data->light_dev);
cancel_delayed_work_sync(&data->work);
diff --git a/drivers/sensor/gp2a_proximity.c b/drivers/sensor/gp2a_proximity.c
index 8ac0d2a..012d8b8 100644
--- a/drivers/sensor/gp2a_proximity.c
+++ b/drivers/sensor/gp2a_proximity.c
@@ -39,10 +39,14 @@
#include <linux/gpio.h>
#include <mach/gpio-midas.h>
#include <linux/sensor/sensors_core.h>
+#include <linux/printk.h>
/*********** for debug *******************************/
#undef DEBUG
+#define VENDOR "SHARP"
+#define CHIP_ID "GP2AP"
+
#if 1
#define gprintk(fmt, x...) printk(KERN_INFO "%s(%d): "\
fmt, __func__ , __LINE__, ## x)
@@ -52,6 +56,11 @@ fmt, __func__ , __LINE__, ## x)
/**************************************************/
#define PROX_READ_NUM 40
+#define PS_LOW_THD_L 0x08
+#define PS_LOW_THD_H 0x09
+#define PS_HIGH_THD_L 0x0A
+#define PS_HIGH_THD_H 0x0B
+
/* global var */
static struct i2c_driver opt_i2c_driver;
static struct i2c_client *opt_i2c_client;
@@ -128,12 +137,69 @@ static int proximity_onoff(u8 onoff);
int is_gp2a030a(void)
{
-#if defined(CONFIG_MACH_C1) || defined(CONFIG_MACH_C1VZW) || \
- defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_M3)
+#if defined(CONFIG_MACH_C1) || \
+ defined(CONFIG_MACH_M0) || \
+ defined(CONFIG_MACH_GRANDE) || \
+ defined(CONFIG_MACH_IRON)
return (system_rev != 0 && system_rev != 3);
#endif
+#if defined(CONFIG_MACH_M3) || \
+ defined(CONFIG_MACH_BAFFIN)
+ return 1;
+#endif
+#if defined(CONFIG_MACH_REDWOOD)
+ return (system_rev == 0x04);
+#endif
+
return 0;
}
+
+static int gp2a_update_threshold(u8 (*selected_image)[2],
+ unsigned long new_threshold, bool update_reg)
+{
+ int i, err = 0;
+ u8 set_value;
+
+ for (i = 0; i < COL; i++) {
+ switch (selected_image[i][0]) {
+ case PS_LOW_THD_L:
+ /*PS mode LTH(Loff) for low 8bit*/
+ set_value = new_threshold & 0x00FF;
+ break;
+
+ case PS_LOW_THD_H:
+ /*PS mode LTH(Loff) for high 8bit*/
+ set_value = (new_threshold & 0xFF00) >> 8;
+ break;
+
+ case PS_HIGH_THD_L:
+ /*PS mode HTH(Lon) for low 8bit*/
+ set_value = (new_threshold+1) & 0x00FF;
+ break;
+
+ case PS_HIGH_THD_H:
+ /* PS mode HTH(Lon) for high 8bit*/
+ set_value = ((new_threshold+1) & 0xFF00) >> 8;
+ break;
+
+ default:
+ continue;
+ }
+
+ if (update_reg)
+ err = opt_i2c_write(selected_image[i][0], &set_value);
+
+ if (err) {
+ pr_err("%s : setting error i = %d, err=%d\n",
+ __func__, i, err);
+ return err;
+ } else
+ selected_image[i][1] = set_value;
+ }
+
+ return err;
+}
+
/* Proximity Sysfs interface */
static ssize_t
proximity_enable_show(struct device *dev,
@@ -173,9 +239,7 @@ proximity_enable_store(struct device *dev,
proximity_enable = value;
proximity_onoff(0);
disable_irq_wake(data->irq);
-#ifndef CONFIG_MACH_MIDAS_02_BD
data->pdata->gp2a_led_on(false);
-#endif
} else if (!data->enabled && value) { /* proximity power on */
data->pdata->gp2a_led_on(true);
/*msleep(1); */
@@ -261,13 +325,65 @@ static ssize_t proximity_avg_store(struct device *dev,
return size;
}
+static ssize_t proximity_thresh_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ int threshold = 0;
+ u8 (*selected_image)[2] = (is_gp2a030a() ?
+ gp2a_original_image_030a : gp2a_original_image);
+
+ for (i = 0; i < COL; i++) {
+ if (selected_image[i][0] == 0x08)
+ /*PS mode LTH(Loff) */
+ threshold = selected_image[i][1];
+ else if (selected_image[i][0] == 0x09)
+ /*PS mode LTH(Loff) */
+ threshold |= selected_image[i][1]<<8;
+ }
+
+ return sprintf(buf, "prox_threshold = %d\n", threshold);
+}
+
+static ssize_t proximity_thresh_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned long threshold;
+ int err = 0;
+
+ err = strict_strtoul(buf, 10, &threshold);
+
+ if (err) {
+ pr_err("%s, conversion %s to number.\n",
+ __func__, buf);
+ return err;
+ }
+
+ err = gp2a_update_threshold(is_gp2a030a() ?
+ gp2a_original_image_030a : gp2a_original_image,
+ threshold, true);
+
+ if (err) {
+ pr_err("gp2a threshold(with register) update fail.\n");
+ return err;
+ }
+
+ return size;
+}
+
static DEVICE_ATTR(enable, 0664, proximity_enable_show, proximity_enable_store);
static DEVICE_ATTR(prox_avg, 0664, proximity_avg_show, proximity_avg_store);
static DEVICE_ATTR(state, 0664, proximity_state_show, NULL);
+static DEVICE_ATTR(prox_thresh, S_IRUGO | S_IWUSR,
+ proximity_thresh_show, proximity_thresh_store);
static struct attribute *proximity_attributes[] = {
&dev_attr_enable.attr,
&dev_attr_state.attr,
+#ifdef CONFIG_SLP
+ &dev_attr_prox_thresh.attr,
+#endif
NULL
};
@@ -275,6 +391,38 @@ static struct attribute_group proximity_attribute_group = {
.attrs = proximity_attributes
};
+/* sysfs for vendor & name */
+static ssize_t proximity_vendor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", VENDOR);
+}
+
+static ssize_t proximity_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ return is_gp2a030a() ? sprintf(buf, "%s030\n", CHIP_ID)
+ : sprintf(buf, "%s020\n", CHIP_ID);
+}
+
+static ssize_t proximity_raw_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int D2_data = 0;
+ unsigned char get_D2_data[2] = { 0, };
+
+ msleep(20);
+ opt_i2c_read(0x10, get_D2_data, sizeof(get_D2_data));
+ D2_data = (get_D2_data[1] << 8) | get_D2_data[0];
+
+ return sprintf(buf, "%d\n", D2_data);
+}
+
+static DEVICE_ATTR(vendor, 0644, proximity_vendor_show, NULL);
+static DEVICE_ATTR(name, 0644, proximity_name_show, NULL);
+static DEVICE_ATTR(raw_data, 0644, proximity_raw_data_show, NULL);
+
static void proxsensor_get_avgvalue(struct gp2a_data *data)
{
int min = 0, max = 0, avg = 0;
@@ -324,6 +472,9 @@ irqreturn_t gp2a_irq_handler(int irq, void *gp2a_data_p)
struct gp2a_data *data = gp2a_data_p;
wake_lock_timeout(&data->prx_wake_lock, 3 * HZ);
+#ifdef CONFIG_SLP
+ pm_wakeup_event(data->proximity_dev, 0);
+#endif
schedule_work(&data->work);
@@ -564,6 +715,12 @@ static int gp2a_opt_probe(struct platform_device *pdev)
/* gp2a power on */
pdata->gp2a_led_on(true);
+ if (pdata->gp2a_get_threshold) {
+ gp2a_update_threshold(is_gp2a030a() ?
+ gp2a_original_image_030a : gp2a_original_image,
+ pdata->gp2a_get_threshold(), false);
+ }
+
/* allocate driver_data */
gp2a = kzalloc(sizeof(struct gp2a_data), GFP_KERNEL);
if (!gp2a) {
@@ -653,6 +810,37 @@ static int gp2a_opt_probe(struct platform_device *pdev)
dev_attr_prox_avg.attr.name);
goto err_proximity_device_create_file2;
}
+
+ if (device_create_file(gp2a->proximity_dev,
+ &dev_attr_prox_thresh) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_prox_thresh.attr.name);
+ goto err_proximity_device_create_file3;
+ }
+
+ if (device_create_file(gp2a->proximity_dev,
+ &dev_attr_vendor) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_vendor.attr.name);
+ goto err_proximity_device_create_file4;
+ }
+
+ if (device_create_file(gp2a->proximity_dev,
+ &dev_attr_name) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_name.attr.name);
+ goto err_proximity_device_create_file5;
+ }
+
+ if (device_create_file(gp2a->proximity_dev, &dev_attr_raw_data) < 0) {
+ pr_err("%s: could not create device file(%s)!\n", __func__,
+ dev_attr_raw_data.attr.name);
+ goto err_proximity_device_create_file6;
+ }
+
+#ifdef CONFIG_SLP
+ device_init_wakeup(gp2a->proximity_dev, true);
+#endif
dev_set_drvdata(gp2a->proximity_dev, gp2a);
device_init_wakeup(&pdev->dev, 1);
@@ -661,6 +849,14 @@ static int gp2a_opt_probe(struct platform_device *pdev)
return 0;
+err_proximity_device_create_file6:
+ device_remove_file(gp2a->proximity_dev, &dev_attr_raw_data);
+err_proximity_device_create_file5:
+ device_remove_file(gp2a->proximity_dev, &dev_attr_name);
+err_proximity_device_create_file4:
+ device_remove_file(gp2a->proximity_dev, &dev_attr_vendor);
+err_proximity_device_create_file3:
+ device_remove_file(gp2a->proximity_dev, &dev_attr_prox_avg);
err_proximity_device_create_file2:
device_remove_file(gp2a->proximity_dev, &dev_attr_state);
err_proximity_device_create_file1:
@@ -690,8 +886,29 @@ static int gp2a_opt_remove(struct platform_device *pdev)
return -1;
}
+ if (gp2a->enabled) {
+ disable_irq(gp2a->irq);
+ proximity_enable = 0;
+ proximity_onoff(0);
+ disable_irq_wake(gp2a->irq);
+#ifndef CONFIG_MACH_MIDAS_02_BD
+ gp2a->pdata->gp2a_led_on(false);
+#endif
+ gp2a->enabled = 0;
+ }
+
+ hrtimer_cancel(&gp2a->prox_timer);
+ cancel_work_sync(&gp2a->work_prox);
+ destroy_workqueue(gp2a->prox_wq);
+#ifdef CONFIG_SLP
+ device_init_wakeup(gp2a->proximity_dev, false);
+#endif
+ device_remove_file(gp2a->proximity_dev, &dev_attr_prox_thresh);
device_remove_file(gp2a->proximity_dev, &dev_attr_prox_avg);
device_remove_file(gp2a->proximity_dev, &dev_attr_state);
+ device_remove_file(gp2a->proximity_dev, &dev_attr_vendor);
+ device_remove_file(gp2a->proximity_dev, &dev_attr_name);
+ device_remove_file(gp2a->proximity_dev, &dev_attr_raw_data);
sensors_classdev_unregister(gp2a->proximity_dev);
if (gp2a->input_dev != NULL) {
@@ -702,7 +919,6 @@ static int gp2a_opt_remove(struct platform_device *pdev)
kfree(gp2a->input_dev);
}
- destroy_workqueue(gp2a->prox_wq);
wake_lock_destroy(&gp2a->prx_wake_lock);
device_init_wakeup(&pdev->dev, 0);
free_irq(gp2a->irq, gp2a);
diff --git a/drivers/sensor/k3dh.c b/drivers/sensor/k3dh.c
index 0d3f0da..9010e0b 100644
--- a/drivers/sensor/k3dh.c
+++ b/drivers/sensor/k3dh.c
@@ -70,7 +70,7 @@ struct k3dh_data {
struct mutex read_lock;
struct mutex write_lock;
struct completion data_ready;
-#ifdef CONFIG_MACH_U1
+#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS)
struct class *acc_class;
#else
struct device *dev;
@@ -426,7 +426,7 @@ static ssize_t k3dh_fs_read(struct device *dev,
{
struct k3dh_data *data = dev_get_drvdata(dev);
-#ifdef CONFIG_MACH_U1
+#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS)
int err = 0;
int on;
@@ -526,7 +526,7 @@ static ssize_t k3dh_calibration_store(struct device *dev,
return count;
}
-#ifdef CONFIG_MACH_U1
+#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS)
static DEVICE_ATTR(acc_file, 0664, k3dh_fs_read, NULL);
#else
static ssize_t k3dh_accel_vendor_show(struct device *dev,
@@ -565,7 +565,7 @@ static int k3dh_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct k3dh_data *data;
-#ifdef CONFIG_MACH_U1
+#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS)
struct device *dev_t, *dev_cal;
#endif
struct accel_platform_data *pdata;
@@ -619,7 +619,7 @@ static int k3dh_probe(struct i2c_client *client,
pdata = client->dev.platform_data;
-#ifdef CONFIG_MACH_U1
+#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS)
/* creating class/device for test */
data->acc_class = class_create(THIS_MODULE, "accelerometer");
if (IS_ERR(data->acc_class)) {
@@ -704,7 +704,7 @@ static int k3dh_probe(struct i2c_client *client,
return 0;
-#ifdef CONFIG_MACH_U1
+#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS)
err_cal_device_create_file:
device_destroy(sec_class, 0);
err_cal_device_create:
@@ -748,7 +748,7 @@ static int k3dh_remove(struct i2c_client *client)
pr_err("%s: pm_off failed %d\n", __func__, err);
}
-#ifdef CONFIG_MACH_U1
+#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS)
device_destroy(sec_class, 0);
device_destroy(data->acc_class, MKDEV(ACC_DEV_MAJOR, 0));
class_destroy(data->acc_class);
diff --git a/drivers/sensor/lps331ap.c b/drivers/sensor/lps331ap.c
index 6990f25..e49e683 100644
--- a/drivers/sensor/lps331ap.c
+++ b/drivers/sensor/lps331ap.c
@@ -208,7 +208,11 @@
#define DELAY_DEFAULT 200
#define DELAY_MINIMUM 40
/* calibration file path */
+#ifdef CONFIG_SLP
+#define CALIBRATION_FILE_PATH "/csa/sensor/baro_cal_data"
+#else
#define CALIBRATION_FILE_PATH "/efs/FactoryApp/baro_delta"
+#endif
static const struct {
unsigned int cutoff_ms;
@@ -277,7 +281,7 @@ static int lps331ap_prs_i2c_read(struct lps331ap_prs_data *prs,
err = i2c_transfer(prs->client->adapter, msgs, 2);
if (err != 2) {
- dev_err(&prs->client->dev, "read transfer error\n");
+ dev_err(&prs->client->dev, "read transfer error = %d\n", err);
err = -EIO;
}
return 0;
@@ -1041,15 +1045,25 @@ static ssize_t lps331ap_reg_get(struct device *dev,\
{
ssize_t ret;
struct lps331ap_prs_data *prs = dev_get_drvdata(dev);
- int rc;
+ int rc, i;
u8 data;
+ u8 data_all[64] = {0,};
mutex_lock(&prs->lock);
data = prs->reg_addr;
mutex_unlock(&prs->lock);
rc = lps331ap_prs_i2c_read(prs, &data, 1);
if (rc < 0)
- return rc;
+ return rc;
+
+ data_all[0] = (I2C_AUTO_INCREMENT | 0x00);
+ rc = lps331ap_prs_i2c_read(prs, data_all, 64);
+ if (rc < 0)
+ return rc;
+ for (i = 0; i < 64; i++)
+ pr_info("%s, Register[0x%02x] = 0x%02x\n", __func__,
+ i, data_all[i]);
+
ret = sprintf(buf, "0x%02x\n", data);
return ret;
}
diff --git a/drivers/sensor/lsm330dlc_accel.c b/drivers/sensor/lsm330dlc_accel.c
index a564d52..5f228c7 100644
--- a/drivers/sensor/lsm330dlc_accel.c
+++ b/drivers/sensor/lsm330dlc_accel.c
@@ -71,7 +71,11 @@ enum {
#define ACC_DEV_NAME "accelerometer"
+#ifdef CONFIG_SLP
+#define CALIBRATION_FILE_PATH "/csa/sensor/accel_cal_data"
+#else
#define CALIBRATION_FILE_PATH "/efs/calibration_data"
+#endif
#define CAL_DATA_AMOUNT 20
static const struct odr_delay {
@@ -88,7 +92,6 @@ static const struct odr_delay {
{ ODR1, 1000000000LL }, /* 1Hz */
};
-/* It will be used, when google fusion is enabled. */
static const int position_map[][3][3] = {
{{-1, 0, 0}, { 0, -1, 0}, { 0, 0, 1} }, /* 0 top/upper-left */
{{ 0, -1, 0}, { 1, 0, 0}, { 0, 0, 1} }, /* 1 top/upper-right */
@@ -150,6 +153,10 @@ static int lsm330dlc_accel_read_raw_xyz(struct lsm330dlc_accel_data *data,
acc->y = acc->y >> 4;
acc->z = acc->z >> 4;
+#if defined(CONFIG_MACH_M3_JPN_DCM)
+ acc->y = -acc->y;
+#endif
+
return 0;
}
@@ -558,15 +565,9 @@ static ssize_t lsm330dlc_accel_fs_read(struct device *dev,
accel_adjusted[i]
+= position_map[data->position][i][j] * raw[j];
}
-#ifdef CONFIG_SLP
- return sprintf(buf, "raw:%d,%d,%d adjust:%d,%d,%d\n",
- raw[0], raw[1], raw[2], accel_adjusted[0],
- accel_adjusted[1], accel_adjusted[2]);
-#else
return sprintf(buf, "%d,%d,%d\n",
accel_adjusted[0], accel_adjusted[1],
accel_adjusted[2]);
-#endif
} else
return sprintf(buf, "%d,%d,%d\n",
data->acc_xyz.x, data->acc_xyz.y, data->acc_xyz.z);
@@ -1340,7 +1341,6 @@ static int lsm330dlc_accel_remove(struct i2c_client *client)
device_remove_file(data->dev, &dev_attr_odr);
#endif
#ifdef USES_MOVEMENT_RECOGNITION
- wake_lock_destroy(&data->reactive_wake_lock);
device_remove_file(data->dev, &dev_attr_reactive_alert);
#endif
device_remove_file(data->dev, &dev_attr_calibration);
@@ -1350,6 +1350,7 @@ static int lsm330dlc_accel_remove(struct i2c_client *client)
#ifdef USES_MOVEMENT_RECOGNITION
device_init_wakeup(&data->client->dev, 0);
free_irq(data->client->irq, data);
+ wake_lock_destroy(&data->reactive_wake_lock);
#endif
#ifdef USES_INPUT_DEV
destroy_workqueue(data->work_queue);
diff --git a/drivers/sensor/lsm330dlc_gyro.c b/drivers/sensor/lsm330dlc_gyro.c
index 631730a..3b96f84 100644
--- a/drivers/sensor/lsm330dlc_gyro.c
+++ b/drivers/sensor/lsm330dlc_gyro.c
@@ -35,7 +35,11 @@
#define VENDOR "STM"
#define CHIP_ID "LSM330"
+#ifdef CONFIG_SLP
+#define CALIBRATION_FILE_PATH "/csa/sensor/gyro_cal_data"
+#else
#define CALIBRATION_FILE_PATH "/efs/gyro_cal_data"
+#endif
/* lsm330dlc_gyro chip id */
#define DEVICE_ID 0xD4
@@ -137,6 +141,17 @@ struct gyro_t {
s16 z;
};
+static const int position_map[][3][3] = {
+ {{-1, 0, 0}, { 0, -1, 0}, { 0, 0, 1} }, /* 0 top/upper-left */
+ {{ 0, -1, 0}, { 1, 0, 0}, { 0, 0, 1} }, /* 1 top/upper-right */
+ {{ 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1} }, /* 2 top/lower-right */
+ {{ 0, 1, 0}, {-1, 0, 0}, { 0, 0, 1} }, /* 3 top/lower-left */
+ {{ 1, 0, 0}, { 0, -1, 0}, { 0, 0, -1} }, /* 4 bottom/upper-left */
+ {{ 0, 1, 0}, { 1, 0, 0}, { 0, 0, -1} }, /* 5 bottom/upper-right */
+ {{-1, 0, 0}, { 0, 1, 0}, { 0, 0, -1} }, /* 6 bottom/lower-right */
+ {{ 0, -1, 0}, {-1, 0, 0}, { 0, 0, -1} }, /* 7 bottom/lower-left*/
+};
+
struct lsm330dlc_gyro_data {
struct i2c_client *client;
struct input_dev *input_dev;
@@ -146,11 +161,11 @@ struct lsm330dlc_gyro_data {
struct hrtimer timer;
atomic_t opened;
bool enable;
- bool drop_next_event;
bool self_test; /* is self_test or not? */
bool interruptible; /* interrupt or polling? */
int entries; /* number of fifo entries */
int dps; /* scale selection */
+ int sensitivity_value;
/* fifo data entries */
u8 fifo_data[sizeof(struct gyro_t) * 32];
u8 ctrl_regs[5]; /* saving register settings */
@@ -164,6 +179,8 @@ struct lsm330dlc_gyro_data {
int count;
#endif
struct gyro_t cal_data;
+ int position;
+ bool axis_adjust;
};
static int lsm330dlc_gyro_open_calibration(struct lsm330dlc_gyro_data *data)
@@ -262,30 +279,46 @@ static int lsm330dlc_gyro_read_values(struct i2c_client *client,
}
static int lsm330dlc_gyro_report_values\
- (struct lsm330dlc_gyro_data *gyro_data)
+ (struct lsm330dlc_gyro_data *data)
{
- int res;
- struct gyro_t data;
+ int res, i, j;
+ s16 raw[3] = {0,}, gyro_adjusted[3] = {0,};
- res = lsm330dlc_gyro_read_values(gyro_data->client, &data,
- gyro_data->entries);
+ res = lsm330dlc_gyro_read_values(data->client,
+ &data->xyz_data, data->entries);
if (res < 0)
return res;
- data.x -= gyro_data->cal_data.x;
- data.y -= gyro_data->cal_data.y;
- data.z -= gyro_data->cal_data.z;
+ data->xyz_data.x -= data->cal_data.x;
+ data->xyz_data.y -= data->cal_data.y;
+ data->xyz_data.z -= data->cal_data.z;
+
+ if (data->axis_adjust) {
+ raw[0] = data->xyz_data.x;
+ raw[1] = data->xyz_data.y;
+ raw[2] = data->xyz_data.z;
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++)
+ gyro_adjusted[i]
+ += position_map[data->position][i][j] * raw[j];
+ }
+ } else {
+ gyro_adjusted[0] = data->xyz_data.x;
+ gyro_adjusted[1] = data->xyz_data.y;
+ gyro_adjusted[2] = data->xyz_data.z;
+ }
- input_report_rel(gyro_data->input_dev, REL_RX, data.x);
- input_report_rel(gyro_data->input_dev, REL_RY, data.y);
- input_report_rel(gyro_data->input_dev, REL_RZ, data.z);
- input_sync(gyro_data->input_dev);
+ input_report_rel(data->input_dev, REL_RX, gyro_adjusted[0]);
+ input_report_rel(data->input_dev, REL_RY, gyro_adjusted[1]);
+ input_report_rel(data->input_dev, REL_RZ, gyro_adjusted[2]);
+ input_sync(data->input_dev);
- lsm330dlc_gyro_restart_fifo(gyro_data);
+ lsm330dlc_gyro_restart_fifo(data);
#ifdef LOGGING_GYRO
- printk(KERN_INFO "%s, x = %d, y = %d, z = %d, count = %d\n"
- , __func__, data.x, data.y, data.z, gyro_data->count);
+ pr_info("%s, x = %d, y = %d, z = %d\n"
+ , __func__, gyro_adjusted[0], gyro_adjusted[1],
+ gyro_adjusted[2]);
#endif
return res;
@@ -302,40 +335,67 @@ static enum hrtimer_restart lsm330dlc_gyro_timer_func(struct hrtimer *timer)
static void lsm330dlc_gyro_work_func(struct work_struct *work)
{
- int res, retry = 3;
- struct lsm330dlc_gyro_data *gyro_data\
+ int res, retry = 3, i, j;
+ struct lsm330dlc_gyro_data *data\
= container_of(work, struct lsm330dlc_gyro_data, work);
s32 status = 0;
+ s16 raw[3] = {0,}, gyro_adjusted[3] = {0,};
do {
- status = i2c_smbus_read_byte_data(gyro_data->client,
+ status = i2c_smbus_read_byte_data(data->client,
STATUS_REG);
if (status & 0x08)
break;
} while (retry--);
- if (status & 0x08 && gyro_data->self_test == false) {
- res = lsm330dlc_gyro_read_values(gyro_data->client,
- &gyro_data->xyz_data, 0);
+ if (status & 0x08 && data->self_test == false) {
+ res = lsm330dlc_gyro_read_values(data->client,
+ &data->xyz_data, 0);
if (res < 0)
pr_err("%s, reading data fail(res = %d)\n",
__func__, res);
- } else
- pr_warn("%s, use last data.\n", __func__);
+ if (data->dps == DPS500) {
+ data->xyz_data.x -= data->cal_data.x;
+ data->xyz_data.y -= data->cal_data.y;
+ data->xyz_data.z -= data->cal_data.z;
+ } else {
+ data->xyz_data.x -= (data->cal_data.x *
+ data->sensitivity_value / 2);
+ data->xyz_data.y -= (data->cal_data.y *
+ data->sensitivity_value / 2);
+ data->xyz_data.z -= (data->cal_data.z *
+ data->sensitivity_value / 2);
+ }
+ } else {
+ pr_warn("%s, use last data(%d, %d, %d), status=%d, selftest=%d\n",
+ __func__, data->xyz_data.x, data->xyz_data.y,
+ data->xyz_data.z, status, data->self_test);
+ }
- gyro_data->xyz_data.x -= gyro_data->cal_data.x;
- gyro_data->xyz_data.y -= gyro_data->cal_data.y;
- gyro_data->xyz_data.z -= gyro_data->cal_data.z;
+ if (data->axis_adjust) {
+ raw[0] = data->xyz_data.x;
+ raw[1] = data->xyz_data.y;
+ raw[2] = data->xyz_data.z;
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++)
+ gyro_adjusted[i]
+ += position_map[data->position][i][j] * raw[j];
+ }
+ } else {
+ gyro_adjusted[0] = data->xyz_data.x;
+ gyro_adjusted[1] = data->xyz_data.y;
+ gyro_adjusted[2] = data->xyz_data.z;
+ }
- input_report_rel(gyro_data->input_dev, REL_RX, gyro_data->xyz_data.x);
- input_report_rel(gyro_data->input_dev, REL_RY, gyro_data->xyz_data.y);
- input_report_rel(gyro_data->input_dev, REL_RZ, gyro_data->xyz_data.z);
- input_sync(gyro_data->input_dev);
+ input_report_rel(data->input_dev, REL_RX, gyro_adjusted[0]);
+ input_report_rel(data->input_dev, REL_RY, gyro_adjusted[1]);
+ input_report_rel(data->input_dev, REL_RZ, gyro_adjusted[2]);
+ input_sync(data->input_dev);
#ifdef LOGGING_GYRO
pr_info("%s, x = %d, y = %d, z = %d\n"
- , __func__, gyro_data->xyz_data.x, gyro_data->xyz_data.y,
- gyro_data->xyz_data.z);
+ , __func__, gyro_adjusted[0], gyro_adjusted[1],
+ gyro_adjusted[2]);
#endif
}
@@ -458,14 +518,19 @@ static ssize_t lsm330dlc_gyro_selftest_dps_store(struct device *dev,
ctrl = (data->ctrl_regs[3] & ~FS_MASK);
- if (new_dps == DPS250)
+ if (new_dps == DPS250) {
ctrl |= FS_250DPS;
- else if (new_dps == DPS500)
+ data->sensitivity_value = 1;
+ } else if (new_dps == DPS500) {
ctrl |= FS_500DPS;
- else if (new_dps == DPS2000)
+ data->sensitivity_value = 2;
+ } else if (new_dps == DPS2000) {
ctrl |= FS_2000DPS;
- else
+ data->sensitivity_value = 8;
+ } else {
ctrl |= FS_DEFULAT_DPS;
+ data->sensitivity_value = 2;
+ }
/* apply new dps */
mutex_lock(&data->lock);
@@ -480,7 +545,8 @@ static ssize_t lsm330dlc_gyro_selftest_dps_store(struct device *dev,
mutex_unlock(&data->lock);
data->dps = new_dps;
- pr_err("%s: %d dps stored\n", __func__, data->dps);
+ pr_info("%s: %d dps stored, sensitivity = %d\n",
+ __func__, data->dps, data->sensitivity_value);
return count;
}
@@ -1007,7 +1073,7 @@ static int lsm330dlc_gyro_bypass_self_test\
msleep(800);
/* Read 5 samples output before self-test on */
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < sample_num; i++) {
/* check ZYXDA ready bit */
for (j = 0; j < 10; j++) {
temp = i2c_smbus_read_byte_data(gyro_data->client,
@@ -1269,6 +1335,32 @@ static ssize_t lsm330dlc_gyro_name_show(struct device *dev,
return sprintf(buf, "%s\n", CHIP_ID);
}
+static ssize_t
+lsm330dlc_gyro_position_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct lsm330dlc_gyro_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", data->position);
+}
+
+static ssize_t
+lsm330dlc_gyro_position_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct lsm330dlc_gyro_data *data = dev_get_drvdata(dev);
+ int err = 0;
+
+ err = kstrtoint(buf, 10, &data->position);
+ if (err < 0)
+ pr_err("%s, kstrtoint failed.", __func__);
+
+ return count;
+}
+
static DEVICE_ATTR(power_off, 0664,
lsm330dlc_gyro_power_off, NULL);
static DEVICE_ATTR(power_on, 0664,
@@ -1283,7 +1375,8 @@ static DEVICE_ATTR(vendor, 0664,
lsm330dlc_gyro_vendor_show, NULL);
static DEVICE_ATTR(name, 0664,
lsm330dlc_gyro_name_show, NULL);
-
+static DEVICE_ATTR(position, 0664,
+ lsm330dlc_gyro_position_show, lsm330dlc_gyro_position_store);
#ifdef DEBUG_REGISTER
static DEVICE_ATTR(reg_data, 0664,
register_data_show, NULL);
@@ -1299,6 +1392,7 @@ static int lsm330dlc_gyro_probe(struct i2c_client *client,
int err = 0;
struct lsm330dlc_gyro_data *data;
struct input_dev *input_dev;
+ struct gyro_platform_data *pdata;
pr_info("%s, started", __func__);
data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -1310,10 +1404,17 @@ static int lsm330dlc_gyro_probe(struct i2c_client *client,
}
data->client = client;
- data->drop_next_event = 0;
+ data->sensitivity_value = 2;
/* read chip id */
ret = i2c_smbus_read_byte_data(client, WHO_AM_I);
+
+#if defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON)
+ if (system_rev == 13) {
+ if (ret == 0xD5) /*KR330D chip ID only use CHN rev.13 */
+ ret = 0xD4;
+ }
+#endif
if (ret != DEVICE_ID) {
if (ret < 0) {
pr_err("%s: i2c for reading chip id failed\n",
@@ -1460,11 +1561,31 @@ static int lsm330dlc_gyro_probe(struct i2c_client *client,
goto err_device_create_file9;
}
+ /* set mounting position of the sensor */
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ /*Set by default position 2, it doesn't adjust raw value*/
+ data->position = 2;
+ data->axis_adjust = false;
+ pr_info("%s, using defualt position = %d\n", __func__,
+ data->position);
+ } else {
+ data->position = pdata->gyro_get_position();
+ data->axis_adjust = pdata->axis_adjust;
+ pr_info("%s, position = %d\n", __func__, data->position);
+ }
+ err = device_create_file(data->dev, &dev_attr_position);
+ if (err < 0) {
+ pr_err("%s: Failed to create device file(%s)\n",
+ __func__, dev_attr_position.attr.name);
+ goto err_device_create_file10;
+ }
+
#ifdef DEBUG_REGISTER
if (device_create_file(data->dev, &dev_attr_reg_data) < 0) {
pr_err("%s: Failed to create device file(%s)!\n", __func__,
dev_attr_reg_data.attr.name);
- goto err_device_create_file10;
+ goto err_device_create_file11;
}
#endif
@@ -1474,9 +1595,11 @@ static int lsm330dlc_gyro_probe(struct i2c_client *client,
return 0;
#ifdef DEBUG_REGISTER
+err_device_create_file11:
+ device_remove_file(data->dev, &dev_attr_position);
+#endif
err_device_create_file10:
device_remove_file(data->dev, &dev_attr_name);
-#endif
err_device_create_file9:
device_remove_file(data->dev, &dev_attr_vendor);
err_device_create_file8:
@@ -1517,6 +1640,7 @@ static int lsm330dlc_gyro_remove(struct i2c_client *client)
int err = 0;
struct lsm330dlc_gyro_data *data = i2c_get_clientdata(client);
+ device_remove_file(data->dev, &dev_attr_position);
device_remove_file(data->dev, &dev_attr_vendor);
device_remove_file(data->dev, &dev_attr_name);
device_remove_file(data->dev, &dev_attr_selftest_dps);