From 2489007e7d740ccbc3e0a202914e243ad5178787 Mon Sep 17 00:00:00 2001 From: codeworkx Date: Sat, 22 Sep 2012 09:48:20 +0200 Subject: merge opensource jb u5 Change-Id: I1aaec157aa196f3448eff8636134fce89a814cf2 --- drivers/sensor/Kconfig | 19 + drivers/sensor/Makefile | 26 +- drivers/sensor/ak8963-reg.h | 48 +++ drivers/sensor/ak8963.c | 880 +++++++++++++++++++++++++++++++++++++++ drivers/sensor/ak8975.c | 6 +- drivers/sensor/al3201.c | 697 +++++++++++++++++++++++++++++++ drivers/sensor/cm3663.c | 113 +---- drivers/sensor/cm36651.c | 30 +- drivers/sensor/gp2a_light.c | 103 ++++- drivers/sensor/gp2a_proximity.c | 226 +++++++++- drivers/sensor/k3dh.c | 14 +- drivers/sensor/lps331ap.c | 20 +- drivers/sensor/lsm330dlc_accel.c | 17 +- drivers/sensor/lsm330dlc_gyro.c | 210 ++++++++-- 14 files changed, 2206 insertions(+), 203 deletions(-) create mode 100644 drivers/sensor/ak8963-reg.h create mode 100644 drivers/sensor/ak8963.c create mode 100644 drivers/sensor/al3201.c (limited to 'drivers/sensor') 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ak8963-reg.h" +#include + +#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 +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 "); +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 #include #include -#if defined(CONFIG_MACH_S2PLUS) -#include -#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 #include #include +#include /*********** 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); -- cgit v1.1