Merge "leds: leds-qpnp: Correct switch frequency settings"
diff --git a/arch/arm/mach-msm/board-fsm9900-gpiomux.c b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
index dede706..990aefc 100644
--- a/arch/arm/mach-msm/board-fsm9900-gpiomux.c
+++ b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
@@ -17,6 +17,370 @@
#include <mach/board.h>
#include <mach/gpiomux.h>
+static struct gpiomux_setting blsp_uart_no_pull_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting blsp_uart_pull_up_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting blsp_i2c_config = {
+ .func = GPIOMUX_FUNC_3,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_blsp_configs[] __initdata = {
+ {
+ .gpio = 0, /* BLSP UART1 TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_uart_no_pull_config,
+ },
+ },
+ {
+ .gpio = 1, /* BLSP UART1 RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_uart_pull_up_config,
+ },
+ },
+ {
+ .gpio = 2, /* BLSP I2C SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP I2C SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 6, /* BLSP I2C SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 7, /* BLSP I2C SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 36, /* BLSP UART10 TX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_uart_no_pull_config,
+ },
+ },
+ {
+ .gpio = 37, /* BLSP UART10 RX */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_uart_pull_up_config,
+ },
+ },
+ {
+ .gpio = 38, /* BLSP I2C10 SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+ {
+ .gpio = 39, /* BLSP I2C10 SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &blsp_i2c_config,
+ },
+ },
+
+};
+
+static struct gpiomux_setting geni_func4_config = {
+ .func = GPIOMUX_FUNC_4,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting geni_func5_config = {
+ .func = GPIOMUX_FUNC_5,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config fsm_geni_configs[] __initdata = {
+ {
+ .gpio = 8, /* GENI7 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 9, /* GENI1 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 10, /* GENI2 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 11, /* GENI7 CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 20, /* GENI3 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func5_config,
+ },
+ },
+ {
+ .gpio = 21, /* GENI4 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func5_config,
+ },
+ },
+ {
+ .gpio = 22, /* GENI6 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func5_config,
+ },
+ },
+ {
+ .gpio = 23, /* GENI6 CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func5_config,
+ },
+ },
+ {
+ .gpio = 30, /* GENI5 DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+ {
+ .gpio = 31, /* GENI5 CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &geni_func4_config,
+ },
+ },
+
+};
+
+static struct gpiomux_setting dan_spi_func4_config = {
+ .func = GPIOMUX_FUNC_4,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting dan_spi_func1_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_dan_spi_configs[] __initdata = {
+ {
+ .gpio = 12, /* BLSP DAN0 SPI_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 13, /* BLSP DAN0 SPI_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 14, /* BLSP DAN0 SPI_CS */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 15, /* BLSP DAN0 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 16, /* BLSP DAN1 SPI_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 17, /* BLSP DAN1 SPI_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 18, /* BLSP DAN1 SPI_CS */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 19, /* BLSP DAN1 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func4_config,
+ },
+ },
+ {
+ .gpio = 81, /* BLSP DAN1 SPI_CS0 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func1_config,
+ },
+ },
+ {
+ .gpio = 82, /* BLSP DAN1 SPI_CS1 */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &dan_spi_func1_config,
+ },
+ },
+};
+
+static struct gpiomux_setting uim_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_4MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_uim_configs[] __initdata = {
+ {
+ .gpio = 24, /* UIM_DATA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &uim_config,
+ },
+ },
+ {
+ .gpio = 25, /* UIM_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &uim_config,
+ },
+ },
+ {
+ .gpio = 26, /* UIM_RESET */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &uim_config,
+ },
+ },
+ {
+ .gpio = 27, /* UIM_PRESENT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &uim_config,
+ },
+ },
+};
+
+static struct gpiomux_setting pcie_config = {
+ .func = GPIOMUX_FUNC_4,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_pcie_configs[] __initdata = {
+ {
+ .gpio = 28, /* BLSP PCIE1_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pcie_config,
+ },
+ },
+ {
+ .gpio = 32, /* BLSP PCIE0_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pcie_config,
+ },
+ },
+};
+
+static struct gpiomux_setting pps_out_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_4MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting pps_in_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gps_clk_in_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting gps_nav_tlmm_blank_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+static struct msm_gpiomux_config fsm_gps_configs[] __initdata = {
+ {
+ .gpio = 40, /* GPS_PPS_OUT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pps_out_config,
+ },
+ },
+ {
+ .gpio = 41, /* GPS_PPS_IN */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pps_in_config,
+ },
+ },
+ {
+ .gpio = 43, /* GPS_CLK_IN */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gps_clk_in_config,
+ },
+ },
+ {
+ .gpio = 120, /* GPS_NAV_TLMM_BLANK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gps_nav_tlmm_blank_config,
+ },
+ },
+};
+
+static struct gpiomux_setting sd_detect_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sd_wp_config = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config fsm_sd_configs[] __initdata = {
+ {
+ .gpio = 42, /* SD_CARD_DET */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &sd_detect_config,
+ },
+ },
+ {
+ .gpio = 122, /* BLSP SD WRITE PROTECT */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &sd_wp_config,
+ },
+ },
+};
+
void __init fsm9900_init_gpiomux(void)
{
int rc;
@@ -26,4 +390,13 @@
pr_err("%s failed %d\n", __func__, rc);
return;
}
+
+ msm_gpiomux_install(fsm_blsp_configs, ARRAY_SIZE(fsm_blsp_configs));
+ msm_gpiomux_install(fsm_geni_configs, ARRAY_SIZE(fsm_geni_configs));
+ msm_gpiomux_install(fsm_dan_spi_configs,
+ ARRAY_SIZE(fsm_dan_spi_configs));
+ msm_gpiomux_install(fsm_uim_configs, ARRAY_SIZE(fsm_uim_configs));
+ msm_gpiomux_install(fsm_pcie_configs, ARRAY_SIZE(fsm_pcie_configs));
+ msm_gpiomux_install(fsm_gps_configs, ARRAY_SIZE(fsm_gps_configs));
+ msm_gpiomux_install(fsm_sd_configs, ARRAY_SIZE(fsm_sd_configs));
}
diff --git a/drivers/gud/mobicore_driver/api.c b/drivers/gud/mobicore_driver/api.c
index 871f6cc..b47383a0 100644
--- a/drivers/gud/mobicore_driver/api.c
+++ b/drivers/gud/mobicore_driver/api.c
@@ -98,7 +98,11 @@
*/
struct mc_instance *mobicore_open(void)
{
- return mc_alloc_instance();
+ struct mc_instance *instance = mc_alloc_instance();
+ if(instance) {
+ instance->admin = true;
+ }
+ return instance;
}
EXPORT_SYMBOL(mobicore_open);
diff --git a/drivers/gud/mobicore_driver/build_tag.h b/drivers/gud/mobicore_driver/build_tag.h
index 2a7772e..4a24275 100644
--- a/drivers/gud/mobicore_driver/build_tag.h
+++ b/drivers/gud/mobicore_driver/build_tag.h
@@ -26,4 +26,4 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define MOBICORE_COMPONENT_BUILD_TAG \
- "*** GC_MSM8960_Release_V019 ###"
+ "*** t-base-202_V001 ###"
diff --git a/drivers/gud/mobicore_driver/main.c b/drivers/gud/mobicore_driver/main.c
index 6f91974..0451452 100644
--- a/drivers/gud/mobicore_driver/main.c
+++ b/drivers/gud/mobicore_driver/main.c
@@ -47,7 +47,7 @@
/* Define a MobiCore device structure for use with dev_debug() etc */
struct device_driver mcd_debug_name = {
- .name = "mcdrvkmod"
+ .name = "MobiCore"
};
struct device mcd_debug_subname = {
diff --git a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
index 4768f39..7854fc5 100644
--- a/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
+++ b/drivers/gud/mobicore_driver/platforms/msm8960_surf_std/platform.h
@@ -41,7 +41,15 @@
/* Enable the use of vm_unamp instead of the deprecated do_munmap
* and other 3.7 features
*/
+#ifndef CONFIG_ARCH_MSM8960
#define MC_VM_UNMAP
+#endif
+
+
+#if defined(CONFIG_ARCH_MSM8974) || defined(CONFIG_ARCH_MSM8226)
+/* Perform clock enable/disable */
+#define MC_CRYPTO_CLOCK_MANAGEMENT
+#endif
/* Enable Power Management for Crypto Engine */
#define MC_CRYPTO_CLOCK_MANAGEMENT
diff --git a/drivers/gud/mobicore_driver/pm.c b/drivers/gud/mobicore_driver/pm.c
index 3ad2015..55a1ef7 100644
--- a/drivers/gud/mobicore_driver/pm.c
+++ b/drivers/gud/mobicore_driver/pm.c
@@ -67,8 +67,8 @@
MCDRV_DBG(mcd, "MobiCore IDLE=%d!", flags->schedule);
MCDRV_DBG(mcd,
"MobiCore Request Sleep=%d!", flags->sleep_mode.SleepReq);
- MCDRV_DBG(mcd, "MobiCore Sleep Ready=%d!",
- flags->sleep_mode.ReadyToSleep);
+ MCDRV_DBG(mcd,
+ "MobiCore Sleep Ready=%d!", flags->sleep_mode.ReadyToSleep);
}
static int mc_suspend_notifier(struct notifier_block *nb,
diff --git a/drivers/gud/mobicore_driver/public/mc_linux.h b/drivers/gud/mobicore_driver/public/mc_linux.h
index 9c49aef..af027dc 100644
--- a/drivers/gud/mobicore_driver/public/mc_linux.h
+++ b/drivers/gud/mobicore_driver/public/mc_linux.h
@@ -43,6 +43,10 @@
#include "version.h"
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
+
#define MC_ADMIN_DEVNODE "mobicore"
#define MC_USER_DEVNODE "mobicore-user"
diff --git a/drivers/gud/mobicore_kernelapi/clientlib.c b/drivers/gud/mobicore_kernelapi/clientlib.c
index 7038e02..16b52e5 100644
--- a/drivers/gud/mobicore_kernelapi/clientlib.c
+++ b/drivers/gud/mobicore_kernelapi/clientlib.c
@@ -299,7 +299,8 @@
{
session->device_id,
*uuid,
- (uint32_t)wsm->phys_addr,
+ (uint32_t)(wsm->phys_addr) & 0xFFF,
+ wsm->handle,
len
}
};
@@ -926,7 +927,8 @@
{
session->session_id,
handle,
- (uint32_t)(map_info->secure_virt_addr)
+ (uint32_t)(map_info->secure_virt_addr),
+ map_info->secure_virt_len
}
};
@@ -956,11 +958,11 @@
break;
}
- struct mc_drv_rsp_unmap_bulk_mem_payload_t
+ /*struct mc_drv_rsp_unmap_bulk_mem_payload_t
rsp_unmap_bulk_mem_payload;
connection_read_datablock(dev_con,
&rsp_unmap_bulk_mem_payload,
- sizeof(rsp_unmap_bulk_mem_payload));
+ sizeof(rsp_unmap_bulk_mem_payload));*/
/*
* Unregister mapped bulk buffer from Kernel Module and
diff --git a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
index 3b8eb4b..eaf7e6c 100644
--- a/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
+++ b/drivers/gud/mobicore_kernelapi/public/mobicore_driver_cmd.h
@@ -109,6 +109,7 @@
uint32_t device_id;
struct mc_uuid_t uuid;
uint32_t tci;
+ uint32_t handle;
uint32_t len;
};
@@ -119,10 +120,8 @@
struct mc_drv_rsp_open_session_payload_t {
- uint32_t device_id;
uint32_t session_id;
uint32_t device_session_id;
- uint32_t mc_result;
uint32_t session_magic;
};
@@ -186,7 +185,6 @@
struct mc_drv_rsp_map_bulk_mem_payload_t {
uint32_t session_id;
uint32_t secure_virtual_adr;
- uint32_t mc_result;
};
struct mc_drv_rsp_map_bulk_mem_t {
@@ -210,7 +208,6 @@
struct mc_drv_rsp_unmap_bulk_mem_payload_t {
uint32_t response_id;
uint32_t session_id;
- uint32_t mc_result;
};
struct mc_drv_rsp_unmap_bulk_mem_t {
diff --git a/drivers/input/misc/cm36283.c b/drivers/input/misc/cm36283.c
new file mode 100644
index 0000000..6280013
--- /dev/null
+++ b/drivers/input/misc/cm36283.c
@@ -0,0 +1,1658 @@
+/* drivers/input/misc/cm36283.c - cm36283 optical sensors driver
+ *
+ * Copyright (C) 2012 Capella Microsystems Inc.
+ * Author: Frank Hsieh <pengyueh@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/miscdevice.h>
+#include <linux/lightsensor.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <asm/mach-types.h>
+#include <linux/cm36283.h>
+#include <linux/capella_cm3602.h>
+#include <asm/setup.h>
+#include <linux/wakelock.h>
+#include <linux/jiffies.h>
+
+#define D(x...) pr_info(x)
+
+#define I2C_RETRY_COUNT 10
+
+#define NEAR_DELAY_TIME ((100 * HZ) / 1000)
+
+#define CONTROL_INT_ISR_REPORT 0x00
+#define CONTROL_ALS 0x01
+#define CONTROL_PS 0x02
+
+static int record_init_fail = 0;
+static void sensor_irq_do_work(struct work_struct *work);
+static DECLARE_WORK(sensor_irq_work, sensor_irq_do_work);
+
+struct cm36283_info {
+ struct class *cm36283_class;
+ struct device *ls_dev;
+ struct device *ps_dev;
+
+ struct input_dev *ls_input_dev;
+ struct input_dev *ps_input_dev;
+
+ struct early_suspend early_suspend;
+ struct i2c_client *i2c_client;
+ struct workqueue_struct *lp_wq;
+
+ int intr_pin;
+ int als_enable;
+ int ps_enable;
+ int ps_irq_flag;
+
+ uint16_t *adc_table;
+ uint16_t cali_table[10];
+ int irq;
+
+ int ls_calibrate;
+
+ int (*power)(int, uint8_t); /* power to the chip */
+
+ uint32_t als_kadc;
+ uint32_t als_gadc;
+ uint16_t golden_adc;
+
+ struct wake_lock ps_wake_lock;
+ int psensor_opened;
+ int lightsensor_opened;
+ uint8_t slave_addr;
+
+ uint8_t ps_close_thd_set;
+ uint8_t ps_away_thd_set;
+ int current_level;
+ uint16_t current_adc;
+
+ uint16_t ps_conf1_val;
+ uint16_t ps_conf3_val;
+
+ uint16_t ls_cmd;
+ uint8_t record_clear_int_fail;
+};
+struct cm36283_info *lp_info;
+int fLevel=-1;
+static struct mutex als_enable_mutex, als_disable_mutex, als_get_adc_mutex;
+static struct mutex ps_enable_mutex, ps_disable_mutex, ps_get_adc_mutex;
+static struct mutex CM36283_control_mutex;
+static int lightsensor_enable(struct cm36283_info *lpi);
+static int lightsensor_disable(struct cm36283_info *lpi);
+static int initial_cm36283(struct cm36283_info *lpi);
+static void psensor_initial_cmd(struct cm36283_info *lpi);
+
+int32_t als_kadc;
+
+static int control_and_report(struct cm36283_info *lpi, uint8_t mode, uint16_t param);
+
+static int I2C_RxData(uint16_t slaveAddr, uint8_t cmd, uint8_t *rxData, int length)
+{
+ uint8_t loop_i;
+ int val;
+ struct cm36283_info *lpi = lp_info;
+ uint8_t subaddr[1];
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = slaveAddr,
+ .flags = 0,
+ .len = 1,
+ .buf = subaddr,
+ },
+ {
+ .addr = slaveAddr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = rxData,
+ },
+ };
+ subaddr[0] = cmd;
+
+ for (loop_i = 0; loop_i < I2C_RETRY_COUNT; loop_i++) {
+
+ if (i2c_transfer(lp_info->i2c_client->adapter, msgs, 2) > 0)
+ break;
+
+ val = gpio_get_value(lpi->intr_pin);
+ /*check intr GPIO when i2c error*/
+ if (loop_i == 0 || loop_i == I2C_RETRY_COUNT -1)
+ D("[PS][CM36283 error] %s, i2c err, slaveAddr 0x%x ISR gpio %d = %d, record_init_fail %d \n",
+ __func__, slaveAddr, lpi->intr_pin, val, record_init_fail);
+
+ msleep(10);
+ }
+ if (loop_i >= I2C_RETRY_COUNT) {
+ printk(KERN_ERR "[PS_ERR][CM36283 error] %s retry over %d\n",
+ __func__, I2C_RETRY_COUNT);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int I2C_TxData(uint16_t slaveAddr, uint8_t *txData, int length)
+{
+ uint8_t loop_i;
+ int val;
+ struct cm36283_info *lpi = lp_info;
+ struct i2c_msg msg[] = {
+ {
+ .addr = slaveAddr,
+ .flags = 0,
+ .len = length,
+ .buf = txData,
+ },
+ };
+
+ for (loop_i = 0; loop_i < I2C_RETRY_COUNT; loop_i++) {
+ if (i2c_transfer(lp_info->i2c_client->adapter, msg, 1) > 0)
+ break;
+
+ val = gpio_get_value(lpi->intr_pin);
+ /*check intr GPIO when i2c error*/
+ if (loop_i == 0 || loop_i == I2C_RETRY_COUNT -1)
+ D("[PS][CM36283 error] %s, i2c err, slaveAddr 0x%x, value 0x%x, ISR gpio%d = %d, record_init_fail %d\n",
+ __func__, slaveAddr, txData[0], lpi->intr_pin, val, record_init_fail);
+
+ msleep(10);
+ }
+
+ if (loop_i >= I2C_RETRY_COUNT) {
+ printk(KERN_ERR "[PS_ERR][CM36283 error] %s retry over %d\n",
+ __func__, I2C_RETRY_COUNT);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int _cm36283_I2C_Read_Word(uint16_t slaveAddr, uint8_t cmd, uint16_t *pdata)
+{
+ uint8_t buffer[2];
+ int ret = 0;
+
+ if (pdata == NULL)
+ return -EFAULT;
+
+ ret = I2C_RxData(slaveAddr, cmd, buffer, 2);
+ if (ret < 0) {
+ pr_err(
+ "[PS_ERR][CM3218 error]%s: I2C_RxData fail [0x%x, 0x%x]\n",
+ __func__, slaveAddr, cmd);
+ return ret;
+ }
+
+ *pdata = (buffer[1]<<8)|buffer[0];
+#if 0
+ /* Debug use */
+ printk(KERN_DEBUG "[CM3218] %s: I2C_RxData[0x%x, 0x%x] = 0x%x\n",
+ __func__, slaveAddr, cmd, *pdata);
+#endif
+ return ret;
+}
+
+static int _cm36283_I2C_Write_Word(uint16_t SlaveAddress, uint8_t cmd, uint16_t data)
+{
+ char buffer[3];
+ int ret = 0;
+#if 0
+ /* Debug use */
+ printk(KERN_DEBUG
+ "[CM3218] %s: _cm36283_I2C_Write_Word[0x%x, 0x%x, 0x%x]\n",
+ __func__, SlaveAddress, cmd, data);
+#endif
+ buffer[0] = cmd;
+ buffer[1] = (uint8_t)(data&0xff);
+ buffer[2] = (uint8_t)((data&0xff00)>>8);
+
+ ret = I2C_TxData(SlaveAddress, buffer, 3);
+ if (ret < 0) {
+ pr_err("[PS_ERR][CM3218 error]%s: I2C_TxData fail\n", __func__);
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static int get_ls_adc_value(uint16_t *als_step, bool resume)
+{
+ struct cm36283_info *lpi = lp_info;
+ uint32_t tmpResult;
+ int ret = 0;
+
+ if (als_step == NULL)
+ return -EFAULT;
+
+ /* Read ALS data: */
+ ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ALS_DATA, als_step);
+ if (ret < 0) {
+ pr_err(
+ "[LS][CM3218 error]%s: _cm36283_I2C_Read_Word fail\n",
+ __func__);
+ return -EIO;
+ }
+
+ if (!lpi->ls_calibrate) {
+ tmpResult = (uint32_t)(*als_step) * lpi->als_gadc / lpi->als_kadc;
+ if (tmpResult > 0xFFFF)
+ *als_step = 0xFFFF;
+ else
+ *als_step = tmpResult;
+ }
+
+ D("[LS][CM3218] %s: raw adc = 0x%X, ls_calibrate = %d\n",
+ __func__, *als_step, lpi->ls_calibrate);
+
+ return ret;
+}
+
+static int set_lsensor_range(uint16_t low_thd, uint16_t high_thd)
+{
+ int ret = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_THDH, high_thd);
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_THDL, low_thd);
+
+ return ret;
+}
+
+static int get_ps_adc_value(uint16_t *data)
+{
+ int ret = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ if (data == NULL)
+ return -EFAULT;
+
+ ret = _cm36283_I2C_Read_Word(lpi->slave_addr, PS_DATA, data);
+
+ (*data) &= 0xFF;
+
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: _cm36283_I2C_Read_Word fail\n",
+ __func__);
+ return -EIO;
+ } else {
+ pr_err(
+ "[PS][CM36283 OK]%s: _cm36283_I2C_Read_Word OK 0x%x\n",
+ __func__, *data);
+ }
+
+ return ret;
+}
+
+static uint16_t mid_value(uint16_t value[], uint8_t size)
+{
+ int i = 0, j = 0;
+ uint16_t temp = 0;
+
+ if (size < 3)
+ return 0;
+
+ for (i = 0; i < (size - 1); i++)
+ for (j = (i + 1); j < size; j++)
+ if (value[i] > value[j]) {
+ temp = value[i];
+ value[i] = value[j];
+ value[j] = temp;
+ }
+ return value[((size - 1) / 2)];
+}
+
+static int get_stable_ps_adc_value(uint16_t *ps_adc)
+{
+ uint16_t value[3] = {0, 0, 0}, mid_val = 0;
+ int ret = 0;
+ int i = 0;
+ int wait_count = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ for (i = 0; i < 3; i++) {
+ /*wait interrupt GPIO high*/
+ while (gpio_get_value(lpi->intr_pin) == 0) {
+ msleep(10);
+ wait_count++;
+ if (wait_count > 12) {
+ pr_err("[PS_ERR][CM36283 error]%s: interrupt GPIO low,"
+ " get_ps_adc_value\n", __func__);
+ return -EIO;
+ }
+ }
+
+ ret = get_ps_adc_value(&value[i]);
+ if (ret < 0) {
+ pr_err("[PS_ERR][CM36283 error]%s: get_ps_adc_value\n",
+ __func__);
+ return -EIO;
+ }
+
+ if (wait_count < 60/10) {/*wait gpio less than 60ms*/
+ msleep(60 - (10*wait_count));
+ }
+ wait_count = 0;
+ }
+
+ /*D("Sta_ps: Before sort, value[0, 1, 2] = [0x%x, 0x%x, 0x%x]",
+ value[0], value[1], value[2]);*/
+ mid_val = mid_value(value, 3);
+ D("Sta_ps: After sort, value[0, 1, 2] = [0x%x, 0x%x, 0x%x]",
+ value[0], value[1], value[2]);
+ *ps_adc = (mid_val & 0xFF);
+
+ return 0;
+}
+
+static void sensor_irq_do_work(struct work_struct *work)
+{
+ struct cm36283_info *lpi = lp_info;
+ uint16_t intFlag;
+ _cm36283_I2C_Read_Word(lpi->slave_addr, INT_FLAG, &intFlag);
+ control_and_report(lpi, CONTROL_INT_ISR_REPORT, intFlag);
+
+ enable_irq(lpi->irq);
+}
+
+static irqreturn_t cm36283_irq_handler(int irq, void *data)
+{
+ struct cm36283_info *lpi = data;
+
+ disable_irq_nosync(lpi->irq);
+ queue_work(lpi->lp_wq, &sensor_irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int als_power(int enable)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ if (lpi->power)
+ lpi->power(LS_PWR_ON, 1);
+
+ return 0;
+}
+
+static void ls_initial_cmd(struct cm36283_info *lpi)
+{
+ /*must disable l-sensor interrupt befrore IST create*//*disable ALS func*/
+ lpi->ls_cmd &= CM36283_ALS_INT_MASK;
+ lpi->ls_cmd |= CM36283_ALS_SD;
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+}
+
+static void psensor_initial_cmd(struct cm36283_info *lpi)
+{
+ /*must disable p-sensor interrupt befrore IST create*//*disable ALS func*/
+ lpi->ps_conf1_val |= CM36283_PS_SD;
+ lpi->ps_conf1_val &= CM36283_PS_INT_MASK;
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val);
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF3, lpi->ps_conf3_val);
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_THD, (lpi->ps_close_thd_set <<8)| lpi->ps_away_thd_set);
+
+ D("[PS][CM36283] %s, finish\n", __func__);
+}
+
+static int psensor_enable(struct cm36283_info *lpi)
+{
+ int ret = -EIO;
+
+ mutex_lock(&ps_enable_mutex);
+ D("[PS][CM36283] %s\n", __func__);
+
+ if ( lpi->ps_enable ) {
+ D("[PS][CM36283] %s: already enabled\n", __func__);
+ ret = 0;
+ } else
+ ret = control_and_report(lpi, CONTROL_PS, 1);
+
+ mutex_unlock(&ps_enable_mutex);
+ return ret;
+}
+
+static int psensor_disable(struct cm36283_info *lpi)
+{
+ int ret = -EIO;
+
+ mutex_lock(&ps_disable_mutex);
+ D("[PS][CM36283] %s\n", __func__);
+
+ if ( lpi->ps_enable == 0 ) {
+ D("[PS][CM36283] %s: already disabled\n", __func__);
+ ret = 0;
+ } else
+ ret = control_and_report(lpi, CONTROL_PS,0);
+
+ mutex_unlock(&ps_disable_mutex);
+ return ret;
+}
+
+static int psensor_open(struct inode *inode, struct file *file)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[PS][CM36283] %s\n", __func__);
+
+ if (lpi->psensor_opened)
+ return -EBUSY;
+
+ lpi->psensor_opened = 1;
+
+ return 0;
+}
+
+static int psensor_release(struct inode *inode, struct file *file)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[PS][CM36283] %s\n", __func__);
+
+ lpi->psensor_opened = 0;
+
+ return psensor_disable(lpi);
+ //return 0;
+}
+
+static long psensor_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int val;
+ struct cm36283_info *lpi = lp_info;
+
+ D("[PS][CM36283] %s cmd %d\n", __func__, _IOC_NR(cmd));
+
+ switch (cmd) {
+ case CAPELLA_CM3602_IOCTL_ENABLE:
+ if (get_user(val, (unsigned long __user *)arg))
+ return -EFAULT;
+ if (val)
+ return psensor_enable(lpi);
+ else
+ return psensor_disable(lpi);
+ break;
+ case CAPELLA_CM3602_IOCTL_GET_ENABLED:
+ return put_user(lpi->ps_enable, (unsigned long __user *)arg);
+ break;
+ default:
+ pr_err("[PS][CM36283 error]%s: invalid cmd %d\n",
+ __func__, _IOC_NR(cmd));
+ return -EINVAL;
+ }
+}
+
+static const struct file_operations psensor_fops = {
+ .owner = THIS_MODULE,
+ .open = psensor_open,
+ .release = psensor_release,
+ .unlocked_ioctl = psensor_ioctl
+};
+
+struct miscdevice psensor_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "proximity",
+ .fops = &psensor_fops
+};
+
+void lightsensor_set_kvalue(struct cm36283_info *lpi)
+{
+ if (!lpi) {
+ pr_err("[LS][CM36283 error]%s: ls_info is empty\n", __func__);
+ return;
+ }
+
+ D("[LS][CM36283] %s: ALS calibrated als_kadc=0x%x\n",
+ __func__, als_kadc);
+
+ if (als_kadc >> 16 == ALS_CALIBRATED)
+ lpi->als_kadc = als_kadc & 0xFFFF;
+ else {
+ lpi->als_kadc = 0;
+ D("[LS][CM36283] %s: no ALS calibrated\n", __func__);
+ }
+
+ if (lpi->als_kadc && lpi->golden_adc > 0) {
+ lpi->als_kadc = (lpi->als_kadc > 0 && lpi->als_kadc < 0x1000) ?
+ lpi->als_kadc : lpi->golden_adc;
+ lpi->als_gadc = lpi->golden_adc;
+ } else {
+ lpi->als_kadc = 1;
+ lpi->als_gadc = 1;
+ }
+ D("[LS][CM36283] %s: als_kadc=0x%x, als_gadc=0x%x\n",
+ __func__, lpi->als_kadc, lpi->als_gadc);
+}
+
+
+static int lightsensor_update_table(struct cm36283_info *lpi)
+{
+ uint32_t tmpData[10];
+ int i;
+ for (i = 0; i < 10; i++) {
+ tmpData[i] = (uint32_t)(*(lpi->adc_table + i))
+ * lpi->als_kadc / lpi->als_gadc ;
+ if( tmpData[i] <= 0xFFFF ){
+ lpi->cali_table[i] = (uint16_t) tmpData[i];
+ } else {
+ lpi->cali_table[i] = 0xFFFF;
+ }
+ D("[LS][CM36283] %s: Calibrated adc_table: data[%d], %x\n",
+ __func__, i, lpi->cali_table[i]);
+ }
+
+ return 0;
+}
+
+
+static int lightsensor_enable(struct cm36283_info *lpi)
+{
+ int ret = -EIO;
+
+ mutex_lock(&als_enable_mutex);
+ D("[LS][CM36283] %s\n", __func__);
+
+ if (lpi->als_enable) {
+ D("[LS][CM36283] %s: already enabled\n", __func__);
+ ret = 0;
+ } else
+ ret = control_and_report(lpi, CONTROL_ALS, 1);
+
+ mutex_unlock(&als_enable_mutex);
+ return ret;
+}
+
+static int lightsensor_disable(struct cm36283_info *lpi)
+{
+ int ret = -EIO;
+ mutex_lock(&als_disable_mutex);
+ D("[LS][CM36283] %s\n", __func__);
+
+ if ( lpi->als_enable == 0 ) {
+ D("[LS][CM36283] %s: already disabled\n", __func__);
+ ret = 0;
+ } else
+ ret = control_and_report(lpi, CONTROL_ALS, 0);
+
+ mutex_unlock(&als_disable_mutex);
+ return ret;
+}
+
+static int lightsensor_open(struct inode *inode, struct file *file)
+{
+ struct cm36283_info *lpi = lp_info;
+ int rc = 0;
+
+ D("[LS][CM36283] %s\n", __func__);
+ if (lpi->lightsensor_opened) {
+ pr_err("[LS][CM36283 error]%s: already opened\n", __func__);
+ rc = -EBUSY;
+ }
+ lpi->lightsensor_opened = 1;
+ return rc;
+}
+
+static int lightsensor_release(struct inode *inode, struct file *file)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[LS][CM36283] %s\n", __func__);
+ lpi->lightsensor_opened = 0;
+ return 0;
+}
+
+static long lightsensor_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc, val;
+ struct cm36283_info *lpi = lp_info;
+
+ /*D("[CM36283] %s cmd %d\n", __func__, _IOC_NR(cmd));*/
+
+ switch (cmd) {
+ case LIGHTSENSOR_IOCTL_ENABLE:
+ if (get_user(val, (unsigned long __user *)arg)) {
+ rc = -EFAULT;
+ break;
+ }
+ D("[LS][CM36283] %s LIGHTSENSOR_IOCTL_ENABLE, value = %d\n",
+ __func__, val);
+ rc = val ? lightsensor_enable(lpi) : lightsensor_disable(lpi);
+ break;
+ case LIGHTSENSOR_IOCTL_GET_ENABLED:
+ val = lpi->als_enable;
+ D("[LS][CM36283] %s LIGHTSENSOR_IOCTL_GET_ENABLED, enabled %d\n",
+ __func__, val);
+ rc = put_user(val, (unsigned long __user *)arg);
+ break;
+ default:
+ pr_err("[LS][CM36283 error]%s: invalid cmd %d\n",
+ __func__, _IOC_NR(cmd));
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static const struct file_operations lightsensor_fops = {
+ .owner = THIS_MODULE,
+ .open = lightsensor_open,
+ .release = lightsensor_release,
+ .unlocked_ioctl = lightsensor_ioctl
+};
+
+static struct miscdevice lightsensor_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "lightsensor",
+ .fops = &lightsensor_fops
+};
+
+
+static ssize_t ps_adc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ uint16_t value;
+ int ret;
+ struct cm36283_info *lpi = lp_info;
+ int intr_val;
+
+ intr_val = gpio_get_value(lpi->intr_pin);
+
+ get_ps_adc_value(&value);
+
+ ret = sprintf(buf, "ADC[0x%04X], ENABLE = %d, intr_pin = %d\n", value, lpi->ps_enable, intr_val);
+
+ return ret;
+}
+
+static ssize_t ps_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ps_en;
+ struct cm36283_info *lpi = lp_info;
+
+ ps_en = -1;
+ sscanf(buf, "%d", &ps_en);
+
+ if (ps_en != 0 && ps_en != 1
+ && ps_en != 10 && ps_en != 13 && ps_en != 16)
+ return -EINVAL;
+
+ if (ps_en) {
+ D("[PS][CM36283] %s: ps_en=%d\n",
+ __func__, ps_en);
+ psensor_enable(lpi);
+ } else
+ psensor_disable(lpi);
+
+ D("[PS][CM36283] %s\n", __func__);
+
+ return count;
+}
+
+static DEVICE_ATTR(ps_adc, 0664, ps_adc_show, ps_enable_store);
+
+unsigned PS_cmd_test_value;
+static ssize_t ps_parameters_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct cm36283_info *lpi = lp_info;
+
+ ret = sprintf(buf, "PS_close_thd_set = 0x%x, PS_away_thd_set = 0x%x, PS_cmd_cmd:value = 0x%x\n",
+ lpi->ps_close_thd_set, lpi->ps_away_thd_set, PS_cmd_test_value);
+
+ return ret;
+}
+
+static ssize_t ps_parameters_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ struct cm36283_info *lpi = lp_info;
+ char *token[10];
+ int i;
+
+ printk(KERN_INFO "[PS][CM36283] %s\n", buf);
+ for (i = 0; i < 3; i++)
+ token[i] = strsep((char **)&buf, " ");
+
+ lpi->ps_close_thd_set = simple_strtoul(token[0], NULL, 16);
+ lpi->ps_away_thd_set = simple_strtoul(token[1], NULL, 16);
+ PS_cmd_test_value = simple_strtoul(token[2], NULL, 16);
+ printk(KERN_INFO
+ "[PS][CM36283]Set PS_close_thd_set = 0x%x, PS_away_thd_set = 0x%x, PS_cmd_cmd:value = 0x%x\n",
+ lpi->ps_close_thd_set, lpi->ps_away_thd_set, PS_cmd_test_value);
+
+ D("[PS][CM36283] %s\n", __func__);
+
+ return count;
+}
+
+static DEVICE_ATTR(ps_parameters, 0664,
+ ps_parameters_show, ps_parameters_store);
+
+
+static ssize_t ps_conf_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cm36283_info *lpi = lp_info;
+ return sprintf(buf, "PS_CONF1 = 0x%x, PS_CONF3 = 0x%x\n", lpi->ps_conf1_val, lpi->ps_conf3_val);
+}
+static ssize_t ps_conf_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int code1, code2;
+ struct cm36283_info *lpi = lp_info;
+
+ sscanf(buf, "0x%x 0x%x", &code1, &code2);
+
+ D("[PS]%s: store value PS conf1 reg = 0x%x PS conf3 reg = 0x%x\n", __func__, code1, code2);
+
+ lpi->ps_conf1_val = code1;
+ lpi->ps_conf3_val = code2;
+
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF3, lpi->ps_conf3_val );
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val );
+
+ return count;
+}
+static DEVICE_ATTR(ps_conf, 0664, ps_conf_show, ps_conf_store);
+
+static ssize_t ps_thd_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct cm36283_info *lpi = lp_info;
+ ret = sprintf(buf, "%s ps_close_thd_set = 0x%x, ps_away_thd_set = 0x%x\n", __func__, lpi->ps_close_thd_set, lpi->ps_away_thd_set);
+ return ret;
+}
+static ssize_t ps_thd_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int code;
+ struct cm36283_info *lpi = lp_info;
+
+ sscanf(buf, "0x%x", &code);
+
+ D("[PS]%s: store value = 0x%x\n", __func__, code);
+
+ lpi->ps_away_thd_set = code &0xFF;
+ lpi->ps_close_thd_set = (code &0xFF00)>>8;
+
+ D("[PS]%s: ps_close_thd_set = 0x%x, ps_away_thd_set = 0x%x\n", __func__, lpi->ps_close_thd_set, lpi->ps_away_thd_set);
+
+ return count;
+}
+static DEVICE_ATTR(ps_thd, 0664, ps_thd_show, ps_thd_store);
+
+static ssize_t ps_hw_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ ret = sprintf(buf, "PS1: reg = 0x%x, PS3: reg = 0x%x, ps_close_thd_set = 0x%x, ps_away_thd_set = 0x%x\n",
+ lpi->ps_conf1_val, lpi->ps_conf3_val, lpi->ps_close_thd_set, lpi->ps_away_thd_set);
+
+ return ret;
+}
+static ssize_t ps_hw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int code;
+// struct cm36283_info *lpi = lp_info;
+
+ sscanf(buf, "0x%x", &code);
+
+ D("[PS]%s: store value = 0x%x\n", __func__, code);
+
+ return count;
+}
+static DEVICE_ATTR(ps_hw, 0664, ps_hw_show, ps_hw_store);
+
+static ssize_t ls_adc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ struct cm36283_info *lpi = lp_info;
+
+ D("[LS][CM36283] %s: ADC = 0x%04X, Level = %d \n",
+ __func__, lpi->current_adc, lpi->current_level);
+ ret = sprintf(buf, "ADC[0x%04X] => level %d\n",
+ lpi->current_adc, lpi->current_level);
+
+ return ret;
+}
+
+static DEVICE_ATTR(ls_adc, 0664, ls_adc_show, NULL);
+
+static ssize_t ls_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret = 0;
+ struct cm36283_info *lpi = lp_info;
+
+ ret = sprintf(buf, "Light sensor Auto Enable = %d\n",
+ lpi->als_enable);
+
+ return ret;
+}
+
+static ssize_t ls_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ int ls_auto;
+ struct cm36283_info *lpi = lp_info;
+
+ ls_auto = -1;
+ sscanf(buf, "%d", &ls_auto);
+
+ if (ls_auto != 0 && ls_auto != 1 && ls_auto != 147)
+ return -EINVAL;
+
+ if (ls_auto) {
+ lpi->ls_calibrate = (ls_auto == 147) ? 1 : 0;
+ ret = lightsensor_enable(lpi);
+ } else {
+ lpi->ls_calibrate = 0;
+ ret = lightsensor_disable(lpi);
+ }
+
+ D("[LS][CM36283] %s: lpi->als_enable = %d, lpi->ls_calibrate = %d, ls_auto=%d\n",
+ __func__, lpi->als_enable, lpi->ls_calibrate, ls_auto);
+
+ if (ret < 0)
+ pr_err(
+ "[LS][CM36283 error]%s: set auto light sensor fail\n",
+ __func__);
+
+ return count;
+}
+
+static DEVICE_ATTR(ls_auto, 0664,
+ ls_enable_show, ls_enable_store);
+
+static ssize_t ls_kadc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cm36283_info *lpi = lp_info;
+ int ret;
+
+ ret = sprintf(buf, "kadc = 0x%x",
+ lpi->als_kadc);
+
+ return ret;
+}
+
+static ssize_t ls_kadc_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cm36283_info *lpi = lp_info;
+ int kadc_temp = 0;
+
+ sscanf(buf, "%d", &kadc_temp);
+
+ mutex_lock(&als_get_adc_mutex);
+ if(kadc_temp != 0) {
+ lpi->als_kadc = kadc_temp;
+ if( lpi->als_gadc != 0){
+ if (lightsensor_update_table(lpi) < 0)
+ printk(KERN_ERR "[LS][CM36283 error] %s: update ls table fail\n", __func__);
+ } else {
+ printk(KERN_INFO "[LS]%s: als_gadc =0x%x wait to be set\n",
+ __func__, lpi->als_gadc);
+ }
+ } else {
+ printk(KERN_INFO "[LS]%s: als_kadc can't be set to zero\n",
+ __func__);
+ }
+
+ mutex_unlock(&als_get_adc_mutex);
+ return count;
+}
+
+static DEVICE_ATTR(ls_kadc, 0664, ls_kadc_show, ls_kadc_store);
+
+static ssize_t ls_gadc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cm36283_info *lpi = lp_info;
+ int ret;
+
+ ret = sprintf(buf, "gadc = 0x%x\n", lpi->als_gadc);
+
+ return ret;
+}
+
+static ssize_t ls_gadc_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cm36283_info *lpi = lp_info;
+ int gadc_temp = 0;
+
+ sscanf(buf, "%d", &gadc_temp);
+
+ mutex_lock(&als_get_adc_mutex);
+ if(gadc_temp != 0) {
+ lpi->als_gadc = gadc_temp;
+ if( lpi->als_kadc != 0){
+ if (lightsensor_update_table(lpi) < 0)
+ printk(KERN_ERR "[LS][CM36283 error] %s: update ls table fail\n", __func__);
+ } else {
+ printk(KERN_INFO "[LS]%s: als_kadc =0x%x wait to be set\n",
+ __func__, lpi->als_kadc);
+ }
+ } else {
+ printk(KERN_INFO "[LS]%s: als_gadc can't be set to zero\n",
+ __func__);
+ }
+ mutex_unlock(&als_get_adc_mutex);
+ return count;
+}
+
+static DEVICE_ATTR(ls_gadc, 0664, ls_gadc_show, ls_gadc_store);
+
+static ssize_t ls_adc_table_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned length = 0;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ length += sprintf(buf + length,
+ "[CM36283]Get adc_table[%d] = 0x%x ; %d, Get cali_table[%d] = 0x%x ; %d, \n",
+ i, *(lp_info->adc_table + i),
+ *(lp_info->adc_table + i),
+ i, *(lp_info->cali_table + i),
+ *(lp_info->cali_table + i));
+ }
+ return length;
+}
+
+static ssize_t ls_adc_table_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ struct cm36283_info *lpi = lp_info;
+ char *token[10];
+ uint16_t tempdata[10];
+ int i;
+
+ printk(KERN_INFO "[LS][CM36283]%s\n", buf);
+ for (i = 0; i < 10; i++) {
+ token[i] = strsep((char **)&buf, " ");
+ tempdata[i] = simple_strtoul(token[i], NULL, 16);
+ if (tempdata[i] < 1 || tempdata[i] > 0xffff) {
+ printk(KERN_ERR
+ "[LS][CM36283 error] adc_table[%d] = 0x%x Err\n",
+ i, tempdata[i]);
+ return count;
+ }
+ }
+ mutex_lock(&als_get_adc_mutex);
+ for (i = 0; i < 10; i++) {
+ lpi->adc_table[i] = tempdata[i];
+ printk(KERN_INFO
+ "[LS][CM36283]Set lpi->adc_table[%d] = 0x%x\n",
+ i, *(lp_info->adc_table + i));
+ }
+ if (lightsensor_update_table(lpi) < 0)
+ printk(KERN_ERR "[LS][CM36283 error] %s: update ls table fail\n",
+ __func__);
+ mutex_unlock(&als_get_adc_mutex);
+ D("[LS][CM36283] %s\n", __func__);
+
+ return count;
+}
+
+static DEVICE_ATTR(ls_adc_table, 0664,
+ ls_adc_table_show, ls_adc_table_store);
+
+static ssize_t ls_conf_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cm36283_info *lpi = lp_info;
+ return sprintf(buf, "ALS_CONF = %x\n", lpi->ls_cmd);
+}
+static ssize_t ls_conf_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cm36283_info *lpi = lp_info;
+ int value = 0;
+ sscanf(buf, "0x%x", &value);
+
+ lpi->ls_cmd = value;
+ printk(KERN_INFO "[LS]set ALS_CONF = %x\n", lpi->ls_cmd);
+
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+ return count;
+}
+static DEVICE_ATTR(ls_conf, 0664, ls_conf_show, ls_conf_store);
+
+static ssize_t ls_fLevel_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "fLevel = %d\n", fLevel);
+}
+static ssize_t ls_fLevel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cm36283_info *lpi = lp_info;
+ int value=0;
+ sscanf(buf, "%d", &value);
+ (value>=0)?(value=min(value,10)):(value=max(value,-1));
+ fLevel=value;
+ input_report_abs(lpi->ls_input_dev, ABS_MISC, fLevel);
+ input_sync(lpi->ls_input_dev);
+ printk(KERN_INFO "[LS]set fLevel = %d\n", fLevel);
+
+ msleep(1000);
+ fLevel=-1;
+ return count;
+}
+static DEVICE_ATTR(ls_flevel, 0664, ls_fLevel_show, ls_fLevel_store);
+
+static int lightsensor_setup(struct cm36283_info *lpi)
+{
+ int ret;
+
+ lpi->ls_input_dev = input_allocate_device();
+ if (!lpi->ls_input_dev) {
+ pr_err(
+ "[LS][CM36283 error]%s: could not allocate ls input device\n",
+ __func__);
+ return -ENOMEM;
+ }
+ lpi->ls_input_dev->name = "cm36283-ls";
+ set_bit(EV_ABS, lpi->ls_input_dev->evbit);
+ input_set_abs_params(lpi->ls_input_dev, ABS_MISC, 0, 9, 0, 0);
+
+ ret = input_register_device(lpi->ls_input_dev);
+ if (ret < 0) {
+ pr_err("[LS][CM36283 error]%s: can not register ls input device\n",
+ __func__);
+ goto err_free_ls_input_device;
+ }
+
+ ret = misc_register(&lightsensor_misc);
+ if (ret < 0) {
+ pr_err("[LS][CM36283 error]%s: can not register ls misc device\n",
+ __func__);
+ goto err_unregister_ls_input_device;
+ }
+
+ return ret;
+
+err_unregister_ls_input_device:
+ input_unregister_device(lpi->ls_input_dev);
+err_free_ls_input_device:
+ input_free_device(lpi->ls_input_dev);
+ return ret;
+}
+
+static int psensor_setup(struct cm36283_info *lpi)
+{
+ int ret;
+
+ lpi->ps_input_dev = input_allocate_device();
+ if (!lpi->ps_input_dev) {
+ pr_err(
+ "[PS][CM36283 error]%s: could not allocate ps input device\n",
+ __func__);
+ return -ENOMEM;
+ }
+ lpi->ps_input_dev->name = "cm36283-ps";
+ set_bit(EV_ABS, lpi->ps_input_dev->evbit);
+ input_set_abs_params(lpi->ps_input_dev, ABS_DISTANCE, 0, 1, 0, 0);
+
+ ret = input_register_device(lpi->ps_input_dev);
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: could not register ps input device\n",
+ __func__);
+ goto err_free_ps_input_device;
+ }
+
+ ret = misc_register(&psensor_misc);
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: could not register ps misc device\n",
+ __func__);
+ goto err_unregister_ps_input_device;
+ }
+
+ return ret;
+
+err_unregister_ps_input_device:
+ input_unregister_device(lpi->ps_input_dev);
+err_free_ps_input_device:
+ input_free_device(lpi->ps_input_dev);
+ return ret;
+}
+
+
+static int initial_cm36283(struct cm36283_info *lpi)
+{
+ int val, ret;
+ uint16_t idReg;
+
+ val = gpio_get_value(lpi->intr_pin);
+ D("[PS][CM36283] %s, INTERRUPT GPIO val = %d\n", __func__, val);
+
+ ret = _cm36283_I2C_Read_Word(lpi->slave_addr, ID_REG, &idReg);
+ if ((ret < 0) || (idReg != 0xC082)) {
+ if (record_init_fail == 0)
+ record_init_fail = 1;
+ return -ENOMEM;/*If devices without cm36283 chip and did not probe driver*/
+ }
+
+ return 0;
+}
+
+static int cm36283_setup(struct cm36283_info *lpi)
+{
+ int ret = 0;
+
+ als_power(1);
+ msleep(5);
+ ret = gpio_request(lpi->intr_pin, "gpio_cm36283_intr");
+ if (ret < 0) {
+ pr_err("[PS][CM36283 error]%s: gpio %d request failed (%d)\n",
+ __func__, lpi->intr_pin, ret);
+ return ret;
+ }
+
+ ret = gpio_direction_input(lpi->intr_pin);
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: fail to set gpio %d as input (%d)\n",
+ __func__, lpi->intr_pin, ret);
+ goto fail_free_intr_pin;
+ }
+
+
+ ret = initial_cm36283(lpi);
+ if (ret < 0) {
+ pr_err(
+ "[PS_ERR][CM36283 error]%s: fail to initial cm36283 (%d)\n",
+ __func__, ret);
+ goto fail_free_intr_pin;
+ }
+
+ /*Default disable P sensor and L sensor*/
+ ls_initial_cmd(lpi);
+ psensor_initial_cmd(lpi);
+
+ ret = request_any_context_irq(lpi->irq,
+ cm36283_irq_handler,
+ IRQF_TRIGGER_LOW,
+ "cm36283",
+ lpi);
+ if (ret < 0) {
+ pr_err(
+ "[PS][CM36283 error]%s: req_irq(%d) fail for gpio %d (%d)\n",
+ __func__, lpi->irq,
+ lpi->intr_pin, ret);
+ goto fail_free_intr_pin;
+ }
+
+ return ret;
+
+fail_free_intr_pin:
+ gpio_free(lpi->intr_pin);
+ return ret;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void cm36283_early_suspend(struct early_suspend *h)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[LS][CM36283] %s\n", __func__);
+
+ if (lpi->als_enable)
+ lightsensor_disable(lpi);
+
+}
+
+static void cm36283_late_resume(struct early_suspend *h)
+{
+ struct cm36283_info *lpi = lp_info;
+
+ D("[LS][CM36283] %s\n", __func__);
+
+ if (!lpi->als_enable)
+ lightsensor_enable(lpi);
+}
+#endif
+
+static int cm36283_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct cm36283_info *lpi;
+ struct cm36283_platform_data *pdata;
+
+ D("[PS][CM36283] %s\n", __func__);
+
+
+ lpi = kzalloc(sizeof(struct cm36283_info), GFP_KERNEL);
+ if (!lpi)
+ return -ENOMEM;
+
+ /*D("[CM36283] %s: client->irq = %d\n", __func__, client->irq);*/
+
+ lpi->i2c_client = client;
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ pr_err("[PS][CM36283 error]%s: Assign platform_data error!!\n",
+ __func__);
+ ret = -EBUSY;
+ goto err_platform_data_null;
+ }
+
+ lpi->irq = client->irq;
+
+ i2c_set_clientdata(client, lpi);
+
+ lpi->intr_pin = pdata->intr;
+ lpi->adc_table = pdata->levels;
+ lpi->power = pdata->power;
+
+ lpi->slave_addr = pdata->slave_addr;
+
+ lpi->ps_away_thd_set = pdata->ps_away_thd_set;
+ lpi->ps_close_thd_set = pdata->ps_close_thd_set;
+ lpi->ps_conf1_val = pdata->ps_conf1_val;
+ lpi->ps_conf3_val = pdata->ps_conf3_val;
+
+ lpi->ls_cmd = pdata->ls_cmd;
+
+ lpi->record_clear_int_fail=0;
+
+ D("[PS][CM36283] %s: ls_cmd 0x%x\n",
+ __func__, lpi->ls_cmd);
+
+ if (pdata->ls_cmd == 0) {
+ lpi->ls_cmd = CM36283_ALS_IT_160ms | CM36283_ALS_GAIN_2;
+ }
+
+ lp_info = lpi;
+
+ mutex_init(&CM36283_control_mutex);
+
+ mutex_init(&als_enable_mutex);
+ mutex_init(&als_disable_mutex);
+ mutex_init(&als_get_adc_mutex);
+
+ ret = lightsensor_setup(lpi);
+ if (ret < 0) {
+ pr_err("[LS][CM36283 error]%s: lightsensor_setup error!!\n",
+ __func__);
+ goto err_lightsensor_setup;
+ }
+
+ mutex_init(&ps_enable_mutex);
+ mutex_init(&ps_disable_mutex);
+ mutex_init(&ps_get_adc_mutex);
+
+ ret = psensor_setup(lpi);
+ if (ret < 0) {
+ pr_err("[PS][CM36283 error]%s: psensor_setup error!!\n",
+ __func__);
+ goto err_psensor_setup;
+ }
+
+ //SET LUX STEP FACTOR HERE
+ // if adc raw value one step = 5/100 = 1/20 = 0.05 lux
+ // the following will set the factor 0.05 = 1/20
+ // and lpi->golden_adc = 1;
+ // set als_kadc = (ALS_CALIBRATED <<16) | 20;
+
+ als_kadc = (ALS_CALIBRATED <<16) | 20;
+ lpi->golden_adc = 1;
+
+ //ls calibrate always set to 1
+ lpi->ls_calibrate = 1;
+
+ lightsensor_set_kvalue(lpi);
+ ret = lightsensor_update_table(lpi);
+ if (ret < 0) {
+ pr_err("[LS][CM36283 error]%s: update ls table fail\n",
+ __func__);
+ goto err_lightsensor_update_table;
+ }
+
+ lpi->lp_wq = create_singlethread_workqueue("cm36283_wq");
+ if (!lpi->lp_wq) {
+ pr_err("[PS][CM36283 error]%s: can't create workqueue\n", __func__);
+ ret = -ENOMEM;
+ goto err_create_singlethread_workqueue;
+ }
+ wake_lock_init(&(lpi->ps_wake_lock), WAKE_LOCK_SUSPEND, "proximity");
+
+ ret = cm36283_setup(lpi);
+ if (ret < 0) {
+ pr_err("[PS_ERR][CM36283 error]%s: cm36283_setup error!\n", __func__);
+ goto err_cm36283_setup;
+ }
+ lpi->cm36283_class = class_create(THIS_MODULE, "optical_sensors");
+ if (IS_ERR(lpi->cm36283_class)) {
+ ret = PTR_ERR(lpi->cm36283_class);
+ lpi->cm36283_class = NULL;
+ goto err_create_class;
+ }
+
+ lpi->ls_dev = device_create(lpi->cm36283_class,
+ NULL, 0, "%s", "lightsensor");
+ if (unlikely(IS_ERR(lpi->ls_dev))) {
+ ret = PTR_ERR(lpi->ls_dev);
+ lpi->ls_dev = NULL;
+ goto err_create_ls_device;
+ }
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_auto);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_kadc);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_gadc);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_adc_table);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_conf);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ ret = device_create_file(lpi->ls_dev, &dev_attr_ls_flevel);
+ if (ret)
+ goto err_create_ls_device_file;
+
+ lpi->ps_dev = device_create(lpi->cm36283_class,
+ NULL, 0, "%s", "proximity");
+ if (unlikely(IS_ERR(lpi->ps_dev))) {
+ ret = PTR_ERR(lpi->ps_dev);
+ lpi->ps_dev = NULL;
+ goto err_create_ls_device_file;
+ }
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ps_dev, &dev_attr_ps_adc);
+ if (ret)
+ goto err_create_ps_device;
+
+ ret = device_create_file(lpi->ps_dev,
+ &dev_attr_ps_parameters);
+ if (ret)
+ goto err_create_ps_device;
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ps_dev, &dev_attr_ps_conf);
+ if (ret)
+ goto err_create_ps_device;
+
+ /* register the attributes */
+ ret = device_create_file(lpi->ps_dev, &dev_attr_ps_thd);
+ if (ret)
+ goto err_create_ps_device;
+
+ ret = device_create_file(lpi->ps_dev, &dev_attr_ps_hw);
+ if (ret)
+ goto err_create_ps_device;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ lpi->early_suspend.level =
+ EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ lpi->early_suspend.suspend = cm36283_early_suspend;
+ lpi->early_suspend.resume = cm36283_late_resume;
+ register_early_suspend(&lpi->early_suspend);
+#endif
+
+ D("[PS][CM36283] %s: Probe success!\n", __func__);
+
+ return ret;
+
+err_create_ps_device:
+ device_unregister(lpi->ps_dev);
+err_create_ls_device_file:
+ device_unregister(lpi->ls_dev);
+err_create_ls_device:
+ class_destroy(lpi->cm36283_class);
+err_create_class:
+err_cm36283_setup:
+ destroy_workqueue(lpi->lp_wq);
+ wake_lock_destroy(&(lpi->ps_wake_lock));
+
+ input_unregister_device(lpi->ls_input_dev);
+ input_free_device(lpi->ls_input_dev);
+ input_unregister_device(lpi->ps_input_dev);
+ input_free_device(lpi->ps_input_dev);
+err_create_singlethread_workqueue:
+err_lightsensor_update_table:
+ misc_deregister(&psensor_misc);
+err_psensor_setup:
+ mutex_destroy(&CM36283_control_mutex);
+ mutex_destroy(&ps_enable_mutex);
+ mutex_destroy(&ps_disable_mutex);
+ mutex_destroy(&ps_get_adc_mutex);
+ misc_deregister(&lightsensor_misc);
+err_lightsensor_setup:
+ mutex_destroy(&als_enable_mutex);
+ mutex_destroy(&als_disable_mutex);
+ mutex_destroy(&als_get_adc_mutex);
+err_platform_data_null:
+ kfree(lpi);
+ return ret;
+}
+
+static int control_and_report( struct cm36283_info *lpi, uint8_t mode, uint16_t param ) {
+ int ret=0;
+ uint16_t adc_value = 0;
+ uint16_t ps_data = 0;
+ int level = 0, i, val;
+
+ mutex_lock(&CM36283_control_mutex);
+
+ if( mode == CONTROL_ALS ){
+ if(param){
+ lpi->ls_cmd &= CM36283_ALS_SD_MASK;
+ } else {
+ lpi->ls_cmd |= CM36283_ALS_SD;
+ }
+ _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+ lpi->als_enable=param;
+ } else if( mode == CONTROL_PS ){
+ if(param){
+ lpi->ps_conf1_val &= CM36283_PS_SD_MASK;
+ lpi->ps_conf1_val |= CM36283_PS_INT_IN_AND_OUT;
+ } else {
+ lpi->ps_conf1_val |= CM36283_PS_SD;
+ lpi->ps_conf1_val &= CM36283_PS_INT_MASK;
+ }
+ _cm36283_I2C_Write_Word(lpi->slave_addr, PS_CONF1, lpi->ps_conf1_val);
+ lpi->ps_enable=param;
+ }
+ if((mode == CONTROL_ALS)||(mode == CONTROL_PS)){
+ if( param==1 ){
+ msleep(100);
+ }
+ }
+
+ if(lpi->als_enable){
+ if( mode == CONTROL_ALS ||
+ ( mode == CONTROL_INT_ISR_REPORT &&
+ ((param&INT_FLAG_ALS_IF_L)||(param&INT_FLAG_ALS_IF_H)))){
+
+ lpi->ls_cmd &= CM36283_ALS_INT_MASK;
+ ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+
+ get_ls_adc_value(&adc_value, 0);
+
+ if( lpi->ls_calibrate ) {
+ for (i = 0; i < 10; i++) {
+ if (adc_value <= (*(lpi->cali_table + i))) {
+ level = i;
+ if (*(lpi->cali_table + i))
+ break;
+ }
+ if ( i == 9) {/*avoid i = 10, because 'cali_table' of size is 10 */
+ level = i;
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < 10; i++) {
+ if (adc_value <= (*(lpi->adc_table + i))) {
+ level = i;
+ if (*(lpi->adc_table + i))
+ break;
+ }
+ if ( i == 9) {/*avoid i = 10, because 'cali_table' of size is 10 */
+ level = i;
+ break;
+ }
+ }
+ }
+
+ ret = set_lsensor_range(((i == 0) || (adc_value == 0)) ? 0 :
+ *(lpi->cali_table + (i - 1)) + 1,
+ *(lpi->cali_table + i));
+
+ lpi->ls_cmd |= CM36283_ALS_INT_EN;
+
+ ret = _cm36283_I2C_Write_Word(lpi->slave_addr, ALS_CONF, lpi->ls_cmd);
+
+ if ((i == 0) || (adc_value == 0))
+ D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd equal 0, h_thd = 0x%x \n",
+ __func__, adc_value, level, *(lpi->cali_table + i));
+ else
+ D("[LS][CM3628] %s: ADC=0x%03X, Level=%d, l_thd = 0x%x, h_thd = 0x%x \n",
+ __func__, adc_value, level, *(lpi->cali_table + (i - 1)) + 1, *(lpi->cali_table + i));
+ lpi->current_level = level;
+ lpi->current_adc = adc_value;
+ input_report_abs(lpi->ls_input_dev, ABS_MISC, level);
+ input_sync(lpi->ls_input_dev);
+ }
+ }
+
+#define PS_CLOSE 1
+#define PS_AWAY (1<<1)
+#define PS_CLOSE_AND_AWAY PS_CLOSE+PS_AWAY
+
+ if(lpi->ps_enable){
+ int ps_status = 0;
+ if( mode == CONTROL_PS )
+ ps_status = PS_CLOSE_AND_AWAY;
+ else if(mode == CONTROL_INT_ISR_REPORT ){
+ if ( param & INT_FLAG_PS_IF_CLOSE )
+ ps_status |= PS_CLOSE;
+ if ( param & INT_FLAG_PS_IF_AWAY )
+ ps_status |= PS_AWAY;
+ }
+
+ if (ps_status!=0){
+ switch(ps_status){
+ case PS_CLOSE_AND_AWAY:
+ get_stable_ps_adc_value(&ps_data);
+ val = (ps_data >= lpi->ps_close_thd_set) ? 0 : 1;
+ break;
+ case PS_AWAY:
+ val = 1;
+ break;
+ case PS_CLOSE:
+ val = 0;
+ break;
+ };
+ input_report_abs(lpi->ps_input_dev, ABS_DISTANCE, val);
+ input_sync(lpi->ps_input_dev);
+ }
+ }
+
+ mutex_unlock(&CM36283_control_mutex);
+ return ret;
+}
+
+
+static const struct i2c_device_id cm36283_i2c_id[] = {
+ {CM36283_I2C_NAME, 0},
+ {}
+};
+
+static struct i2c_driver cm36283_driver = {
+ .id_table = cm36283_i2c_id,
+ .probe = cm36283_probe,
+ .driver = {
+ .name = CM36283_I2C_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cm36283_init(void)
+{
+ return i2c_add_driver(&cm36283_driver);
+}
+
+static void __exit cm36283_exit(void)
+{
+ i2c_del_driver(&cm36283_driver);
+}
+
+module_init(cm36283_init);
+module_exit(cm36283_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CM36283 Driver");
+MODULE_AUTHOR("Frank Hsieh <pengyueh@gmail.com>");
diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c
new file mode 100644
index 0000000..eee9a28
--- /dev/null
+++ b/drivers/input/misc/stk3x1x.c
@@ -0,0 +1,2020 @@
+/*
+ * stk3x1x.c - Linux kernel modules for sensortek stk301x, stk321x and stk331x
+ * proximity/ambient light sensor
+ *
+ * Copyright (C) 2012 Lex Hsieh / sensortek <lex_hsieh@sitronix.com.tw> or
+ * <lex_hsieh@sensortek.com.tw>
+ *
+ * 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/errno.h>
+#include <linux/wakelock.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include "linux/stk3x1x.h"
+
+#define DRIVER_VERSION "3.4.4ts"
+
+/* Driver Settings */
+#define CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+#ifdef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+#define STK_ALS_CHANGE_THD 20 /* The threshold to trigger ALS interrupt, unit: lux */
+#endif /* #ifdef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD */
+#define STK_INT_PS_MODE 1 /* 1, 2, or 3 */
+#define STK_POLL_PS
+#define STK_POLL_ALS /* ALS interrupt is valid only when STK_PS_INT_MODE = 1 or 4*/
+
+#define STK_DEBUG_PRINTF
+
+/* Define Register Map */
+#define STK_STATE_REG 0x00
+#define STK_PSCTRL_REG 0x01
+#define STK_ALSCTRL_REG 0x02
+#define STK_LEDCTRL_REG 0x03
+#define STK_INT_REG 0x04
+#define STK_WAIT_REG 0x05
+#define STK_THDH1_PS_REG 0x06
+#define STK_THDH2_PS_REG 0x07
+#define STK_THDL1_PS_REG 0x08
+#define STK_THDL2_PS_REG 0x09
+#define STK_THDH1_ALS_REG 0x0A
+#define STK_THDH2_ALS_REG 0x0B
+#define STK_THDL1_ALS_REG 0x0C
+#define STK_THDL2_ALS_REG 0x0D
+#define STK_FLAG_REG 0x10
+#define STK_DATA1_PS_REG 0x11
+#define STK_DATA2_PS_REG 0x12
+#define STK_DATA1_ALS_REG 0x13
+#define STK_DATA2_ALS_REG 0x14
+#define STK_DATA1_OFFSET_REG 0x15
+#define STK_DATA2_OFFSET_REG 0x16
+#define STK_DATA1_IR_REG 0x17
+#define STK_DATA2_IR_REG 0x18
+#define STK_PDT_ID_REG 0x3E
+#define STK_RSRVD_REG 0x3F
+#define STK_SW_RESET_REG 0x80
+
+
+/* Define state reg */
+#define STK_STATE_EN_IRS_SHIFT 7
+#define STK_STATE_EN_AK_SHIFT 6
+#define STK_STATE_EN_ASO_SHIFT 5
+#define STK_STATE_EN_IRO_SHIFT 4
+#define STK_STATE_EN_WAIT_SHIFT 2
+#define STK_STATE_EN_ALS_SHIFT 1
+#define STK_STATE_EN_PS_SHIFT 0
+
+#define STK_STATE_EN_IRS_MASK 0x80
+#define STK_STATE_EN_AK_MASK 0x40
+#define STK_STATE_EN_ASO_MASK 0x20
+#define STK_STATE_EN_IRO_MASK 0x10
+#define STK_STATE_EN_WAIT_MASK 0x04
+#define STK_STATE_EN_ALS_MASK 0x02
+#define STK_STATE_EN_PS_MASK 0x01
+
+/* Define PS ctrl reg */
+#define STK_PS_PRS_SHIFT 6
+#define STK_PS_GAIN_SHIFT 4
+#define STK_PS_IT_SHIFT 0
+
+#define STK_PS_PRS_MASK 0xC0
+#define STK_PS_GAIN_MASK 0x30
+#define STK_PS_IT_MASK 0x0F
+
+/* Define ALS ctrl reg */
+#define STK_ALS_PRS_SHIFT 6
+#define STK_ALS_GAIN_SHIFT 4
+#define STK_ALS_IT_SHIFT 0
+
+#define STK_ALS_PRS_MASK 0xC0
+#define STK_ALS_GAIN_MASK 0x30
+#define STK_ALS_IT_MASK 0x0F
+
+/* Define LED ctrl reg */
+#define STK_LED_IRDR_SHIFT 6
+#define STK_LED_DT_SHIFT 0
+
+#define STK_LED_IRDR_MASK 0xC0
+#define STK_LED_DT_MASK 0x3F
+
+/* Define interrupt reg */
+#define STK_INT_CTRL_SHIFT 7
+#define STK_INT_OUI_SHIFT 4
+#define STK_INT_ALS_SHIFT 3
+#define STK_INT_PS_SHIFT 0
+
+#define STK_INT_CTRL_MASK 0x80
+#define STK_INT_OUI_MASK 0x10
+#define STK_INT_ALS_MASK 0x08
+#define STK_INT_PS_MASK 0x07
+
+#define STK_INT_ALS 0x08
+
+/* Define flag reg */
+#define STK_FLG_ALSDR_SHIFT 7
+#define STK_FLG_PSDR_SHIFT 6
+#define STK_FLG_ALSINT_SHIFT 5
+#define STK_FLG_PSINT_SHIFT 4
+#define STK_FLG_OUI_SHIFT 2
+#define STK_FLG_IR_RDY_SHIFT 1
+#define STK_FLG_NF_SHIFT 0
+
+#define STK_FLG_ALSDR_MASK 0x80
+#define STK_FLG_PSDR_MASK 0x40
+#define STK_FLG_ALSINT_MASK 0x20
+#define STK_FLG_PSINT_MASK 0x10
+#define STK_FLG_OUI_MASK 0x04
+#define STK_FLG_IR_RDY_MASK 0x02
+#define STK_FLG_NF_MASK 0x01
+
+/* misc define */
+#define MIN_ALS_POLL_DELAY_NS 110000000
+
+#define DEVICE_NAME "stk_ps"
+#define ALS_NAME "lightsensor-level"
+#define PS_NAME "proximity"
+
+struct stk3x1x_data {
+ struct i2c_client *client;
+#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
+ int32_t irq;
+ struct work_struct stk_work;
+ struct workqueue_struct *stk_wq;
+#endif
+ int int_pin;
+ uint8_t wait_reg;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend stk_early_suspend;
+#endif
+ uint16_t ps_thd_h;
+ uint16_t ps_thd_l;
+ struct mutex io_lock;
+ struct input_dev *ps_input_dev;
+ int32_t ps_distance_last;
+ bool ps_enabled;
+ struct wake_lock ps_wakelock;
+ struct work_struct stk_ps_work;
+ struct workqueue_struct *stk_ps_wq;
+#ifdef STK_POLL_PS
+ struct wake_lock ps_nosuspend_wl;
+#endif
+ struct input_dev *als_input_dev;
+ int32_t als_lux_last;
+ uint32_t als_transmittance;
+ bool als_enabled;
+ struct hrtimer als_timer;
+ struct hrtimer ps_timer;
+ ktime_t als_poll_delay;
+ ktime_t ps_poll_delay;
+#ifdef STK_POLL_ALS
+ struct work_struct stk_als_work;
+ struct workqueue_struct *stk_als_wq;
+#endif
+};
+
+#if( !defined(CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD))
+static uint32_t lux_threshold_table[] =
+{
+ 3,
+ 10,
+ 40,
+ 65,
+ 145,
+ 300,
+ 550,
+ 930,
+ 1250,
+ 1700,
+};
+
+#define LUX_THD_TABLE_SIZE (sizeof(lux_threshold_table)/sizeof(uint32_t)+1)
+static uint16_t code_threshold_table[LUX_THD_TABLE_SIZE+1];
+#endif
+
+static int32_t stk3x1x_enable_ps(struct stk3x1x_data *ps_data, uint8_t enable);
+static int32_t stk3x1x_enable_als(struct stk3x1x_data *ps_data, uint8_t enable);
+static int32_t stk3x1x_set_ps_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l);
+static int32_t stk3x1x_set_ps_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h);
+static int32_t stk3x1x_set_als_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l);
+static int32_t stk3x1x_set_als_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h);
+//static int32_t stk3x1x_set_ps_aoffset(struct stk3x1x_data *ps_data, uint16_t offset);
+
+inline uint32_t stk_alscode2lux(struct stk3x1x_data *ps_data, uint32_t alscode)
+{
+ alscode += ((alscode<<7)+(alscode<<3)+(alscode>>1));
+ alscode<<=3;
+ alscode/=ps_data->als_transmittance;
+ return alscode;
+}
+
+inline uint32_t stk_lux2alscode(struct stk3x1x_data *ps_data, uint32_t lux)
+{
+ lux*=ps_data->als_transmittance;
+ lux/=1100;
+ if (unlikely(lux>=(1<<16)))
+ lux = (1<<16) -1;
+ return lux;
+}
+
+#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+static void stk_init_code_threshold_table(struct stk3x1x_data *ps_data)
+{
+ uint32_t i,j;
+ uint32_t alscode;
+
+ code_threshold_table[0] = 0;
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "alscode[0]=%d\n",0);
+#endif
+ for (i=1,j=0;i<LUX_THD_TABLE_SIZE;i++,j++)
+ {
+ alscode = stk_lux2alscode(ps_data, lux_threshold_table[j]);
+ printk(KERN_INFO "alscode[%d]=%d\n",i,alscode);
+ code_threshold_table[i] = (uint16_t)(alscode);
+ }
+ code_threshold_table[i] = 0xffff;
+ printk(KERN_INFO "alscode[%d]=%d\n",i,alscode);
+}
+
+static uint32_t stk_get_lux_interval_index(uint16_t alscode)
+{
+ uint32_t i;
+ for (i=1;i<=LUX_THD_TABLE_SIZE;i++)
+ {
+ if ((alscode>=code_threshold_table[i-1])&&(alscode<code_threshold_table[i]))
+ {
+ return i;
+ }
+ }
+ return LUX_THD_TABLE_SIZE;
+}
+#else
+inline void stk_als_set_new_thd(struct stk3x1x_data *ps_data, uint16_t alscode)
+{
+ int32_t high_thd,low_thd;
+ high_thd = alscode + stk_lux2alscode(ps_data, STK_ALS_CHANGE_THD);
+ low_thd = alscode - stk_lux2alscode(ps_data, STK_ALS_CHANGE_THD);
+ if (high_thd >= (1<<16))
+ high_thd = (1<<16) -1;
+ if (low_thd <0)
+ low_thd = 0;
+ stk3x1x_set_als_thd_h(ps_data, (uint16_t)high_thd);
+ stk3x1x_set_als_thd_l(ps_data, (uint16_t)low_thd);
+}
+#endif // CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+
+
+static int32_t stk3x1x_init_all_reg(struct stk3x1x_data *ps_data, struct stk3x1x_platform_data *plat_data)
+{
+ int32_t ret;
+ uint8_t w_reg;
+
+ w_reg = plat_data->state_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ ps_data->ps_thd_h = plat_data->ps_thd_h;
+ ps_data->ps_thd_l = plat_data->ps_thd_l;
+
+ w_reg = plat_data->psctrl_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_PSCTRL_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_reg = plat_data->alsctrl_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_ALSCTRL_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_reg = plat_data->ledctrl_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_LEDCTRL_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ ps_data->wait_reg = plat_data->wait_reg;
+
+ if(ps_data->wait_reg < 2)
+ {
+ printk(KERN_WARNING "%s: wait_reg should be larger than 2, force to write 2\n", __func__);
+ ps_data->wait_reg = 2;
+ }
+ else if (ps_data->wait_reg > 0xFF)
+ {
+ printk(KERN_WARNING "%s: wait_reg should be less than 0xFF, force to write 0xFF\n", __func__);
+ ps_data->wait_reg = 0xFF;
+ }
+ w_reg = plat_data->wait_reg;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_WAIT_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ stk3x1x_set_ps_thd_h(ps_data, ps_data->ps_thd_h);
+ stk3x1x_set_ps_thd_l(ps_data, ps_data->ps_thd_l);
+
+ w_reg = 0;
+#ifndef STK_POLL_PS
+ w_reg |= STK_INT_PS_MODE;
+#else
+ w_reg |= 0x01;
+#endif
+
+#if (!defined(STK_POLL_ALS) && (STK_INT_PS_MODE != 0x02) && (STK_INT_PS_MODE != 0x03))
+ w_reg |= STK_INT_ALS;
+#endif
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_INT_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ return 0;
+}
+
+static int32_t stk3x1x_check_pid(struct stk3x1x_data *ps_data)
+{
+ int32_t err1, err2;
+
+ err1 = i2c_smbus_read_byte_data(ps_data->client,STK_PDT_ID_REG);
+ if (err1 < 0)
+ {
+ printk(KERN_ERR "%s: read i2c error, err=%d\n", __func__, err1);
+ return err1;
+ }
+
+ err2 = i2c_smbus_read_byte_data(ps_data->client,STK_RSRVD_REG);
+ if (err2 < 0)
+ {
+ printk(KERN_ERR "%s: read i2c error, err=%d\n", __func__, err2);
+ return -1;
+ }
+ printk(KERN_INFO "%s: PID=0x%x, RID=0x%x\n", __func__, err1, err2);
+ if(err2 == 0xC0)
+ printk(KERN_INFO "%s: RID=0xC0!!!!!!!!!!!!!\n", __func__);
+
+ return 0;
+}
+
+
+static int32_t stk3x1x_software_reset(struct stk3x1x_data *ps_data)
+{
+ int32_t r;
+ uint8_t w_reg;
+
+ w_reg = 0x7F;
+ r = i2c_smbus_write_byte_data(ps_data->client,STK_WAIT_REG,w_reg);
+ if (r<0)
+ {
+ printk(KERN_ERR "%s: software reset: write i2c error, ret=%d\n", __func__, r);
+ return r;
+ }
+ r = i2c_smbus_read_byte_data(ps_data->client,STK_WAIT_REG);
+ if (w_reg != r)
+ {
+ printk(KERN_ERR "%s: software reset: read-back value is not the same\n", __func__);
+ return -1;
+ }
+
+ r = i2c_smbus_write_byte_data(ps_data->client,STK_SW_RESET_REG,0);
+ if (r<0)
+ {
+ printk(KERN_ERR "%s: software reset: read error after reset\n", __func__);
+ return r;
+ }
+ msleep(1);
+ return 0;
+}
+
+
+static int32_t stk3x1x_set_als_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&thd_l;
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ return i2c_smbus_write_word_data(ps_data->client,STK_THDL1_ALS_REG,thd_l);
+}
+static int32_t stk3x1x_set_als_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&thd_h;
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ return i2c_smbus_write_word_data(ps_data->client,STK_THDH1_ALS_REG,thd_h);
+}
+
+static int32_t stk3x1x_set_ps_thd_l(struct stk3x1x_data *ps_data, uint16_t thd_l)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&thd_l;
+
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ ps_data->ps_thd_l = thd_l;
+ return i2c_smbus_write_word_data(ps_data->client,STK_THDL1_PS_REG,thd_l);
+}
+
+static int32_t stk3x1x_set_ps_thd_h(struct stk3x1x_data *ps_data, uint16_t thd_h)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&thd_h;
+
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ ps_data->ps_thd_h = thd_h;
+ return i2c_smbus_write_word_data(ps_data->client,STK_THDH1_PS_REG,thd_h);
+}
+
+/*
+static int32_t stk3x1x_set_ps_foffset(struct stk3x1x_data *ps_data, uint16_t offset)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&offset;
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ return i2c_smbus_write_word_data(ps_data->client,STK_DATA1_OFFSET_REG,offset);
+}
+
+static int32_t stk3x1x_set_ps_aoffset(struct stk3x1x_data *ps_data, uint16_t offset)
+{
+ uint8_t temp;
+ uint8_t* pSrc = (uint8_t*)&offset;
+ int ret;
+ uint8_t w_state_reg;
+ uint8_t re_en;
+
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ re_en = (ret & STK_STATE_EN_AK_MASK) ? 1: 0;
+ if(re_en)
+ {
+ w_state_reg = (uint8_t)(ret & (~STK_STATE_EN_AK_MASK));
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ msleep(1);
+ }
+ temp = *pSrc;
+ *pSrc = *(pSrc+1);
+ *(pSrc+1) = temp;
+ ret = i2c_smbus_write_word_data(ps_data->client,0x0E,offset);
+ if(!re_en)
+ return ret;
+
+ w_state_reg |= STK_STATE_EN_AK_MASK;
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+*/
+
+static inline uint32_t stk3x1x_get_ps_reading(struct stk3x1x_data *ps_data)
+{
+ int32_t word_data, tmp_word_data;
+
+ tmp_word_data = i2c_smbus_read_word_data(ps_data->client,STK_DATA1_PS_REG);
+ if(tmp_word_data < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data);
+ return tmp_word_data;
+ }
+ word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ;
+ return word_data;
+}
+
+static int32_t stk3x1x_set_flag(struct stk3x1x_data *ps_data, uint8_t org_flag_reg, uint8_t clr)
+{
+ uint8_t w_flag;
+ w_flag = org_flag_reg | (STK_FLG_ALSINT_MASK | STK_FLG_PSINT_MASK | STK_FLG_OUI_MASK | STK_FLG_IR_RDY_MASK);
+ w_flag &= (~clr);
+ //printk(KERN_INFO "%s: org_flag_reg=0x%x, w_flag = 0x%x\n", __func__, org_flag_reg, w_flag);
+ return i2c_smbus_write_byte_data(ps_data->client,STK_FLAG_REG, w_flag);
+}
+
+static int32_t stk3x1x_get_flag(struct stk3x1x_data *ps_data)
+{
+ return i2c_smbus_read_byte_data(ps_data->client,STK_FLAG_REG);
+}
+
+static int32_t stk3x1x_enable_ps(struct stk3x1x_data *ps_data, uint8_t enable)
+{
+ int32_t ret;
+ uint8_t w_state_reg;
+ uint8_t curr_ps_enable;
+ curr_ps_enable = ps_data->ps_enabled?1:0;
+ if(curr_ps_enable == enable)
+ return 0;
+
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error, ret=%d\n", __func__, ret);
+ return ret;
+ }
+ w_state_reg = ret;
+ w_state_reg &= ~(STK_STATE_EN_PS_MASK | STK_STATE_EN_WAIT_MASK | 0x60);
+ if(enable)
+ {
+ w_state_reg |= STK_STATE_EN_PS_MASK;
+ if(!(ps_data->als_enabled))
+ w_state_reg |= STK_STATE_EN_WAIT_MASK;
+ }
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error, ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ if(enable)
+ {
+#ifdef STK_POLL_PS
+ hrtimer_start(&ps_data->ps_timer, ps_data->ps_poll_delay, HRTIMER_MODE_REL);
+ ps_data->ps_distance_last = -1;
+#endif
+ ps_data->ps_enabled = true;
+#ifndef STK_POLL_PS
+#ifndef STK_POLL_ALS
+ if(!(ps_data->als_enabled))
+#endif /* #ifndef STK_POLL_ALS */
+ enable_irq(ps_data->irq);
+ msleep(1);
+ ret = stk3x1x_get_flag(ps_data);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: read i2c error, ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ near_far_state = ret & STK_FLG_NF_MASK;
+ ps_data->ps_distance_last = near_far_state;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state);
+ input_sync(ps_data->ps_input_dev);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ reading = stk3x1x_get_ps_reading(ps_data);
+ printk(KERN_INFO "%s: ps input event=%d, ps code = %d\n",__func__, near_far_state, reading);
+#endif /* #ifndef STK_POLL_PS */
+ }
+ else
+ {
+#ifdef STK_POLL_PS
+ hrtimer_cancel(&ps_data->ps_timer);
+#else
+#ifndef STK_POLL_ALS
+ if(!(ps_data->als_enabled))
+#endif
+ disable_irq(ps_data->irq);
+#endif
+ ps_data->ps_enabled = false;
+ }
+ return ret;
+}
+
+static int32_t stk3x1x_enable_als(struct stk3x1x_data *ps_data, uint8_t enable)
+{
+ int32_t ret;
+ uint8_t w_state_reg;
+ uint8_t curr_als_enable = (ps_data->als_enabled)?1:0;
+
+ if(curr_als_enable == enable)
+ return 0;
+
+#ifndef STK_POLL_ALS
+ if (enable)
+ {
+ stk3x1x_set_als_thd_h(ps_data, 0x0000);
+ stk3x1x_set_als_thd_l(ps_data, 0xFFFF);
+ }
+#endif
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_state_reg = (uint8_t)(ret & (~(STK_STATE_EN_ALS_MASK | STK_STATE_EN_WAIT_MASK)));
+ if(enable)
+ w_state_reg |= STK_STATE_EN_ALS_MASK;
+ else if (ps_data->ps_enabled)
+ w_state_reg |= STK_STATE_EN_WAIT_MASK;
+
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ if (enable)
+ {
+ ps_data->als_enabled = true;
+#ifdef STK_POLL_ALS
+ hrtimer_start(&ps_data->als_timer, ps_data->als_poll_delay, HRTIMER_MODE_REL);
+#else
+#ifndef STK_POLL_PS
+ if(!(ps_data->ps_enabled))
+#endif
+ enable_irq(ps_data->irq);
+#endif
+ }
+ else
+ {
+ ps_data->als_enabled = false;
+#ifdef STK_POLL_ALS
+ hrtimer_cancel(&ps_data->als_timer);
+#else
+#ifndef STK_POLL_PS
+ if(!(ps_data->ps_enabled))
+#endif
+ disable_irq(ps_data->irq);
+#endif
+ }
+ return ret;
+}
+
+static inline int32_t stk3x1x_get_als_reading(struct stk3x1x_data *ps_data)
+{
+ int32_t word_data, tmp_word_data;
+ tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_ALS_REG);
+ if(tmp_word_data < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data);
+ return tmp_word_data;
+ }
+ word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ;
+ return word_data;
+}
+
+static int32_t stk3x1x_get_ir_reading(struct stk3x1x_data *ps_data)
+{
+ int32_t word_data, tmp_word_data;
+ int32_t ret;
+ uint8_t w_reg, retry = 0;
+
+ if(ps_data->ps_enabled)
+ {
+ stk3x1x_enable_ps(ps_data, 0);
+ ps_data->ps_enabled = true;
+ }
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_reg = (uint8_t)(ret & (~STK_STATE_EN_IRS_MASK));
+ w_reg |= STK_STATE_EN_IRS_MASK;
+
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ msleep(100);
+
+ do
+ {
+ msleep(50);
+ ret = stk3x1x_get_flag(ps_data);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ retry++;
+ }while(retry < 5 && ((ret&STK_FLG_IR_RDY_MASK) == 0));
+
+ if(retry == 5)
+ {
+ printk(KERN_ERR "%s: ir data is not ready for 300ms\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = stk3x1x_get_flag(ps_data);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ ret = stk3x1x_set_flag(ps_data, ret, STK_FLG_IR_RDY_MASK);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_IR_REG);
+ if(tmp_word_data < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data);
+ return tmp_word_data;
+ }
+ word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ;
+
+ if(ps_data->ps_enabled)
+ stk3x1x_enable_ps(ps_data, 1);
+ return word_data;
+}
+
+
+static ssize_t stk_als_code_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t reading;
+
+ reading = stk3x1x_get_als_reading(ps_data);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
+}
+
+
+static ssize_t stk_als_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t enable, ret;
+
+ mutex_lock(&ps_data->io_lock);
+ enable = (ps_data->als_enabled)?1:0;
+ mutex_unlock(&ps_data->io_lock);
+ ret = i2c_smbus_read_byte_data(ps_data->client,STK_STATE_REG);
+ ret = (ret & STK_STATE_EN_ALS_MASK)?1:0;
+
+ if(enable != ret)
+ printk(KERN_ERR "%s: driver and sensor mismatch! driver_enable=0x%x, sensor_enable=%x\n", __func__, enable, ret);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
+static ssize_t stk_als_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint8_t en;
+ if (sysfs_streq(buf, "1"))
+ en = 1;
+ else if (sysfs_streq(buf, "0"))
+ en = 0;
+ else
+ {
+ printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
+ return -EINVAL;
+ }
+ printk(KERN_INFO "%s: Enable ALS : %d\n", __func__, en);
+ mutex_lock(&ps_data->io_lock);
+ stk3x1x_enable_als(ps_data, en);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_als_lux_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t als_reading;
+ uint32_t als_lux;
+ als_reading = stk3x1x_get_als_reading(ps_data);
+ mutex_lock(&ps_data->io_lock);
+ als_lux = stk_alscode2lux(ps_data, als_reading);
+ mutex_unlock(&ps_data->io_lock);
+ return scnprintf(buf, PAGE_SIZE, "%d lux\n", als_lux);
+}
+
+static ssize_t stk_als_lux_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = strict_strtoul(buf, 16, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ ps_data->als_lux_last = value;
+ input_report_abs(ps_data->als_input_dev, ABS_MISC, value);
+ input_sync(ps_data->als_input_dev);
+ mutex_unlock(&ps_data->io_lock);
+ printk(KERN_INFO "%s: als input event %ld lux\n",__func__, value);
+
+ return size;
+}
+
+
+static ssize_t stk_als_transmittance_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t transmittance;
+ mutex_lock(&ps_data->io_lock);
+ transmittance = ps_data->als_transmittance;
+ mutex_unlock(&ps_data->io_lock);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", transmittance);
+}
+
+
+static ssize_t stk_als_transmittance_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = strict_strtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ ps_data->als_transmittance = value;
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_als_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ return scnprintf(buf, PAGE_SIZE, "%lld\n", ktime_to_ns(ps_data->als_poll_delay));
+}
+
+
+static ssize_t stk_als_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ uint64_t value = 0;
+ int ret;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ ret = strict_strtoull(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoull failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: set als poll delay=%lld\n", __func__, value);
+#endif
+ if(value < MIN_ALS_POLL_DELAY_NS)
+ {
+ printk(KERN_ERR "%s: delay is too small\n", __func__);
+ value = MIN_ALS_POLL_DELAY_NS;
+ }
+ mutex_lock(&ps_data->io_lock);
+ if(value != ktime_to_ns(ps_data->als_poll_delay))
+ ps_data->als_poll_delay = ns_to_ktime(value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_als_ir_code_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t reading;
+ reading = stk3x1x_get_ir_reading(ps_data);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
+}
+
+static ssize_t stk_ps_code_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint32_t reading;
+ reading = stk3x1x_get_ps_reading(ps_data);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", reading);
+}
+
+static ssize_t stk_ps_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t enable, ret;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+
+ mutex_lock(&ps_data->io_lock);
+ enable = (ps_data->ps_enabled)?1:0;
+ mutex_unlock(&ps_data->io_lock);
+ ret = i2c_smbus_read_byte_data(ps_data->client,STK_STATE_REG);
+ ret = (ret & STK_STATE_EN_PS_MASK)?1:0;
+
+ if(enable != ret)
+ printk(KERN_ERR "%s: driver and sensor mismatch! driver_enable=0x%x, sensor_enable=%x\n", __func__, enable, ret);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
+static ssize_t stk_ps_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint8_t en;
+ if (sysfs_streq(buf, "1"))
+ en = 1;
+ else if (sysfs_streq(buf, "0"))
+ en = 0;
+ else
+ {
+ printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
+ return -EINVAL;
+ }
+ printk(KERN_INFO "%s: Enable PS : %d\n", __func__, en);
+ mutex_lock(&ps_data->io_lock);
+ stk3x1x_enable_ps(ps_data, en);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_ps_enable_aso_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t ret;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+
+ ret = i2c_smbus_read_byte_data(ps_data->client,STK_STATE_REG);
+ ret = (ret & STK_STATE_EN_ASO_MASK)?1:0;
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
+static ssize_t stk_ps_enable_aso_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint8_t en;
+ int32_t ret;
+ uint8_t w_state_reg;
+
+ if (sysfs_streq(buf, "1"))
+ en = 1;
+ else if (sysfs_streq(buf, "0"))
+ en = 0;
+ else
+ {
+ printk(KERN_ERR "%s, invalid value %d\n", __func__, *buf);
+ return -EINVAL;
+ }
+ printk(KERN_INFO "%s: Enable PS ASO : %d\n", __func__, en);
+
+ ret = i2c_smbus_read_byte_data(ps_data->client, STK_STATE_REG);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ w_state_reg = (uint8_t)(ret & (~STK_STATE_EN_ASO_MASK));
+ if(en)
+ w_state_reg |= STK_STATE_EN_ASO_MASK;
+
+ ret = i2c_smbus_write_byte_data(ps_data->client, STK_STATE_REG, w_state_reg);
+ if (ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+
+ return size;
+}
+
+
+static ssize_t stk_ps_offset_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t word_data, tmp_word_data;
+
+ tmp_word_data = i2c_smbus_read_word_data(ps_data->client, STK_DATA1_OFFSET_REG);
+ if(tmp_word_data < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, tmp_word_data);
+ return tmp_word_data;
+ }
+ word_data = ((tmp_word_data & 0xFF00) >> 8) | ((tmp_word_data & 0x00FF) << 8) ;
+ return scnprintf(buf, PAGE_SIZE, "%d\n", word_data);
+}
+
+static ssize_t stk_ps_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ uint16_t offset;
+
+ ret = strict_strtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ if(value > 65535)
+ {
+ printk(KERN_ERR "%s: invalid value, offset=%ld\n", __func__, value);
+ return -EINVAL;
+ }
+
+ offset = (uint16_t) ((value&0x00FF) << 8) | ((value&0xFF00) >>8);
+ ret = i2c_smbus_write_word_data(ps_data->client,STK_DATA1_OFFSET_REG,offset);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s: write i2c error\n", __func__);
+ return ret;
+ }
+ return size;
+}
+
+
+static ssize_t stk_ps_distance_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ int32_t dist=1, ret;
+
+ mutex_lock(&ps_data->io_lock);
+ ret = stk3x1x_get_flag(ps_data);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s: stk3x1x_get_flag failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ dist = (ret & STK_FLG_NF_MASK)?1:0;
+
+ ps_data->ps_distance_last = dist;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, dist);
+ input_sync(ps_data->ps_input_dev);
+ mutex_unlock(&ps_data->io_lock);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ printk(KERN_INFO "%s: ps input event %d cm\n",__func__, dist);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", dist);
+}
+
+
+static ssize_t stk_ps_distance_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = strict_strtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ ps_data->ps_distance_last = value;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, value);
+ input_sync(ps_data->ps_input_dev);
+ mutex_unlock(&ps_data->io_lock);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ printk(KERN_INFO "%s: ps input event %ld cm\n",__func__, value);
+ return size;
+}
+
+
+static ssize_t stk_ps_code_thd_l_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t ps_thd_l1_reg, ps_thd_l2_reg;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ mutex_lock(&ps_data->io_lock);
+ ps_thd_l1_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDL1_PS_REG);
+ if(ps_thd_l1_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_l1_reg);
+ return -EINVAL;
+ }
+ ps_thd_l2_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDL2_PS_REG);
+ if(ps_thd_l2_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_l2_reg);
+ return -EINVAL;
+ }
+ mutex_unlock(&ps_data->io_lock);
+ ps_thd_l1_reg = ps_thd_l1_reg<<8 | ps_thd_l2_reg;
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ps_thd_l1_reg);
+}
+
+
+static ssize_t stk_ps_code_thd_l_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = strict_strtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ stk3x1x_set_ps_thd_l(ps_data, value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_ps_code_thd_h_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t ps_thd_h1_reg, ps_thd_h2_reg;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ mutex_lock(&ps_data->io_lock);
+ ps_thd_h1_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDH1_PS_REG);
+ if(ps_thd_h1_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_h1_reg);
+ return -EINVAL;
+ }
+ ps_thd_h2_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDH2_PS_REG);
+ if(ps_thd_h2_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, ps_thd_h2_reg);
+ return -EINVAL;
+ }
+ mutex_unlock(&ps_data->io_lock);
+ ps_thd_h1_reg = ps_thd_h1_reg<<8 | ps_thd_h2_reg;
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ps_thd_h1_reg);
+}
+
+
+static ssize_t stk_ps_code_thd_h_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = strict_strtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ stk3x1x_set_ps_thd_h(ps_data, value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+#if 0
+static ssize_t stk_als_lux_thd_l_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t als_thd_l0_reg,als_thd_l1_reg;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint32_t als_lux;
+
+ mutex_lock(&ps_data->io_lock);
+ als_thd_l0_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDL1_ALS_REG);
+ als_thd_l1_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDL2_ALS_REG);
+ if(als_thd_l0_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_l0_reg);
+ return -EINVAL;
+ }
+ if(als_thd_l1_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_l1_reg);
+ return -EINVAL;
+ }
+ als_thd_l0_reg|=(als_thd_l1_reg<<8);
+ als_lux = stk_alscode2lux(ps_data, als_thd_l0_reg);
+ mutex_unlock(&ps_data->io_lock);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", als_lux);
+}
+
+
+static ssize_t stk_als_lux_thd_l_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = strict_strtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ value = stk_lux2alscode(ps_data, value);
+ stk3x1x_set_als_thd_l(ps_data, value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+
+static ssize_t stk_als_lux_thd_h_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t als_thd_h0_reg,als_thd_h1_reg;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ uint32_t als_lux;
+
+ mutex_lock(&ps_data->io_lock);
+ als_thd_h0_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDH1_ALS_REG);
+ als_thd_h1_reg = i2c_smbus_read_byte_data(ps_data->client,STK_THDH2_ALS_REG);
+ if(als_thd_h0_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_h0_reg);
+ return -EINVAL;
+ }
+ if(als_thd_h1_reg < 0)
+ {
+ printk(KERN_ERR "%s fail, err=0x%x", __func__, als_thd_h1_reg);
+ return -EINVAL;
+ }
+ als_thd_h0_reg|=(als_thd_h1_reg<<8);
+ als_lux = stk_alscode2lux(ps_data, als_thd_h0_reg);
+ mutex_unlock(&ps_data->io_lock);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", als_lux);
+}
+
+
+static ssize_t stk_als_lux_thd_h_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ unsigned long value = 0;
+ int ret;
+ ret = strict_strtoul(buf, 10, &value);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ mutex_lock(&ps_data->io_lock);
+ value = stk_lux2alscode(ps_data, value);
+ stk3x1x_set_als_thd_h(ps_data, value);
+ mutex_unlock(&ps_data->io_lock);
+ return size;
+}
+#endif
+
+
+static ssize_t stk_all_reg_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int32_t ps_reg[27];
+ uint8_t cnt;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+ mutex_lock(&ps_data->io_lock);
+ for(cnt=0;cnt<25;cnt++)
+ {
+ ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, (cnt));
+ if(ps_reg[cnt] < 0)
+ {
+ mutex_unlock(&ps_data->io_lock);
+ printk(KERN_ERR "stk_all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
+ return -EINVAL;
+ }
+ else
+ {
+ printk(KERN_INFO "reg[0x%2X]=0x%2X\n", cnt, ps_reg[cnt]);
+ }
+ }
+ ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_PDT_ID_REG);
+ if(ps_reg[cnt] < 0)
+ {
+ mutex_unlock(&ps_data->io_lock);
+ printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
+ return -EINVAL;
+ }
+ printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_PDT_ID_REG, ps_reg[cnt]);
+ cnt++;
+ ps_reg[cnt] = i2c_smbus_read_byte_data(ps_data->client, STK_RSRVD_REG);
+ if(ps_reg[cnt] < 0)
+ {
+ mutex_unlock(&ps_data->io_lock);
+ printk( KERN_ERR "all_reg_show:i2c_smbus_read_byte_data fail, ret=%d", ps_reg[cnt]);
+ return -EINVAL;
+ }
+ printk( KERN_INFO "reg[0x%x]=0x%2X\n", STK_RSRVD_REG, ps_reg[cnt]);
+ mutex_unlock(&ps_data->io_lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X %2X %2X %2X,%2X %2X\n",
+ ps_reg[0], ps_reg[1], ps_reg[2], ps_reg[3], ps_reg[4], ps_reg[5], ps_reg[6], ps_reg[7], ps_reg[8],
+ ps_reg[9], ps_reg[10], ps_reg[11], ps_reg[12], ps_reg[13], ps_reg[14], ps_reg[15], ps_reg[16], ps_reg[17],
+ ps_reg[18], ps_reg[19], ps_reg[20], ps_reg[21], ps_reg[22], ps_reg[23], ps_reg[24], ps_reg[25], ps_reg[26]);
+}
+
+static ssize_t stk_recv_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+
+static ssize_t stk_recv_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ unsigned long value = 0;
+ int ret;
+ int32_t recv_data;
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+
+ if((ret = strict_strtoul(buf, 16, &value)) < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ recv_data = i2c_smbus_read_byte_data(ps_data->client,value);
+ printk("%s: reg 0x%x=0x%x\n", __func__, (int)value, recv_data);
+ return size;
+}
+
+
+static ssize_t stk_send_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+
+static ssize_t stk_send_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
+{
+ int addr, cmd;
+ u8 addr_u8, cmd_u8;
+ int32_t ret, i;
+ char *token[10];
+ struct stk3x1x_data *ps_data = dev_get_drvdata(dev);
+
+ for (i = 0; i < 2; i++)
+ token[i] = strsep((char **)&buf, " ");
+ if((ret = strict_strtoul(token[0], 16, (unsigned long *)&(addr))) < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ if((ret = strict_strtoul(token[1], 16, (unsigned long *)&(cmd))) < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, ret=0x%x\n", __func__, ret);
+ return ret;
+ }
+ printk(KERN_INFO "%s: write reg 0x%x=0x%x\n", __func__, addr, cmd);
+
+ addr_u8 = (u8) addr;
+ cmd_u8 = (u8) cmd;
+ //mutex_lock(&ps_data->io_lock);
+ ret = i2c_smbus_write_byte_data(ps_data->client,addr_u8,cmd_u8);
+ //mutex_unlock(&ps_data->io_lock);
+ if (0 != ret)
+ {
+ printk(KERN_ERR "%s: i2c_smbus_write_byte_data fail\n", __func__);
+ return ret;
+ }
+
+ return size;
+}
+
+
+static struct device_attribute als_enable_attribute = __ATTR(enable,0664,stk_als_enable_show,stk_als_enable_store);
+static struct device_attribute als_lux_attribute = __ATTR(lux,0664,stk_als_lux_show,stk_als_lux_store);
+static struct device_attribute als_code_attribute = __ATTR(code, 0444, stk_als_code_show, NULL);
+static struct device_attribute als_transmittance_attribute = __ATTR(transmittance,0664,stk_als_transmittance_show,stk_als_transmittance_store);
+static struct device_attribute als_poll_delay_attribute = __ATTR(delay,0664,stk_als_delay_show,stk_als_delay_store);
+static struct device_attribute als_ir_code_attribute = __ATTR(ircode,0444,stk_als_ir_code_show,NULL);
+
+
+static struct attribute *stk_als_attrs [] =
+{
+ &als_enable_attribute.attr,
+ &als_lux_attribute.attr,
+ &als_code_attribute.attr,
+ &als_transmittance_attribute.attr,
+ &als_poll_delay_attribute.attr,
+ &als_ir_code_attribute.attr,
+ NULL
+};
+
+static struct attribute_group stk_als_attribute_group = {
+ .name = "driver",
+ .attrs = stk_als_attrs,
+};
+
+
+static struct device_attribute ps_enable_attribute = __ATTR(enable,0664,stk_ps_enable_show,stk_ps_enable_store);
+static struct device_attribute ps_enable_aso_attribute = __ATTR(enableaso,0664,stk_ps_enable_aso_show,stk_ps_enable_aso_store);
+static struct device_attribute ps_distance_attribute = __ATTR(distance,0664,stk_ps_distance_show, stk_ps_distance_store);
+static struct device_attribute ps_offset_attribute = __ATTR(offset,0664,stk_ps_offset_show, stk_ps_offset_store);
+static struct device_attribute ps_code_attribute = __ATTR(code, 0444, stk_ps_code_show, NULL);
+static struct device_attribute ps_code_thd_l_attribute = __ATTR(codethdl,0664,stk_ps_code_thd_l_show,stk_ps_code_thd_l_store);
+static struct device_attribute ps_code_thd_h_attribute = __ATTR(codethdh,0664,stk_ps_code_thd_h_show,stk_ps_code_thd_h_store);
+static struct device_attribute recv_attribute = __ATTR(recv,0664,stk_recv_show,stk_recv_store);
+static struct device_attribute send_attribute = __ATTR(send,0664,stk_send_show, stk_send_store);
+static struct device_attribute all_reg_attribute = __ATTR(allreg, 0444, stk_all_reg_show, NULL);
+
+static struct attribute *stk_ps_attrs [] =
+{
+ &ps_enable_attribute.attr,
+ &ps_enable_aso_attribute.attr,
+ &ps_distance_attribute.attr,
+ &ps_offset_attribute.attr,
+ &ps_code_attribute.attr,
+ &ps_code_thd_l_attribute.attr,
+ &ps_code_thd_h_attribute.attr,
+ &recv_attribute.attr,
+ &send_attribute.attr,
+ &all_reg_attribute.attr,
+ NULL
+};
+
+static struct attribute_group stk_ps_attribute_group = {
+ .name = "driver",
+ .attrs = stk_ps_attrs,
+};
+
+#ifdef STK_POLL_ALS
+static enum hrtimer_restart stk_als_timer_func(struct hrtimer *timer)
+{
+ struct stk3x1x_data *ps_data = container_of(timer, struct stk3x1x_data, als_timer);
+ queue_work(ps_data->stk_als_wq, &ps_data->stk_als_work);
+ hrtimer_forward_now(&ps_data->als_timer, ps_data->als_poll_delay);
+ return HRTIMER_RESTART;
+}
+
+static void stk_als_work_func(struct work_struct *work)
+{
+ struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_als_work);
+ int32_t reading;
+
+ mutex_lock(&ps_data->io_lock);
+ reading = stk3x1x_get_als_reading(ps_data);
+ if(reading < 0)
+ return;
+ ps_data->als_lux_last = stk_alscode2lux(ps_data, reading);
+ input_report_abs(ps_data->als_input_dev, ABS_MISC, ps_data->als_lux_last);
+ input_sync(ps_data->als_input_dev);
+ mutex_unlock(&ps_data->io_lock);
+ //printk(KERN_INFO "%s: als input event %d lux\n",__func__, ps_data->als_lux_last);
+}
+#endif
+
+static enum hrtimer_restart stk_ps_timer_func(struct hrtimer *timer)
+{
+ struct stk3x1x_data *ps_data = container_of(timer, struct stk3x1x_data, ps_timer);
+ queue_work(ps_data->stk_ps_wq, &ps_data->stk_ps_work);
+#ifdef STK_POLL_PS
+ hrtimer_forward_now(&ps_data->ps_timer, ps_data->ps_poll_delay);
+ return HRTIMER_RESTART;
+#else
+ hrtimer_cancel(&ps_data->ps_timer);
+ return HRTIMER_NORESTART;
+#endif
+}
+
+static void stk_ps_work_func(struct work_struct *work)
+{
+ struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_ps_work);
+ uint32_t reading;
+ int32_t near_far_state;
+ uint8_t org_flag_reg;
+ int32_t ret;
+ uint8_t disable_flag = 0;
+ mutex_lock(&ps_data->io_lock);
+
+ org_flag_reg = stk3x1x_get_flag(ps_data);
+ if(org_flag_reg < 0)
+ {
+ printk(KERN_ERR "%s: get_status_reg fail, ret=%d", __func__, org_flag_reg);
+ goto err_i2c_rw;
+ }
+ near_far_state = (org_flag_reg & STK_FLG_NF_MASK)?1:0;
+ reading = stk3x1x_get_ps_reading(ps_data);
+ if(ps_data->ps_distance_last != near_far_state)
+ {
+ ps_data->ps_distance_last = near_far_state;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state);
+ input_sync(ps_data->ps_input_dev);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: ps input event %d cm, ps code = %d\n",__func__, near_far_state, reading);
+#endif
+ }
+ ret = stk3x1x_set_flag(ps_data, org_flag_reg, disable_flag);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:stk3x1x_set_flag fail, ret=%d\n", __func__, ret);
+ goto err_i2c_rw;
+ }
+
+ mutex_unlock(&ps_data->io_lock);
+ return;
+
+err_i2c_rw:
+ mutex_unlock(&ps_data->io_lock);
+ msleep(30);
+ return;
+}
+
+
+#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
+static void stk_work_func(struct work_struct *work)
+{
+ uint32_t reading;
+#if ((STK_INT_PS_MODE != 0x03) && (STK_INT_PS_MODE != 0x02))
+ int32_t ret;
+ uint8_t disable_flag = 0;
+ uint8_t org_flag_reg;
+#endif /* #if ((STK_INT_PS_MODE != 0x03) && (STK_INT_PS_MODE != 0x02)) */
+
+#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+ uint32_t nLuxIndex;
+#endif
+ struct stk3x1x_data *ps_data = container_of(work, struct stk3x1x_data, stk_work);
+ int32_t near_far_state;
+
+ mutex_lock(&ps_data->io_lock);
+
+#if (STK_INT_PS_MODE == 0x03)
+ near_far_state = gpio_get_value(ps_data->int_pin);
+#elif (STK_INT_PS_MODE == 0x02)
+ near_far_state = !(gpio_get_value(ps_data->int_pin));
+#endif
+
+#if ((STK_INT_PS_MODE == 0x03) || (STK_INT_PS_MODE == 0x02))
+ ps_data->ps_distance_last = near_far_state;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state);
+ input_sync(ps_data->ps_input_dev);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ reading = stk3x1x_get_ps_reading(ps_data);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: ps input event %d cm, ps code = %d\n",__func__, near_far_state, reading);
+#endif
+#else
+ /* mode 0x01 or 0x04 */
+ org_flag_reg = stk3x1x_get_flag(ps_data);
+ if(org_flag_reg < 0)
+ {
+ printk(KERN_ERR "%s: get_status_reg fail, org_flag_reg=%d", __func__, org_flag_reg);
+ goto err_i2c_rw;
+ }
+
+ if (org_flag_reg & STK_FLG_ALSINT_MASK)
+ {
+ disable_flag |= STK_FLG_ALSINT_MASK;
+ reading = stk3x1x_get_als_reading(ps_data);
+ if(reading < 0)
+ {
+ printk(KERN_ERR "%s: stk3x1x_get_als_reading fail, ret=%d", __func__, reading);
+ goto err_i2c_rw;
+ }
+#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+ nLuxIndex = stk_get_lux_interval_index(reading);
+ stk3x1x_set_als_thd_h(ps_data, code_threshold_table[nLuxIndex]);
+ stk3x1x_set_als_thd_l(ps_data, code_threshold_table[nLuxIndex-1]);
+#else
+ stk_als_set_new_thd(ps_data, reading);
+#endif //CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+ ps_data->als_lux_last = stk_alscode2lux(ps_data, reading);
+ input_report_abs(ps_data->als_input_dev, ABS_MISC, ps_data->als_lux_last);
+ input_sync(ps_data->als_input_dev);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: als input event %d lux\n",__func__, ps_data->als_lux_last);
+#endif
+ }
+ if (org_flag_reg & STK_FLG_PSINT_MASK)
+ {
+ disable_flag |= STK_FLG_PSINT_MASK;
+ near_far_state = (org_flag_reg & STK_FLG_NF_MASK)?1:0;
+
+ ps_data->ps_distance_last = near_far_state;
+ input_report_abs(ps_data->ps_input_dev, ABS_DISTANCE, near_far_state);
+ input_sync(ps_data->ps_input_dev);
+ wake_lock_timeout(&ps_data->ps_wakelock, 3*HZ);
+ reading = stk3x1x_get_ps_reading(ps_data);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: ps input event=%d, ps code = %d\n",__func__, near_far_state, reading);
+#endif
+ }
+
+ ret = stk3x1x_set_flag(ps_data, org_flag_reg, disable_flag);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s:reset_int_flag fail, ret=%d\n", __func__, ret);
+ goto err_i2c_rw;
+ }
+#endif
+
+ msleep(1);
+ enable_irq(ps_data->irq);
+ mutex_unlock(&ps_data->io_lock);
+ return;
+
+err_i2c_rw:
+ mutex_unlock(&ps_data->io_lock);
+ msleep(30);
+ enable_irq(ps_data->irq);
+ return;
+}
+#endif
+
+#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
+static irqreturn_t stk_oss_irq_handler(int irq, void *data)
+{
+ struct stk3x1x_data *pData = data;
+ disable_irq_nosync(irq);
+ queue_work(pData->stk_wq,&pData->stk_work);
+ return IRQ_HANDLED;
+}
+#endif /* #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS)) */
+static int32_t stk3x1x_init_all_setting(struct i2c_client *client, struct stk3x1x_platform_data *plat_data)
+{
+ int32_t ret;
+ struct stk3x1x_data *ps_data = i2c_get_clientdata(client);
+
+ mutex_lock(&ps_data->io_lock);
+ ps_data->als_enabled = false;
+ ps_data->ps_enabled = false;
+ mutex_unlock(&ps_data->io_lock);
+
+ ret = stk3x1x_software_reset(ps_data);
+ if(ret < 0)
+ return ret;
+
+ stk3x1x_check_pid(ps_data);
+ if(ret < 0)
+ return ret;
+
+ ret = stk3x1x_init_all_reg(ps_data, plat_data);
+ if(ret < 0)
+ return ret;
+#ifndef CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD
+ stk_init_code_threshold_table(ps_data);
+#endif
+ return 0;
+}
+
+#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
+static int stk3x1x_setup_irq(struct i2c_client *client)
+{
+ int irq, err = -EIO;
+ struct stk3x1x_data *ps_data = i2c_get_clientdata(client);
+
+ irq = gpio_to_irq(ps_data->int_pin);
+#ifdef STK_DEBUG_PRINTF
+ printk(KERN_INFO "%s: int pin #=%d, irq=%d\n",__func__, ps_data->int_pin, irq);
+#endif
+ if (irq <= 0)
+ {
+ printk(KERN_ERR "irq number is not specified, irq # = %d, int pin=%d\n",irq, ps_data->int_pin);
+ return irq;
+ }
+ ps_data->irq = irq;
+ err = gpio_request(ps_data->int_pin,"stk-int");
+ if(err < 0)
+ {
+ printk(KERN_ERR "%s: gpio_request, err=%d", __func__, err);
+ return err;
+ }
+ err = gpio_direction_input(ps_data->int_pin);
+ if(err < 0)
+ {
+ printk(KERN_ERR "%s: gpio_direction_input, err=%d", __func__, err);
+ return err;
+ }
+#if ((STK_INT_PS_MODE == 0x03) || (STK_INT_PS_MODE == 0x02))
+ err = request_any_context_irq(irq, stk_oss_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, DEVICE_NAME, ps_data);
+#else
+ err = request_any_context_irq(irq, stk_oss_irq_handler, IRQF_TRIGGER_LOW, DEVICE_NAME, ps_data);
+#endif
+ if (err < 0)
+ {
+ printk(KERN_WARNING "%s: request_any_context_irq(%d) failed for (%d)\n", __func__, irq, err);
+ goto err_request_any_context_irq;
+ }
+ disable_irq(irq);
+
+ return 0;
+err_request_any_context_irq:
+ gpio_free(ps_data->int_pin);
+ return err;
+}
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void stk3x1x_early_suspend(struct early_suspend *h)
+{
+ struct stk3x1x_data *ps_data = container_of(h, struct stk3x1x_data, stk_early_suspend);
+#ifndef STK_POLL_PS
+ int err;
+#endif
+
+ printk(KERN_INFO "%s", __func__);
+ mutex_lock(&ps_data->io_lock);
+ if(ps_data->als_enabled)
+ {
+ stk3x1x_enable_als(ps_data, 0);
+ ps_data->als_enabled = true;
+ }
+ if(ps_data->ps_enabled)
+ {
+#ifdef STK_POLL_PS
+ wake_lock(&ps_data->ps_nosuspend_wl);
+#else
+ err = enable_irq_wake(ps_data->irq);
+ if (err)
+ printk(KERN_WARNING "%s: set_irq_wake(%d) failed, err=(%d)\n", __func__, ps_data->irq, err);
+#endif
+ }
+ mutex_unlock(&ps_data->io_lock);
+ return;
+}
+
+static void stk3x1x_late_resume(struct early_suspend *h)
+{
+ struct stk3x1x_data *ps_data = container_of(h, struct stk3x1x_data, stk_early_suspend);
+#ifndef STK_POLL_PS
+ int err;
+#endif
+
+ printk(KERN_INFO "%s", __func__);
+ mutex_lock(&ps_data->io_lock);
+ if(ps_data->als_enabled)
+ stk3x1x_enable_als(ps_data, 1);
+
+ if(ps_data->ps_enabled)
+ {
+#ifdef STK_POLL_PS
+ wake_lock(&ps_data->ps_nosuspend_wl);
+#else
+ err = disable_irq_wake(ps_data->irq);
+ if (err)
+ printk(KERN_WARNING "%s: disable_irq_wake(%d) failed, err=(%d)\n", __func__, ps_data->irq, err);
+#endif
+ }
+ mutex_unlock(&ps_data->io_lock);
+ return;
+}
+#endif //#ifdef CONFIG_HAS_EARLYSUSPEND
+
+
+static int stk3x1x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err = -ENODEV;
+ struct stk3x1x_data *ps_data;
+ struct stk3x1x_platform_data *plat_data;
+ printk(KERN_INFO "%s: driver version = %s\n", __func__, DRIVER_VERSION);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ {
+ printk(KERN_ERR "%s: No Support for I2C_FUNC_SMBUS_BYTE_DATA\n", __func__);
+ return -ENODEV;
+ }
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ {
+ printk(KERN_ERR "%s: No Support for I2C_FUNC_SMBUS_WORD_DATA\n", __func__);
+ return -ENODEV;
+ }
+
+ ps_data = kzalloc(sizeof(struct stk3x1x_data),GFP_KERNEL);
+ if(!ps_data)
+ {
+ printk(KERN_ERR "%s: failed to allocate stk3x1x_data\n", __func__);
+ return -ENOMEM;
+ }
+ ps_data->client = client;
+ i2c_set_clientdata(client,ps_data);
+ mutex_init(&ps_data->io_lock);
+ wake_lock_init(&ps_data->ps_wakelock,WAKE_LOCK_SUSPEND, "stk_input_wakelock");
+
+#ifdef STK_POLL_PS
+ wake_lock_init(&ps_data->ps_nosuspend_wl,WAKE_LOCK_SUSPEND, "stk_nosuspend_wakelock");
+#endif
+ if(client->dev.platform_data != NULL)
+ {
+ plat_data = client->dev.platform_data;
+ ps_data->als_transmittance = plat_data->transmittance;
+ ps_data->int_pin = plat_data->int_pin;
+ if(ps_data->als_transmittance == 0)
+ {
+ printk(KERN_ERR "%s: Please set als_transmittance in platform data\n", __func__);
+ goto err_als_input_allocate;
+ }
+ }
+ else
+ {
+ printk(KERN_ERR "%s: no stk3x1x platform data!\n", __func__);
+ goto err_als_input_allocate;
+ }
+
+ ps_data->als_input_dev = input_allocate_device();
+ if (ps_data->als_input_dev==NULL)
+ {
+ printk(KERN_ERR "%s: could not allocate als device\n", __func__);
+ err = -ENOMEM;
+ goto err_als_input_allocate;
+ }
+ ps_data->ps_input_dev = input_allocate_device();
+ if (ps_data->ps_input_dev==NULL)
+ {
+ printk(KERN_ERR "%s: could not allocate ps device\n", __func__);
+ err = -ENOMEM;
+ goto err_ps_input_allocate;
+ }
+ ps_data->als_input_dev->name = ALS_NAME;
+ ps_data->ps_input_dev->name = PS_NAME;
+ set_bit(EV_ABS, ps_data->als_input_dev->evbit);
+ set_bit(EV_ABS, ps_data->ps_input_dev->evbit);
+ input_set_abs_params(ps_data->als_input_dev, ABS_MISC, 0, stk_alscode2lux(ps_data, (1<<16)-1), 0, 0);
+ input_set_abs_params(ps_data->ps_input_dev, ABS_DISTANCE, 0,1, 0, 0);
+ err = input_register_device(ps_data->als_input_dev);
+ if (err<0)
+ {
+ printk(KERN_ERR "%s: can not register als input device\n", __func__);
+ goto err_als_input_register;
+ }
+ err = input_register_device(ps_data->ps_input_dev);
+ if (err<0)
+ {
+ printk(KERN_ERR "%s: can not register ps input device\n", __func__);
+ goto err_ps_input_register;
+ }
+
+ err = sysfs_create_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group);
+ if (err < 0)
+ {
+ printk(KERN_ERR "%s:could not create sysfs group for als\n", __func__);
+ goto err_als_sysfs_create_group;
+ }
+ err = sysfs_create_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group);
+ if (err < 0)
+ {
+ printk(KERN_ERR "%s:could not create sysfs group for ps\n", __func__);
+ goto err_ps_sysfs_create_group;
+ }
+ input_set_drvdata(ps_data->als_input_dev, ps_data);
+ input_set_drvdata(ps_data->ps_input_dev, ps_data);
+
+#ifdef STK_POLL_ALS
+ ps_data->stk_als_wq = create_singlethread_workqueue("stk_als_wq");
+ INIT_WORK(&ps_data->stk_als_work, stk_als_work_func);
+ hrtimer_init(&ps_data->als_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ps_data->als_poll_delay = ns_to_ktime(110 * NSEC_PER_MSEC);
+ ps_data->als_timer.function = stk_als_timer_func;
+#endif
+
+ ps_data->stk_ps_wq = create_singlethread_workqueue("stk_ps_wq");
+ INIT_WORK(&ps_data->stk_ps_work, stk_ps_work_func);
+ hrtimer_init(&ps_data->ps_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ps_data->ps_poll_delay = ns_to_ktime(110 * NSEC_PER_MSEC);
+ ps_data->ps_timer.function = stk_ps_timer_func;
+#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
+ ps_data->stk_wq = create_singlethread_workqueue("stk_wq");
+ INIT_WORK(&ps_data->stk_work, stk_work_func);
+ err = stk3x1x_setup_irq(client);
+ if(err < 0)
+ goto err_stk3x1x_setup_irq;
+#endif
+
+ err = stk3x1x_init_all_setting(client, plat_data);
+ if(err < 0)
+ goto err_init_all_setting;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ps_data->stk_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ps_data->stk_early_suspend.suspend = stk3x1x_early_suspend;
+ ps_data->stk_early_suspend.resume = stk3x1x_late_resume;
+ register_early_suspend(&ps_data->stk_early_suspend);
+#endif
+ printk(KERN_INFO "%s: probe successfully", __func__);
+ return 0;
+
+err_init_all_setting:
+#ifndef STK_POLL_PS
+ free_irq(ps_data->irq, ps_data);
+ gpio_free(plat_data->int_pin);
+#endif
+#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
+err_stk3x1x_setup_irq:
+#endif
+#ifdef STK_POLL_ALS
+ hrtimer_try_to_cancel(&ps_data->als_timer);
+ destroy_workqueue(ps_data->stk_als_wq);
+#endif
+ destroy_workqueue(ps_data->stk_ps_wq);
+#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
+ destroy_workqueue(ps_data->stk_wq);
+#endif
+ sysfs_remove_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group);
+err_ps_sysfs_create_group:
+ sysfs_remove_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group);
+err_als_sysfs_create_group:
+ input_unregister_device(ps_data->ps_input_dev);
+err_ps_input_register:
+ input_unregister_device(ps_data->als_input_dev);
+err_als_input_register:
+ input_free_device(ps_data->ps_input_dev);
+err_ps_input_allocate:
+ input_free_device(ps_data->als_input_dev);
+err_als_input_allocate:
+#ifdef STK_POLL_PS
+ wake_lock_destroy(&ps_data->ps_nosuspend_wl);
+#endif
+ wake_lock_destroy(&ps_data->ps_wakelock);
+ mutex_destroy(&ps_data->io_lock);
+ kfree(ps_data);
+ return err;
+}
+
+
+static int stk3x1x_remove(struct i2c_client *client)
+{
+ struct stk3x1x_data *ps_data = i2c_get_clientdata(client);
+#ifndef STK_POLL_PS
+ free_irq(ps_data->irq, ps_data);
+ gpio_free(ps_data->int_pin);
+#endif
+#ifdef STK_POLL_ALS
+ hrtimer_try_to_cancel(&ps_data->als_timer);
+ destroy_workqueue(ps_data->stk_als_wq);
+#endif
+ destroy_workqueue(ps_data->stk_ps_wq);
+#if (!defined(STK_POLL_ALS) || !defined(STK_POLL_PS))
+ destroy_workqueue(ps_data->stk_wq);
+#endif
+ sysfs_remove_group(&ps_data->ps_input_dev->dev.kobj, &stk_ps_attribute_group);
+ sysfs_remove_group(&ps_data->als_input_dev->dev.kobj, &stk_als_attribute_group);
+ input_unregister_device(ps_data->ps_input_dev);
+ input_unregister_device(ps_data->als_input_dev);
+ input_free_device(ps_data->ps_input_dev);
+ input_free_device(ps_data->als_input_dev);
+#ifdef STK_POLL_PS
+ wake_lock_destroy(&ps_data->ps_nosuspend_wl);
+#endif
+ wake_lock_destroy(&ps_data->ps_wakelock);
+ mutex_destroy(&ps_data->io_lock);
+ kfree(ps_data);
+
+ return 0;
+}
+
+static const struct i2c_device_id stk_ps_id[] =
+{
+ { "stk_ps", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, stk_ps_id);
+
+static struct i2c_driver stk_ps_driver =
+{
+ .driver = {
+ .name = DEVICE_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = stk3x1x_probe,
+ .remove = stk3x1x_remove,
+ .id_table = stk_ps_id,
+};
+
+
+static int __init stk3x1x_init(void)
+{
+ int ret;
+ ret = i2c_add_driver(&stk_ps_driver);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void __exit stk3x1x_exit(void)
+{
+ i2c_del_driver(&stk_ps_driver);
+}
+
+module_init(stk3x1x_init);
+module_exit(stk3x1x_exit);
+MODULE_AUTHOR("Lex Hsieh <lex_hsieh@sitronix.com.tw>");
+MODULE_DESCRIPTION("Sensortek stk3x1x Proximity Sensor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 3722066..aac973e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -144,7 +144,7 @@
/* CGC_OVERRIDE */
msm_camera_io_w(0x07FFFFFF, vfe_dev->vfe_base + 0xC);
/* BUS_CFG */
- msm_camera_io_w(0x00000001, vfe_dev->vfe_base + 0x3C);
+ msm_camera_io_w(0x00000009, vfe_dev->vfe_base + 0x3C);
msm_camera_io_w(0x01000025, vfe_dev->vfe_base + 0x1C);
msm_camera_io_w_mb(0x1CFFFFFF, vfe_dev->vfe_base + 0x20);
msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x24);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index d857a14..33f63b3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -150,6 +150,12 @@
stats_idx = vfe_dev->hw_info->vfe_ops.stats_ops.
get_stats_idx(stream_req_cmd->stats_type);
+ if ((stats_idx > MSM_ISP_STATS_MAX) ||
+ (stats_idx == -EINVAL)) {
+ pr_err("%s: Stats idx Error\n", __func__);
+ return rc;
+ }
+
stream_info = &stats_data->stream_info[stats_idx];
if (stream_info->state != STATS_AVALIABLE) {
pr_err("%s: Stats already requested\n", __func__);
@@ -188,7 +194,7 @@
int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg)
{
- int rc = 0;
+ int rc = -1;
struct msm_vfe_stats_stream_request_cmd *stream_req_cmd = arg;
struct msm_vfe_stats_stream *stream_info = NULL;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
@@ -202,6 +208,11 @@
}
stats_idx = STATS_IDX(stream_req_cmd->stream_handle);
+ if (stats_idx > MSM_ISP_STATS_MAX) {
+ pr_err("%s: Stats idx Error\n", __func__);
+ return rc;
+ }
+
stream_info = &stats_data->stream_info[stats_idx];
framedrop_period = msm_isp_get_framedrop_period(
@@ -228,9 +239,14 @@
struct msm_vfe_stats_stream_release_cmd *stream_release_cmd = arg;
struct msm_vfe_stats_shared_data *stats_data = &vfe_dev->stats_data;
int stats_idx = STATS_IDX(stream_release_cmd->stream_handle);
- struct msm_vfe_stats_stream *stream_info =
- &stats_data->stream_info[stats_idx];
+ struct msm_vfe_stats_stream *stream_info = NULL;
+ if (stats_idx > MSM_ISP_STATS_MAX) {
+ pr_err("%s: Stats idx Error\n", __func__);
+ return rc;
+ }
+
+ stream_info = &stats_data->stream_info[stats_idx];
if (stream_info->state == STATS_AVALIABLE) {
pr_err("%s: stream already release\n", __func__);
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index ad34d45..f94b6f1 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -770,12 +770,12 @@
vb->v4l2_planes[0].bytesused = response->input_done.filled_len;
vb->v4l2_planes[0].data_offset = response->input_done.offset;
if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length)
- dprintk(VIDC_ERR, "Error: data_offset overflow\n");
+ dprintk(VIDC_INFO, "data_offset overflow length\n");
if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length)
- dprintk(VIDC_ERR, "Error: buffer overflow\n");
+ dprintk(VIDC_INFO, "bytesused overflow length\n");
if ((u8 *)vb->v4l2_planes[0].m.userptr !=
response->input_done.packet_buffer)
- dprintk(VIDC_ERR, "Error: unexpected buffer address\n");
+ dprintk(VIDC_INFO, "Unexpected buffer address\n");
vb->v4l2_buf.flags = 0;
empty_buf_done = (struct vidc_hal_ebd *)&response->input_done;
if (empty_buf_done) {
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index b518f1f..c246036 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1970,6 +1970,11 @@
pr_debug("new delta ocv = %d\n", delta_ocv_uv);
}
+ if (wake_lock_active(&chip->low_voltage_wake_lock)) {
+ pr_debug("Low Voltage, apply only ibat limited corrections\n");
+ goto skip_limiting_corrections;
+ }
+
if (chip->last_ocv_uv > 3800000)
correction_limit_uv = the_chip->high_ocv_correction_limit_uv;
else
@@ -1986,6 +1991,7 @@
pr_debug("new delta ocv = %d\n", delta_ocv_uv);
}
+skip_limiting_corrections:
chip->last_ocv_uv -= delta_ocv_uv;
if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -2278,7 +2284,6 @@
int new_calculated_soc;
static int firsttime = 1;
- calib_hkadc_check(chip, batt_temp);
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
&unusable_charge_uah,
@@ -2426,6 +2431,7 @@
get_batt_temp(chip, &batt_temp);
mutex_lock(&chip->last_ocv_uv_mutex);
+ calib_hkadc_check(chip, batt_temp);
read_soc_params_raw(chip, &raw, batt_temp);
soc = calculate_state_of_charge(chip, &raw,
@@ -2762,6 +2768,7 @@
get_batt_temp(the_chip, &batt_temp);
mutex_lock(&the_chip->last_ocv_uv_mutex);
+ calib_hkadc_check(the_chip, batt_temp);
read_soc_params_raw(the_chip, &raw, batt_temp);
mutex_unlock(&the_chip->last_ocv_uv_mutex);
@@ -2907,6 +2914,7 @@
mutex_lock(&the_chip->last_ocv_uv_mutex);
+ calib_hkadc_check(the_chip, batt_temp);
read_soc_params_raw(the_chip, &raw, batt_temp);
calculate_cc_uah(the_chip, raw.cc, &bms_end_cc_uah);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index d5b2cc6..f3f59e6 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -298,6 +298,7 @@
bool disable_aicl;
int usb_type;
bool disable_chg_rmvl_wrkarnd;
+ struct msm_xo_voter *voter;
};
/* user space parameter to limit usb current */
@@ -4034,6 +4035,7 @@
int err;
u8 temp;
+ msm_xo_mode_vote(chip->voter, MSM_XO_MODE_ON);
temp = 0xD1;
err = pm_chg_write(chip, CHG_TEST, temp);
if (err) {
@@ -4092,6 +4094,8 @@
pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
return;
}
+
+ msm_xo_mode_vote(chip->voter, MSM_XO_MODE_OFF);
}
static void pm8921_chg_set_hw_clk_switching(struct pm8921_chg_chip *chip)
@@ -4099,6 +4103,7 @@
int err;
u8 temp;
+ msm_xo_mode_vote(chip->voter, MSM_XO_MODE_ON);
temp = 0xD1;
err = pm_chg_write(chip, CHG_TEST, temp);
if (err) {
@@ -4112,6 +4117,7 @@
pr_err("Error %d writing %d to addr %d\n", err, temp, CHG_TEST);
return;
}
+ msm_xo_mode_vote(chip->voter, MSM_XO_MODE_OFF);
}
#define VREF_BATT_THERM_FORCE_ON BIT(7)
@@ -4800,6 +4806,7 @@
chip->ibatmax_max_adj_ma = find_ibat_max_adj_ma(
chip->max_bat_chg_current);
+ chip->voter = msm_xo_get(MSM_XO_TCXO_D0, "pm8921_charger");
rc = pm8921_chg_hw_init(chip);
if (rc) {
pr_err("couldn't init hardware rc=%d\n", rc);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index c9b2476..25b4b5e 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2919,15 +2919,6 @@
goto err_probe_reqmem;
}
- if (pdata && pdata->ver_reg_exists) {
- enum msm_spi_qup_version ver =
- msm_spi_get_qup_hw_ver(&pdev->dev, dd);
- if (dd->qup_ver != ver)
- dev_warn(&pdev->dev,
- "%s: HW version different then initially assumed by probe",
- __func__);
- }
-
if (pdata && pdata->rsl_id) {
struct remote_mutex_id rmid;
rmid.r_spinlock_id = pdata->rsl_id;
@@ -2986,6 +2977,16 @@
}
pclk_enabled = 1;
+
+ if (pdata && pdata->ver_reg_exists) {
+ enum msm_spi_qup_version ver =
+ msm_spi_get_qup_hw_ver(&pdev->dev, dd);
+ if (dd->qup_ver != ver)
+ dev_warn(&pdev->dev,
+ "%s: HW version different then initially assumed by probe",
+ __func__);
+ }
+
/* GSBI dose not exists on B-family MSM-chips */
if (dd->qup_ver != SPI_QUP_VERSION_BFAM) {
rc = msm_spi_configure_gsbi(dd, pdev);
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index a775459..b0b2f56 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -127,6 +127,8 @@
struct work_struct connect_w;
struct work_struct disconnect_w;
+ struct work_struct suspend_w;
+ struct work_struct resume_w;
};
static struct bam_portmaster {
@@ -542,7 +544,9 @@
struct bam_ch_info *d = &port->data_ch;
int status;
+ spin_lock(&port->port_lock_ul);
if (!port->port_usb) {
+ spin_unlock(&port->port_lock_ul);
pr_err("%s: port->port_usb is NULL", __func__);
return;
}
@@ -551,6 +555,7 @@
status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+ spin_unlock(&port->port_lock_ul);
}
static void gbam_start_endless_tx(struct gbam_port *port)
@@ -558,7 +563,9 @@
struct bam_ch_info *d = &port->data_ch;
int status;
+ spin_lock(&port->port_lock_dl);
if (!port->port_usb) {
+ spin_unlock(&port->port_lock_dl);
pr_err("%s: port->port_usb is NULL", __func__);
return;
}
@@ -567,6 +574,8 @@
status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
if (status)
pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
+ spin_unlock(&port->port_lock_dl);
+
}
static void gbam_stop_endless_rx(struct gbam_port *port)
@@ -574,7 +583,9 @@
struct bam_ch_info *d = &port->data_ch;
int status;
+ spin_lock(&port->port_lock_ul);
if (!port->port_usb) {
+ spin_unlock(&port->port_lock_ul);
pr_err("%s: port->port_usb is NULL", __func__);
return;
}
@@ -583,14 +594,17 @@
status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
if (status)
pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
-
+ spin_unlock(&port->port_lock_ul);
}
+
static void gbam_stop_endless_tx(struct gbam_port *port)
{
struct bam_ch_info *d = &port->data_ch;
int status;
+ spin_lock(&port->port_lock_dl);
if (!port->port_usb) {
+ spin_unlock(&port->port_lock_dl);
pr_err("%s: port->port_usb is NULL", __func__);
return;
}
@@ -599,6 +613,7 @@
status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
if (status)
pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+ spin_unlock(&port->port_lock_dl);
}
static void gbam_start(void *param, enum usb_bam_pipe_dir dir)
@@ -893,6 +908,46 @@
pr_debug("%s: done\n", __func__);
}
+static int gbam_wake_cb(void *param)
+{
+ struct gbam_port *port = (struct gbam_port *)param;
+ struct bam_ch_info *d;
+ struct f_rmnet *dev;
+
+ dev = port_to_rmnet(port->gr);
+ d = &port->data_ch;
+
+ pr_debug("%s: woken up by peer\n", __func__);
+
+ return usb_gadget_wakeup(dev->cdev->gadget);
+}
+
+static void gbam2bam_suspend_work(struct work_struct *w)
+{
+ struct gbam_port *port = container_of(w, struct gbam_port, suspend_w);
+ struct bam_ch_info *d = &port->data_ch;
+
+ pr_debug("%s: suspend work started\n", __func__);
+
+ usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(gbam_start, gbam_stop, port);
+ usb_bam_suspend(&d->ipa_params);
+ }
+}
+
+static void gbam2bam_resume_work(struct work_struct *w)
+{
+ struct gbam_port *port = container_of(w, struct gbam_port, resume_w);
+ struct bam_ch_info *d = &port->data_ch;
+
+ pr_debug("%s: resume work started\n", __func__);
+
+ usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+ usb_bam_resume(&d->ipa_params);
+}
+
static int gbam_peer_reset_cb(void *param)
{
struct gbam_port *port = (struct gbam_port *)param;
@@ -1122,6 +1177,8 @@
INIT_WORK(&port->connect_w, gbam2bam_connect_work);
INIT_WORK(&port->disconnect_w, gbam2bam_disconnect_work);
+ INIT_WORK(&port->suspend_w, gbam2bam_suspend_work);
+ INIT_WORK(&port->resume_w, gbam2bam_resume_work);
/* data ch */
d = &port->data_ch;
@@ -1446,20 +1503,6 @@
return ret;
}
-static int gbam_wake_cb(void *param)
-{
- struct gbam_port *port = (struct gbam_port *)param;
- struct bam_ch_info *d;
- struct f_rmnet *dev;
-
- dev = port_to_rmnet(port->gr);
- d = &port->data_ch;
-
- pr_debug("%s: woken up by peer\n", __func__);
-
- return usb_gadget_wakeup(dev->cdev->gadget);
-}
-
void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans)
{
struct gbam_port *port;
@@ -1474,11 +1517,7 @@
pr_debug("%s: suspended port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
- if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- usb_bam_register_start_stop_cbs(gbam_start, gbam_stop, port);
- usb_bam_suspend(&d->ipa_params);
- }
+ queue_work(gbam_wq, &port->suspend_w);
}
void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1495,7 +1534,5 @@
pr_debug("%s: resumed port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
- if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
- usb_bam_resume(&d->ipa_params);
+ queue_work(gbam_wq, &port->resume_w);
}
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 577a4fe..b315605 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -62,10 +62,15 @@
struct work_struct connect_w;
struct work_struct disconnect_w;
+ struct work_struct suspend_w;
+ struct work_struct resume_w;
};
struct bam_data_port *bam2bam_data_ports[BAM2BAM_DATA_N_PORTS];
+static void bam2bam_data_suspend_work(struct work_struct *w);
+static void bam2bam_data_resume_work(struct work_struct *w);
+
/*------------data_path----------------------------*/
static void bam_data_endless_rx_complete(struct usb_ep *ep,
@@ -351,6 +356,8 @@
INIT_WORK(&port->connect_w, bam2bam_data_connect_work);
INIT_WORK(&port->disconnect_w, bam2bam_data_disconnect_work);
+ INIT_WORK(&port->suspend_w, bam2bam_data_suspend_work);
+ INIT_WORK(&port->resume_w, bam2bam_data_resume_work);
/* data ch */
d = &port->data_ch;
@@ -578,12 +585,8 @@
d = &port->data_ch;
pr_debug("%s: suspended port %d\n", __func__, port_num);
- usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
- if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
- usb_bam_register_start_stop_cbs(bam_data_start, bam_data_stop,
- port);
- usb_bam_suspend(&d->ipa_params);
- }
+
+ queue_work(bam_data_wq, &port->suspend_w);
}
void bam_data_resume(u8 port_num)
@@ -596,6 +599,34 @@
d = &port->data_ch;
pr_debug("%s: resumed port %d\n", __func__, port_num);
+
+ queue_work(bam_data_wq, &port->resume_w);
+}
+
+static void bam2bam_data_suspend_work(struct work_struct *w)
+{
+ struct bam_data_port *port =
+ container_of(w, struct bam_data_port, suspend_w);
+ struct bam_data_ch_info *d = &port->data_ch;
+
+ pr_debug("%s: suspend work started\n", __func__);
+
+ usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
+ if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ usb_bam_register_start_stop_cbs(bam_data_start, bam_data_stop,
+ port);
+ usb_bam_suspend(&d->ipa_params);
+ }
+}
+
+static void bam2bam_data_resume_work(struct work_struct *w)
+{
+ struct bam_data_port *port =
+ container_of(w, struct bam_data_port, resume_w);
+ struct bam_data_ch_info *d = &port->data_ch;
+
+ pr_debug("%s: resume work started\n", __func__);
+
usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)
usb_bam_resume(&d->ipa_params);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 253658e..cfc5961 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1122,10 +1122,16 @@
u32 cmd;
unsigned long flags;
int retries = 0, ret, cnt = RESET_SIGNAL_TIME_USEC;
+ s32 next_latency = 0;
- if (pdata && pdata->swfi_latency)
- pm_qos_update_request(&mehci->pm_qos_req_dma,
- pdata->swfi_latency + 1);
+ if (pdata && pdata->swfi_latency) {
+ next_latency = pdata->swfi_latency + 1;
+ pm_qos_update_request(&mehci->pm_qos_req_dma, next_latency);
+ if (pdata->standalone_latency)
+ next_latency = pdata->standalone_latency + 1;
+ else
+ next_latency = PM_QOS_DEFAULT_VALUE;
+ }
mehci->bus_reset = 1;
@@ -1196,9 +1202,8 @@
pr_debug("reset completed\n");
fail:
mehci->bus_reset = 0;
- if (pdata && pdata->swfi_latency)
- pm_qos_update_request(&mehci->pm_qos_req_dma,
- PM_QOS_DEFAULT_VALUE);
+ if (next_latency)
+ pm_qos_update_request(&mehci->pm_qos_req_dma, next_latency);
}
static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
@@ -1229,19 +1234,27 @@
int retry_cnt = 0;
int tight_resume = 0;
struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+ s32 next_latency = 0;
dbg_log_event(NULL, "Resume RH", 0);
+ if (pdata && pdata->swfi_latency) {
+ next_latency = pdata->swfi_latency + 1;
+ pm_qos_update_request(&mehci->pm_qos_req_dma, next_latency);
+ if (pdata->standalone_latency)
+ next_latency = pdata->standalone_latency + 1;
+ else
+ next_latency = PM_QOS_DEFAULT_VALUE;
+ }
+
/* keep delay between bus states */
if (time_before(jiffies, ehci->next_statechange))
usleep_range(5000, 5000);
spin_lock_irq(&ehci->lock);
if (!HCD_HW_ACCESSIBLE(hcd)) {
- spin_unlock_irq(&ehci->lock);
mehci->resume_status = -ESHUTDOWN;
- complete(&mehci->rt_completion);
- return 0;
+ goto exit;
}
if (unlikely(ehci->debug)) {
@@ -1313,13 +1326,7 @@
&mehci->timer->gptimer1_ctrl);
spin_unlock_irq(&ehci->lock);
- if (pdata && pdata->swfi_latency)
- pm_qos_update_request(&mehci->pm_qos_req_dma,
- pdata->swfi_latency + 1);
wait_for_completion(&mehci->gpt0_completion);
- if (pdata && pdata->standalone_latency)
- pm_qos_update_request(&mehci->pm_qos_req_dma,
- pdata->standalone_latency + 1);
spin_lock_irq(&ehci->lock);
} else {
dbg_log_event(NULL, "FPR: Tightloop", 0);
@@ -1357,9 +1364,11 @@
dbg_log_event(NULL, "FPR: RT-Done", 0);
mehci->resume_status = 1;
+exit:
spin_unlock_irq(&ehci->lock);
-
complete(&mehci->rt_completion);
+ if (next_latency)
+ pm_qos_update_request(&mehci->pm_qos_req_dma, next_latency);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 3b0cd20..a575d6d 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -477,7 +477,6 @@
}
ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
}
- mdss_dsi_op_mode_config(mipi->mode, pdata);
if (pdata->panel_info.type == MIPI_CMD_PANEL) {
if (mipi->vsync_enable && mipi->hw_vsync_mode
@@ -555,9 +554,9 @@
mdss_dsi_sw_reset(pdata);
mdss_dsi_host_init(mipi, pdata);
+ mdss_dsi_op_mode_config(mipi->mode, pdata);
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
- mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
ret = mdss_dsi_unblank(pdata);
if (ret) {
pr_err("%s: unblank failed\n", __func__);
@@ -586,6 +585,8 @@
switch (event) {
case MDSS_EVENT_UNBLANK:
rc = mdss_dsi_on(pdata);
+ mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode,
+ pdata);
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_unblank(pdata);
break;
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 055f233..e48d0d2 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1157,11 +1157,21 @@
dchdr = &cm->dchdr;
mdss_dsi_buf_reserve(tp, len);
len = mdss_dsi_cmd_dma_add(tp, cm);
+ if (!len) {
+ pr_err("%s: failed to call cmd_dma_add\n", __func__);
+ return -EINVAL;
+ }
tot += len;
if (dchdr->last) {
tp->data = tp->start; /* begin of buf */
mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
- mdss_dsi_cmd_dma_tx(ctrl, tp);
+ len = mdss_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(len)) {
+ mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
+ pr_err("%s: failed to call cmd_dma_tx for cmd = 0x%x\n",
+ __func__, cmds->payload[0]);
+ return -EINVAL;
+ }
if (dchdr->wait)
usleep(dchdr->wait * 1000);
@@ -1181,7 +1191,7 @@
struct dsi_cmd_desc *cmds, int cnt)
{
u32 dsi_ctrl, data;
- int video_mode;
+ int video_mode, ret = 0;
u32 left_dsi_ctrl = 0;
bool left_ctrl_restore = false;
@@ -1221,7 +1231,12 @@
MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
}
- mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
+ ret = mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: failed to call\n",
+ __func__);
+ cnt = -EINVAL;
+ }
if (left_ctrl_restore)
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
@@ -1257,7 +1272,7 @@
int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_cmd_desc *cmds, int rlen, u32 rx_flags)
{
- int cnt, len, diff, pkt_size;
+ int cnt, len, diff, pkt_size, ret = 0;
struct dsi_buf *tp, *rp;
int no_max_pkt_size;
char cmd;
@@ -1334,19 +1349,44 @@
/* packet size need to be set at every read */
pkt_size = len;
max_pktsize[0] = pkt_size;
- mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
mdss_dsi_buf_init(tp);
- mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
- mdss_dsi_cmd_dma_tx(ctrl, tp);
+ ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
+ if (!ret) {
+ pr_err("%s: failed to call\n",
+ __func__);
+ rp->len = 0;
+ goto end;
+ }
+ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
+ ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(ret)) {
+ mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
+ pr_err("%s: failed to call\n",
+ __func__);
+ rp->len = 0;
+ goto end;
+ }
pr_debug("%s: Max packet size sent\n", __func__);
}
+ mdss_dsi_buf_init(tp);
+ ret = mdss_dsi_cmd_dma_add(tp, cmds);
+ if (!ret) {
+ pr_err("%s: failed to call cmd_dma_add for cmd = 0x%x\n",
+ __func__, cmds->payload[0]);
+ rp->len = 0;
+ goto end;
+ }
mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
- mdss_dsi_buf_init(tp);
- mdss_dsi_cmd_dma_add(tp, cmds);
-
/* transmit read comamnd to client */
- mdss_dsi_cmd_dma_tx(ctrl, tp);
+ ret = mdss_dsi_cmd_dma_tx(ctrl, tp);
+ if (IS_ERR_VALUE(ret)) {
+ mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM);
+ pr_err("%s: failed to call\n",
+ __func__);
+ rp->len = 0;
+ goto end;
+ }
/*
* once cmd_dma_done interrupt received,
* return data from client is ready and stored
@@ -1378,7 +1418,7 @@
switch (cmd) {
case DTYPE_ACK_ERR_RESP:
pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__);
- break;
+ rp->len = 0;
case DTYPE_GEN_READ1_RESP:
case DTYPE_DCS_READ1_RESP:
mdss_dsi_short_read1_resp(rp);
@@ -1394,10 +1434,10 @@
rp->len -= diff; /* align bytes */
break;
default:
- pr_debug("%s: Unknown cmd received\n", __func__);
- break;
+ pr_warning("%s:Invalid response cmd\n", __func__);
+ rp->len = 0;
}
-
+end:
if (left_ctrl_restore)
MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
left_dsi_ctrl); /*restore */
@@ -1413,7 +1453,7 @@
static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_buf *tp)
{
- int len;
+ int len, ret = 0;
int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
char *bp;
unsigned long size, addr;
@@ -1458,16 +1498,18 @@
MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01); /* trigger */
wmb();
- if (!wait_for_completion_timeout(&ctrl->dma_comp,
- msecs_to_jiffies(DMA_TX_TIMEOUT))) {
- pr_err("%s: dma timeout error\n", __func__);
- }
+ ret = wait_for_completion_timeout(&ctrl->dma_comp,
+ msecs_to_jiffies(DMA_TX_TIMEOUT));
+ if (ret == 0)
+ ret = -ETIMEDOUT;
+ else
+ ret = tp->len;
if (is_mdss_iommu_attached())
msm_iommu_unmap_contig_buffer(addr,
mdss_get_iommu_domain(domain), 0, size);
- return tp->len;
+ return ret;
}
static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index b5a5383..f44ebaf 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1337,7 +1337,7 @@
* writeback block
*/
head[len] = head[len - 1];
- head[len].num = -1;
+ head[len].num = head[len - 1].num;
}
mdata->ctl_off = head;
diff --git a/drivers/video/msm/mdss/mhl_msc.c b/drivers/video/msm/mdss/mhl_msc.c
index d0f93cf..e7cd1be 100644
--- a/drivers/video/msm/mdss/mhl_msc.c
+++ b/drivers/video/msm/mdss/mhl_msc.c
@@ -74,6 +74,22 @@
}
}
+static bool mhl_qualify_path_enable(struct mhl_tx_ctrl *mhl_ctrl)
+{
+ int rc = false;
+
+ if (!mhl_ctrl)
+ return rc;
+
+ if (mhl_ctrl->tmds_en_state ||
+ /* Identify sink with non-standard INT STAT SIZE */
+ (mhl_ctrl->devcap[DEVCAP_OFFSET_MHL_VERSION] == 0x10 &&
+ mhl_ctrl->devcap[DEVCAP_OFFSET_INT_STAT_SIZE] == 0x44))
+ rc = true;
+
+ return rc;
+}
+
void mhl_register_msc(struct mhl_tx_ctrl *ctrl)
{
if (ctrl)
@@ -253,6 +269,11 @@
mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
mhl_drive_hpd(mhl_ctrl, HPD_UP);
break;
+ case DEVCAP_OFFSET_MHL_VERSION:
+ case DEVCAP_OFFSET_INT_STAT_SIZE:
+ if (mhl_qualify_path_enable(mhl_ctrl))
+ mhl_tmds_ctrl(mhl_ctrl, TMDS_ENABLE);
+ break;
}
break;
case MHL_WRITE_BURST:
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index add15a4..c66d50d 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -794,10 +794,14 @@
void mhl_tmds_ctrl(struct mhl_tx_ctrl *mhl_ctrl, uint8_t on)
{
struct i2c_client *client = mhl_ctrl->i2c_handle;
- if (on)
+
+ if (on) {
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, BIT4);
- else
+ mhl_ctrl->tmds_en_state = true;
+ } else {
MHL_SII_REG_NAME_MOD(REG_TMDS_CCTRL, BIT4, 0x00);
+ mhl_ctrl->tmds_en_state = false;
+ }
}
void mhl_drive_hpd(struct mhl_tx_ctrl *mhl_ctrl, uint8_t to_state)
diff --git a/include/linux/cm36283.h b/include/linux/cm36283.h
new file mode 100644
index 0000000..cccd5ee
--- /dev/null
+++ b/include/linux/cm36283.h
@@ -0,0 +1,121 @@
+/* include/linux/cm36283.h
+ *
+ * Copyright (C) 2012 Capella Microsystems Inc.
+ * Author: Frank Hsieh <pengyueh@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_CM36283_H
+#define __LINUX_CM36283_H
+
+#define CM36283_I2C_NAME "cm36283"
+
+/* Define Slave Address*/
+#define CM36283_slave_add 0xC0>>1
+
+#define ALS_CALIBRATED 0x6E9F
+#define PS_CALIBRATED 0x509F
+
+/*Define Command Code*/
+#define ALS_CONF 0x00
+#define ALS_THDH 0x01
+#define ALS_THDL 0x02
+#define PS_CONF1 0x03
+#define PS_CONF3 0x04
+#define PS_CANC 0x05
+#define PS_THD 0x06
+#define RESERVED 0x07
+
+#define PS_DATA 0x08
+#define ALS_DATA 0x09
+#define RESERVED2 0x0A
+#define INT_FLAG 0x0B
+#define ID_REG 0x0C
+
+/*cm36283*/
+/*for ALS CONF command*/
+#define CM36283_ALS_IT_80ms (0 << 6)
+#define CM36283_ALS_IT_160ms (1 << 6)
+#define CM36283_ALS_IT_320ms (2 << 6)
+#define CM36283_ALS_IT_640ms (3 << 6)
+#define CM36283_ALS_GAIN_1 (0 << 2)
+#define CM36283_ALS_GAIN_2 (1 << 2)
+#define CM36283_ALS_GAIN_4 (2 << 2)
+#define CM36283_ALS_GAIN_8 (3 << 2)
+#define CM36283_ALS_INT_EN (1 << 1) /*enable/disable Interrupt*/
+#define CM36283_ALS_INT_MASK 0xFFFD
+#define CM36283_ALS_SD (1 << 0) /*enable/disable ALS func, 1:disable , 0: enable*/
+#define CM36283_ALS_SD_MASK 0xFFFE
+
+/*for PS CONF1 command*/
+#define CM36283_PS_ITB_1_2 (0 << 14)
+#define CM36283_PS_ITB_1 (1 << 14)
+#define CM36283_PS_ITB_2 (2 << 14)
+#define CM36283_PS_ITB_4 (3 << 14)
+#define CM36283_PS_INT_OFF (0 << 8) /*enable/disable Interrupt*/
+#define CM36283_PS_INT_IN (1 << 8)
+#define CM36283_PS_INT_OUT (2 << 8)
+#define CM36283_PS_INT_IN_AND_OUT (3 << 8)
+
+#define CM36283_PS_INT_MASK 0xFCFF
+
+#define CM36283_PS_DR_1_40 (0 << 6)
+#define CM36283_PS_DR_1_80 (1 << 6)
+#define CM36283_PS_DR_1_160 (2 << 6)
+#define CM36283_PS_DR_1_320 (3 << 6)
+#define CM36283_PS_IT_1T (0 << 4)
+#define CM36283_PS_IT_1_3T (1 << 4)
+#define CM36283_PS_IT_1_6T (2 << 4)
+#define CM36283_PS_IT_2T (3 << 4)
+#define CM36283_PS_PERS_1 (0 << 2)
+#define CM36283_PS_PERS_2 (1 << 2)
+#define CM36283_PS_PERS_3 (2 << 2)
+#define CM36283_PS_PERS_4 (3 << 2)
+#define CM36283_PS_RES_1 (1 << 1)
+#define CM36283_PS_SD (1 << 0)/*enable/disable PS func, 1:disable , 0: enable*/
+#define CM36283_PS_SD_MASK 0xFFFE
+
+/*for PS CONF3 command*/
+#define CM36283_PS_MS_NORMAL (0 << 14)
+#define CM36283_PS_MS_LOGIC_ENABLE (1 << 14)
+#define CM36283_PS_PROL_63 (0 << 12)
+#define CM36283_PS_PROL_127 (1 << 12)
+#define CM36283_PS_PROL_191 (2 << 12)
+#define CM36283_PS_PROL_255 (3 << 12)
+#define CM36283_PS_SMART_PERS_ENABLE (1 << 4)
+#define CM36283_PS_ACTIVE_FORCE_MODE (1 << 3)
+#define CM36283_PS_ACTIVE_FORCE_TRIG (1 << 2)
+
+/*for INT FLAG*/
+#define INT_FLAG_PS_SPFLAG (1<<14)
+#define INT_FLAG_ALS_IF_L (1<<13)
+#define INT_FLAG_ALS_IF_H (1<<12)
+#define INT_FLAG_PS_IF_CLOSE (1<<9)
+#define INT_FLAG_PS_IF_AWAY (1<<8)
+
+extern unsigned int ps_kparam1;
+extern unsigned int ps_kparam2;
+
+struct cm36283_platform_data {
+ int intr;
+ uint16_t levels[10];
+ uint16_t golden_adc;
+ int (*power)(int, uint8_t); /* power to the chip */
+ uint8_t slave_addr;
+ uint8_t ps_close_thd_set;
+ uint8_t ps_away_thd_set;
+ uint16_t ls_cmd;
+ uint16_t ps_conf1_val;
+ uint16_t ps_conf3_val;
+};
+
+#endif
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index f0a54eb..d1ee11c 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -149,6 +149,7 @@
uint16_t devcap_state;
uint8_t status[2];
uint8_t path_en_state;
+ uint8_t tmds_en_state;
void *hdmi_mhl_ops;
struct work_struct mhl_msc_send_work;
struct list_head list_cmd;
diff --git a/include/linux/stk3x1x.h b/include/linux/stk3x1x.h
new file mode 100644
index 0000000..c34116a
--- /dev/null
+++ b/include/linux/stk3x1x.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * $Id: stk3x1x.h
+ *
+ * Copyright (C) 2012 Lex Hsieh <lex_hsieh@sitronix.com.tw>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+#ifndef __STK3X1X_H__
+#define __STK3X1X_H__
+
+/* platform data */
+struct stk3x1x_platform_data
+{
+ uint8_t state_reg;
+ uint8_t psctrl_reg;
+ uint8_t alsctrl_reg;
+ uint8_t ledctrl_reg;
+ uint8_t wait_reg;
+ uint16_t ps_thd_h;
+ uint16_t ps_thd_l;
+ int int_pin;
+ uint32_t transmittance;
+};
+
+#endif // __STK3X1X_H__