CAP1106: Fine tune params based on BODYSAR, add APP2MDM_SAR support, code refinement.
Change-Id: Ic7499b0dc1a5005cc6dfba29d061bd4164cd4a7a Signed-off-by: tryout_chen <tryout_chen@asus.com>
This commit is contained in:
committed by
Android Partner Code Review
parent
c6833ee6ee
commit
c7b57708c1
@@ -102,7 +102,6 @@
|
|||||||
#define NFC_GPIO_VEN PM8921_GPIO_PM_TO_SYS(9)
|
#define NFC_GPIO_VEN PM8921_GPIO_PM_TO_SYS(9)
|
||||||
#define NFC_GPIO_WAKE PM8921_GPIO_PM_TO_SYS(8)
|
#define NFC_GPIO_WAKE PM8921_GPIO_PM_TO_SYS(8)
|
||||||
#define NFC_GPIO_IRQ 32
|
#define NFC_GPIO_IRQ 32
|
||||||
#define CAP1106_GPIO_IRQ 52
|
|
||||||
|
|
||||||
static int config_nfc_gpio(void)
|
static int config_nfc_gpio(void)
|
||||||
{
|
{
|
||||||
@@ -150,16 +149,49 @@ static void nfc_init(void) {
|
|||||||
ARRAY_SIZE(i2c_bcm2079x));
|
ARRAY_SIZE(i2c_bcm2079x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SENSORS_CAP1106
|
||||||
|
#include <linux/i2c/cap1106.h>
|
||||||
|
|
||||||
|
static struct cap1106_i2c_platform_data cap1106_pdata = {
|
||||||
|
.app2mdm_enable = 0,
|
||||||
|
.sar_gpio = CAP1106_SAR_GPIO,
|
||||||
|
.sar_gpio_name = CAP1106_SAR_GPIO_NAME,
|
||||||
|
.det_gpio = CAP1106_DET_GPIO,
|
||||||
|
.det_gpio_name = CAP1106_DET_GPIO_NAME,
|
||||||
|
.init_table = {
|
||||||
|
0x1F, 0x1F, // Data sensitivity
|
||||||
|
0x20, 0x20, // MAX duration disable
|
||||||
|
0x21, 0x22, // Enable CS2+CS6.
|
||||||
|
0x22, 0xFF, // MAX duration time to max , repeat period time to max
|
||||||
|
0x24, 0x39, // Digital count update time to 140*64ms
|
||||||
|
0x27, 0x22, // Enable INT. for CS2+CS6.
|
||||||
|
0x28, 0x22, // Disable repeat irq
|
||||||
|
0x2A, 0x00, // All channel run in the same time
|
||||||
|
0x31, 0x0A, // Threshold of CS 2
|
||||||
|
0x35, 0x0A, // Threshold of CS 6
|
||||||
|
0x26, 0x22, // Force re-cal CS2+CS6
|
||||||
|
0x00, 0xC0, // Reset INT. bit.
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static struct i2c_board_info i2c_cap1106[] __initdata = {
|
static struct i2c_board_info i2c_cap1106[] __initdata = {
|
||||||
{
|
{
|
||||||
I2C_BOARD_INFO("cap1106", 0x28),
|
I2C_BOARD_INFO(CAP1106_I2C_NAME, 0x28),
|
||||||
.irq = MSM_GPIO_TO_INT(CAP1106_GPIO_IRQ),
|
.irq = MSM_GPIO_TO_INT(CAP1106_DET_GPIO),
|
||||||
|
.platform_data = &cap1106_pdata,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void cap1106_init(void) {
|
static void cap1106_init(void) {
|
||||||
i2c_register_board_info(APQ_8064_GSBI1_QUP_I2C_BUS_ID,
|
struct cap1106_i2c_platform_data *pdata;
|
||||||
i2c_cap1106,
|
|
||||||
|
pdata = (struct cap1106_i2c_platform_data *) i2c_cap1106[0].platform_data;
|
||||||
|
if ((asustek_get_hw_rev() == HW_REV_C)
|
||||||
|
|| (asustek_get_hw_rev() == HW_REV_D)) {
|
||||||
|
pdata->app2mdm_enable = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_register_board_info(APQ_8064_GSBI1_QUP_I2C_BUS_ID, i2c_cap1106,
|
||||||
ARRAY_SIZE(i2c_cap1106));
|
ARRAY_SIZE(i2c_cap1106));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,13 +223,13 @@ static void enable_cap1106_regulator(void) {
|
|||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("%s: regulator_enable of %s failed(%d)\n",
|
pr_err("%s: regulator_enable of %s failed(%d)\n",
|
||||||
__func__, vdd_name, rc);
|
__func__, vdd_name, rc);
|
||||||
//goto reg_put_LDO_CAP1106;
|
|
||||||
regulator_put(pm8921_cap1106);
|
regulator_put(pm8921_cap1106);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_info("enable_cap1106_regulator() >>\n");
|
pr_info("enable_cap1106_regulator() >>\n");
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_SENSORS_CAP1106 */
|
||||||
|
|
||||||
#define MSM_PMEM_ADSP_SIZE 0x7800000
|
#define MSM_PMEM_ADSP_SIZE 0x7800000
|
||||||
#define MSM_PMEM_AUDIO_SIZE 0x4CF000
|
#define MSM_PMEM_AUDIO_SIZE 0x4CF000
|
||||||
@@ -3385,10 +3417,12 @@ static void __init apq8064_common_init(void)
|
|||||||
|
|
||||||
if (machine_is_apq8064_flo() || machine_is_apq8064_deb())
|
if (machine_is_apq8064_flo() || machine_is_apq8064_deb())
|
||||||
nfc_init();
|
nfc_init();
|
||||||
|
#ifdef CONFIG_SENSORS_CAP1106
|
||||||
if (machine_is_apq8064_deb()) {
|
if (machine_is_apq8064_deb()) {
|
||||||
enable_cap1106_regulator();
|
enable_cap1106_regulator();
|
||||||
cap1106_init();
|
cap1106_init();
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_SENSORS_CAP1106 */
|
||||||
#ifdef CONFIG_SLIMPORT_ANX7808
|
#ifdef CONFIG_SLIMPORT_ANX7808
|
||||||
add_i2c_anx7808_device();
|
add_i2c_anx7808_device();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
683
drivers/hwmon/cap1106.c
Normal file → Executable file
683
drivers/hwmon/cap1106.c
Normal file → Executable file
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* An I2C driver for SMSC Proximity Sensor CAP1106.
|
* An I2C driver for SMSC CAP1106.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012, ASUSTek Corporation.
|
* Copyright (c) 2013, ASUSTek Corporation.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -22,60 +22,54 @@
|
|||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
|
#include <linux/i2c/cap1106.h>
|
||||||
|
|
||||||
MODULE_DESCRIPTION("SMSC Proximity Sensor CAP1106 Driver");
|
/*
|
||||||
MODULE_LICENSE("GPL");
|
* Debug Utility
|
||||||
|
*/
|
||||||
|
#define CAP_DEBUG(fmt, arg...) \
|
||||||
|
pr_debug("CAP1106: [%s] " fmt , __func__ , ##arg)
|
||||||
|
#define CAP_INFO(fmt, arg...) \
|
||||||
|
pr_info("CAP1106: [%s] " fmt , __func__ , ##arg)
|
||||||
|
#define CAP_ERROR(fmt, arg...) \
|
||||||
|
pr_err("CAP1106: [%s] " fmt , __func__ , ##arg)
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
#define CAP_SDEV_NAME "ril_proximity"
|
||||||
** Debug Utility
|
|
||||||
**----------------------------------------------------------------------------*/
|
|
||||||
#define PROX_SENSOR_DEBUG 0
|
|
||||||
#define PROX_SENSOR_VERBOSE_DEBUG 0
|
|
||||||
|
|
||||||
#if PROX_SENSOR_DEBUG
|
/*
|
||||||
#define PROX_DEBUG(format, arg...) \
|
* Global Variable
|
||||||
printk(KERN_INFO "CAP1106: [%s] " format , __FUNCTION__ , ## arg)
|
*/
|
||||||
#else
|
|
||||||
#define PROX_DEBUG(format, arg...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PROX_INFO(format, arg...) \
|
|
||||||
printk(KERN_INFO "CAP1106: [%s] " format , __FUNCTION__ , ## arg)
|
|
||||||
#define PROX_ERROR(format, arg...) \
|
|
||||||
printk(KERN_ERR "CAP1106: [%s] " format , __FUNCTION__ , ## arg)
|
|
||||||
|
|
||||||
#define SAR_DET_3G 52
|
|
||||||
#define NAME_RIL_PROX "ril_proximity"
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
|
||||||
** Global Variable
|
|
||||||
**----------------------------------------------------------------------------*/
|
|
||||||
struct cap1106_data {
|
struct cap1106_data {
|
||||||
struct attribute_group attrs;
|
struct attribute_group attrs;
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
|
struct workqueue_struct *cap_wq;
|
||||||
struct delayed_work work;
|
struct delayed_work work;
|
||||||
struct delayed_work checking_work;
|
struct delayed_work checking_work;
|
||||||
int enable;
|
int enable;
|
||||||
int obj_detect;
|
int obj_detect;
|
||||||
int overflow_status;
|
int overflow_status;
|
||||||
|
int app2mdm_enable;
|
||||||
|
int sar_gpio;
|
||||||
|
char *sar_gpio_name;
|
||||||
|
int det_gpio;
|
||||||
|
char *det_gpio_name;
|
||||||
|
const unsigned char *init_table;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_MUTEX(prox_mtx);
|
static DEFINE_MUTEX(cap_mtx);
|
||||||
static struct cap1106_data *prox_data;
|
static struct cap1106_data *pivate_data;
|
||||||
static struct workqueue_struct *prox_wq;
|
static struct switch_dev cap_sdev;
|
||||||
static struct switch_dev prox_sdev;
|
|
||||||
static long checking_work_period = 100; //default (ms)
|
|
||||||
static int is_wood_sensitivity = 0;
|
static int is_wood_sensitivity = 0;
|
||||||
static int ac2 = 0; // Accumulated Count Ch2
|
static int ac2 = 0; // Accumulated Count Ch2
|
||||||
//static int ac3 = 0; // Accumulated Count Ch3
|
|
||||||
static int ac6 = 0; // Accumulated Count Ch6
|
static int ac6 = 0; // Accumulated Count Ch6
|
||||||
static int ac_limit = 10;
|
static int ac_limit = 10;
|
||||||
static int force_enable = 1;
|
static int force_enable = 1;
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*
|
||||||
** FUNCTION DECLARATION
|
* Function Declaration
|
||||||
**----------------------------------------------------------------------------*/
|
*/
|
||||||
static int __devinit cap1106_probe(struct i2c_client *client, const struct i2c_device_id *id);
|
static int __devinit cap1106_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id);
|
||||||
static int __devexit cap1106_remove(struct i2c_client *client);
|
static int __devexit cap1106_remove(struct i2c_client *client);
|
||||||
static int cap1106_suspend(struct i2c_client *client, pm_message_t mesg);
|
static int cap1106_suspend(struct i2c_client *client, pm_message_t mesg);
|
||||||
static int cap1106_resume(struct i2c_client *client);
|
static int cap1106_resume(struct i2c_client *client);
|
||||||
@@ -88,21 +82,23 @@ static void cap1106_work_function(struct work_struct *work);
|
|||||||
static int cap1106_init_sensor(struct i2c_client *client);
|
static int cap1106_init_sensor(struct i2c_client *client);
|
||||||
static int cap1106_config_irq(struct i2c_client *client);
|
static int cap1106_config_irq(struct i2c_client *client);
|
||||||
static void cap1106_enable_sensor(struct i2c_client *client, int enable);
|
static void cap1106_enable_sensor(struct i2c_client *client, int enable);
|
||||||
static ssize_t show_attrs_handler(struct device *dev, struct device_attribute *devattr, char *buf);
|
static ssize_t show_attrs_handler(struct device *dev,
|
||||||
static ssize_t store_attrs_handler(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
|
struct device_attribute *devattr, char *buf);
|
||||||
|
static ssize_t store_attrs_handler(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t count);
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------
|
/*
|
||||||
** I2C Driver Structure
|
* I2C Driver Structure
|
||||||
**----------------------------------------------------------------------------*/
|
*/
|
||||||
static const struct i2c_device_id cap1106_id[] = {
|
static const struct i2c_device_id cap1106_id[] = {
|
||||||
{"cap1106", 0},
|
{ CAP1106_I2C_NAME, 0 },
|
||||||
{}
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, cap1106_id);
|
MODULE_DEVICE_TABLE(i2c, cap1106_id);
|
||||||
|
|
||||||
static struct i2c_driver cap1106_driver = {
|
static struct i2c_driver cap1106_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "cap1106",
|
.name = CAP1106_I2C_NAME,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
},
|
},
|
||||||
.probe = cap1106_probe,
|
.probe = cap1106_probe,
|
||||||
@@ -127,8 +123,8 @@ DEVICE_ATTR(sensor_input_status, 0644, show_attrs_handler, NULL);
|
|||||||
DEVICE_ATTR(sensing_cycle, 0644, show_attrs_handler, store_attrs_handler);
|
DEVICE_ATTR(sensing_cycle, 0644, show_attrs_handler, store_attrs_handler);
|
||||||
DEVICE_ATTR(sensor_onoff, 0644, show_attrs_handler, store_attrs_handler);
|
DEVICE_ATTR(sensor_onoff, 0644, show_attrs_handler, store_attrs_handler);
|
||||||
DEVICE_ATTR(sensor_recal, 0644, show_attrs_handler, store_attrs_handler);
|
DEVICE_ATTR(sensor_recal, 0644, show_attrs_handler, store_attrs_handler);
|
||||||
//DEVICE_ATTR(sensor_input_3_delta_count, 0644, show_attrs_handler, NULL);
|
DEVICE_ATTR(sensor_app2mdm_sar, 0644, NULL, store_attrs_handler);
|
||||||
//DEVICE_ATTR(sensor_input_3_th, 0644, show_attrs_handler, store_attrs_handler);
|
DEVICE_ATTR(sensor_main, 0644, show_attrs_handler, NULL);
|
||||||
|
|
||||||
static struct attribute *cap1106_attr_deb[] = {
|
static struct attribute *cap1106_attr_deb[] = {
|
||||||
&dev_attr_obj_detect.attr, // 1
|
&dev_attr_obj_detect.attr, // 1
|
||||||
@@ -143,104 +139,117 @@ static struct attribute *cap1106_attr_deb[] = {
|
|||||||
&dev_attr_sensing_cycle.attr, // 10
|
&dev_attr_sensing_cycle.attr, // 10
|
||||||
&dev_attr_sensor_onoff.attr, // 11
|
&dev_attr_sensor_onoff.attr, // 11
|
||||||
&dev_attr_sensor_recal.attr, // 12
|
&dev_attr_sensor_recal.attr, // 12
|
||||||
//&dev_attr_sensor_input_3_delta_count.attr, // 13
|
&dev_attr_sensor_app2mdm_sar.attr, // 13
|
||||||
//&dev_attr_sensor_input_3_th.attr, // 14
|
&dev_attr_sensor_main.attr, // 14
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t show_attrs_handler(struct device *dev, struct device_attribute *devattr, char *buf)
|
static ssize_t show_attrs_handler(struct device *dev,
|
||||||
|
struct device_attribute *devattr, char *buf)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct cap1106_data *data = i2c_get_clientdata(client);
|
struct cap1106_data *data = i2c_get_clientdata(client);
|
||||||
const char *attr_name = devattr->attr.name;
|
const char *attr_name = devattr->attr.name;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
PROX_DEBUG("=== devattr->attr->name: %s\n", devattr->attr.name);
|
CAP_DEBUG("devattr->attr->name: %s\n", devattr->attr.name);
|
||||||
|
|
||||||
mutex_lock(&prox_mtx);
|
mutex_lock(&cap_mtx);
|
||||||
if (data->enable) {
|
if (data->enable) {
|
||||||
if (!strcmp(attr_name, dev_attr_obj_detect.attr.name)) { // 1
|
if (!strcmp(attr_name, dev_attr_obj_detect.attr.name)) {
|
||||||
ret = sprintf(buf, "%d\n", data->obj_detect);
|
ret = sprintf(buf, "%d\n", data->obj_detect);
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensitivity.attr.name)) { // 2
|
} else if (!strcmp(attr_name, dev_attr_sensitivity.attr.name)) {
|
||||||
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x1F));
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x1F));
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_gain.attr.name)) { // 3
|
} else if (!strcmp(attr_name, dev_attr_sensor_gain.attr.name)) {
|
||||||
ret = sprintf(buf, "%02X\n", (cap1106_read_reg(client, 0x00) & 0xC0) >> 6);
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x00) >> 6);
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_input_2_delta_count.attr.name)) { // 4
|
} else if (!strcmp(attr_name,
|
||||||
|
dev_attr_sensor_input_2_delta_count.attr.name)) {
|
||||||
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x11));
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x11));
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_input_2_th.attr.name)) { // 5
|
} else if (!strcmp(attr_name, dev_attr_sensor_input_2_th.attr.name)) {
|
||||||
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x31));
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x31));
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_input_6_delta_count.attr.name)) { // 6
|
} else if (!strcmp(attr_name,
|
||||||
|
dev_attr_sensor_input_6_delta_count.attr.name)) {
|
||||||
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x15));
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x15));
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_input_6_th.attr.name)) { // 7
|
} else if (!strcmp(attr_name, dev_attr_sensor_input_6_th.attr.name)) {
|
||||||
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x35));
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x35));
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_input_noise_th.attr.name)) { // 8
|
} else if (!strcmp(attr_name,
|
||||||
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x38) & 0x3);
|
dev_attr_sensor_input_noise_th.attr.name)) {
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_input_status.attr.name)) { // 9
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x38));
|
||||||
|
} else if (!strcmp(attr_name, dev_attr_sensor_input_status.attr.name)) {
|
||||||
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x03));
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x03));
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensing_cycle.attr.name)) { // 10
|
} else if (!strcmp(attr_name, dev_attr_sensing_cycle.attr.name)) {
|
||||||
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x24));
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x24));
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_onoff.attr.name)) { // 11
|
} else if (!strcmp(attr_name, dev_attr_sensor_onoff.attr.name)) {
|
||||||
ret = sprintf(buf, "%d\n", data->enable);
|
ret = sprintf(buf, "%d\n", data->enable);
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_recal.attr.name)) { // 12
|
} else if (!strcmp(attr_name, dev_attr_sensor_recal.attr.name)) {
|
||||||
ret = sprintf(buf, cap1106_read_reg(client, 0x26) == 0x0 ? "OK\n" : "FAIL\n");
|
ret = sprintf(buf,
|
||||||
}// else if (!strcmp(attr_name, dev_attr_sensor_input_3_delta_count.attr.name)) { // 13
|
cap1106_read_reg(client, 0x26) == 0x0 ? "OK\n" : "FAIL\n");
|
||||||
// ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x12));
|
} else if (!strcmp(attr_name, dev_attr_sensor_main.attr.name)) {
|
||||||
//} else if (!strcmp(attr_name, dev_attr_sensor_input_3_th.attr.name)) { // 14
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x00));
|
||||||
// ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x32));
|
}
|
||||||
//}
|
} else {
|
||||||
|
if (!strcmp(attr_name, dev_attr_sensor_main.attr.name)) {
|
||||||
|
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x00));
|
||||||
} else {
|
} else {
|
||||||
ret = sprintf(buf, "SENSOR DISABLED\n");
|
ret = sprintf(buf, "SENSOR DISABLED\n");
|
||||||
}
|
}
|
||||||
mutex_unlock(&prox_mtx);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mutex_unlock(&cap_mtx);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t store_attrs_handler(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count)
|
static ssize_t store_attrs_handler(struct device *dev,
|
||||||
|
struct device_attribute *devattr, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct cap1106_data *data = i2c_get_clientdata(client);
|
struct cap1106_data *data = i2c_get_clientdata(client);
|
||||||
const char *attr_name = devattr->attr.name;
|
const char *attr_name = devattr->attr.name;
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
|
|
||||||
if (strict_strtoul(buf, 16, &value))
|
if (strict_strtoul(buf, 16, &value)) return -EINVAL;
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
PROX_DEBUG("=== devattr->attr->name: %s, value: %lu\n", devattr->attr.name, value);
|
CAP_DEBUG("devattr->attr->name: %s, value: 0x%lX\n",
|
||||||
|
devattr->attr.name, value);
|
||||||
|
|
||||||
mutex_lock(&prox_mtx);
|
mutex_lock(&cap_mtx);
|
||||||
if (data->enable) {
|
if (data->enable) {
|
||||||
if (!strcmp(attr_name, dev_attr_sensitivity.attr.name)) { // 2
|
if (!strcmp(attr_name, dev_attr_sensitivity.attr.name)) {
|
||||||
cap1106_write_reg(client, 0x1F, value & 0x7F);
|
cap1106_write_reg(client, 0x1F, value & 0x7F);
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_gain.attr.name)) { // 3
|
} else if (!strcmp(attr_name, dev_attr_sensor_gain.attr.name)) {
|
||||||
cap1106_write_reg(client, 0x00, (cap1106_read_reg(client, 0x00) & 0x3F) | ((cap1106_read_reg(client, 0x00) & 0x3) << 6));
|
cap1106_write_reg(client, 0x00,
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_input_2_th.attr.name)) { // 5
|
(cap1106_read_reg(client, 0x00) & 0x3F) | ((value & 0x03) << 6));
|
||||||
|
} else if (!strcmp(attr_name, dev_attr_sensor_input_2_th.attr.name)) {
|
||||||
cap1106_write_reg(client, 0x31, value & 0x7F);
|
cap1106_write_reg(client, 0x31, value & 0x7F);
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_input_6_th.attr.name)) { // 7
|
} else if (!strcmp(attr_name, dev_attr_sensor_input_6_th.attr.name)) {
|
||||||
cap1106_write_reg(client, 0x35, value & 0x7F);
|
cap1106_write_reg(client, 0x35, value & 0x7F);
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_input_noise_th.attr.name)) { // 8
|
} else if (!strcmp(attr_name,
|
||||||
cap1106_write_reg(client, 0x38, value & 0x3);
|
dev_attr_sensor_input_noise_th.attr.name)) {
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensing_cycle.attr.name)) { // 10
|
cap1106_write_reg(client, 0x38, value & 0x03);
|
||||||
|
} else if (!strcmp(attr_name, dev_attr_sensing_cycle.attr.name)) {
|
||||||
cap1106_write_reg(client, 0x24, value & 0x7F);
|
cap1106_write_reg(client, 0x24, value & 0x7F);
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_onoff.attr.name)) { // 11
|
} else if (!strcmp(attr_name, dev_attr_sensor_onoff.attr.name)) {
|
||||||
if ((value == 0) || (value == 1)) {
|
if (value == 0) {
|
||||||
force_enable = value;
|
force_enable = 0;
|
||||||
cap1106_enable_sensor(client, value);
|
cap1106_enable_sensor(client, 0);
|
||||||
}
|
}
|
||||||
} else if (!strcmp(attr_name, dev_attr_sensor_recal.attr.name)) { // 12
|
} else if (!strcmp(attr_name, dev_attr_sensor_recal.attr.name)) {
|
||||||
cap1106_write_reg(client, 0x26, 0x22);
|
cap1106_write_reg(client, 0x26, 0x22);
|
||||||
}// else if (!strcmp(attr_name, dev_attr_sensor_input_3_th.attr.name)) { // 14
|
} else if (!strcmp(attr_name, dev_attr_sensor_app2mdm_sar.attr.name)) {
|
||||||
// cap1106_write_reg(client, 0x32, value & 0x7F);
|
gpio_set_value(data->sar_gpio, value);
|
||||||
//}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!strcmp(attr_name, dev_attr_sensor_onoff.attr.name)) { // 11
|
if (!strcmp(attr_name, dev_attr_sensor_onoff.attr.name)) {
|
||||||
if ((value == 0) || (value == 1)) {
|
if (value == 1) {
|
||||||
force_enable = value;
|
force_enable = 1;
|
||||||
cap1106_enable_sensor(client, value);
|
cap1106_enable_sensor(client, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&prox_mtx);
|
mutex_unlock(&cap_mtx);
|
||||||
|
|
||||||
return strnlen(buf, count);;
|
return strnlen(buf, count);;
|
||||||
}
|
}
|
||||||
@@ -249,48 +258,20 @@ static ssize_t store_attrs_handler(struct device *dev, struct device_attribute *
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Callbacks for switch device
|
// Callbacks for switch device
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
static ssize_t print_prox_name(struct switch_dev *sdev, char *buf)
|
static ssize_t print_cap_name(struct switch_dev *sdev, char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%s\n", "prox_sar_det");
|
return sprintf(buf, "%s\n", "prox_sar_det");
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t print_prox_state(struct switch_dev *sdev, char *buf)
|
static ssize_t print_cap_state(struct switch_dev *sdev, char *buf)
|
||||||
{
|
{
|
||||||
int state = -1;
|
|
||||||
if (switch_get_state(sdev))
|
if (switch_get_state(sdev))
|
||||||
state = 1;
|
return sprintf(buf, "1\n");
|
||||||
else
|
else
|
||||||
state = 0;
|
return sprintf(buf, "0\n");
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", state);
|
|
||||||
}
|
}
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#if PROX_SENSOR_VERBOSE_DEBUG
|
|
||||||
static void dump_registers(struct i2c_client *client)
|
|
||||||
{
|
|
||||||
int value;
|
|
||||||
value = cap1106_read_reg(client, 0x00);
|
|
||||||
PROX_ERROR("=== Main Control(0x00) is %x\n", value);
|
|
||||||
value = cap1106_read_reg(client, 0x02);
|
|
||||||
PROX_ERROR("=== Genaral Status(0x02) is %x\n", value);
|
|
||||||
value = cap1106_read_reg(client, 0x03);
|
|
||||||
PROX_ERROR("=== Sensor Input Status(0x03) is %x\n", value);
|
|
||||||
value = cap1106_read_reg(client, 0x0A);
|
|
||||||
PROX_ERROR("=== Noise Flag Status(0x0A) is %x\n", value);
|
|
||||||
value = cap1106_read_reg(client, 0x21);
|
|
||||||
PROX_ERROR("=== Sensor Input Enable Register(0x21) is %x\n", value);
|
|
||||||
value = cap1106_read_reg(client, 0x44);
|
|
||||||
PROX_ERROR("=== configuration 2(0x44) is %x\n", value);
|
|
||||||
value = cap1106_read_reg(client, 0xFD);
|
|
||||||
PROX_ERROR("=== Product ID(0xFD) is %x\n", value);
|
|
||||||
value = cap1106_read_reg(client, 0xFE);
|
|
||||||
PROX_ERROR("=== Manufacturer ID(0xFE) is %x\n", value);
|
|
||||||
value = cap1106_read_reg(client, 0xFF);
|
|
||||||
PROX_ERROR("=== Revision (0xFF) is %x\n", value);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void cap1106_enable_sensor(struct i2c_client *client, int enable)
|
static void cap1106_enable_sensor(struct i2c_client *client, int enable)
|
||||||
{
|
{
|
||||||
long reg_value;
|
long reg_value;
|
||||||
@@ -300,20 +281,24 @@ static void cap1106_enable_sensor(struct i2c_client *client, int enable)
|
|||||||
if (data->enable != enable) {
|
if (data->enable != enable) {
|
||||||
reg_value = cap1106_read_reg(client, 0x00);
|
reg_value = cap1106_read_reg(client, 0x00);
|
||||||
if (enable) {
|
if (enable) {
|
||||||
cap1106_write_reg(client, 0x00, (reg_value & 0xEF) | (!enable << 4));
|
cap1106_write_reg(client, 0x00, reg_value & 0xCE);
|
||||||
// Time to first conversion is 200ms (Max)
|
// Time to first conversion is 200ms (Max)
|
||||||
queue_delayed_work(prox_wq, &data->work, msecs_to_jiffies(200));
|
queue_delayed_work(data->cap_wq, &data->work,
|
||||||
|
msecs_to_jiffies(200));
|
||||||
enable_irq(client->irq);
|
enable_irq(client->irq);
|
||||||
queue_delayed_work(prox_wq, &prox_data->checking_work, checking_work_period);
|
queue_delayed_work(data->cap_wq, &data->checking_work,
|
||||||
|
msecs_to_jiffies(500));
|
||||||
} else {
|
} else {
|
||||||
disable_irq(client->irq);
|
disable_irq(client->irq);
|
||||||
cancel_delayed_work_sync(&data->work);
|
cancel_delayed_work_sync(&data->work);
|
||||||
cancel_delayed_work_sync(&data->checking_work);
|
cancel_delayed_work_sync(&data->checking_work);
|
||||||
flush_workqueue(prox_wq);
|
flush_workqueue(data->cap_wq);
|
||||||
switch_set_state(&prox_sdev, 0);
|
switch_set_state(&cap_sdev, 0);
|
||||||
cap1106_write_reg(client, 0x00, (reg_value & 0xEF) | (!enable << 4));
|
cap1106_write_reg(client, 0x00, reg_value | 0x30);
|
||||||
}
|
}
|
||||||
data->enable = enable;
|
data->enable = enable;
|
||||||
|
|
||||||
|
CAP_INFO("data->enable: %d\n", data->enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,366 +315,334 @@ static s32 cap1106_write_reg(struct i2c_client *client, u8 command, u8 value)
|
|||||||
static void cap1106_work_function(struct work_struct *work)
|
static void cap1106_work_function(struct work_struct *work)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
//int dc2, dc3, dc6; // Delta Count Ch2, Ch3, Ch6
|
|
||||||
//int bc2, bc3, bc6; // Base Count Ch2, Ch3, Ch6
|
|
||||||
int dc2, dc6; // Delta Count Ch2, Ch6
|
|
||||||
int bc2, bc6; // Base Count Ch2, Ch6
|
int bc2, bc6; // Base Count Ch2, Ch6
|
||||||
struct cap1106_data *data = container_of((struct delayed_work *)work, struct cap1106_data, work);
|
int dc2, dc6; // Delta Count Ch2, Ch6
|
||||||
|
struct cap1106_data *data =
|
||||||
|
container_of((struct delayed_work *)work, struct cap1106_data, work);
|
||||||
|
|
||||||
disable_irq(data->client->irq);
|
disable_irq(data->client->irq);
|
||||||
cap1106_write_reg(data->client, 0x00, 0x80); // Clear INT and Set Gain to MAX
|
// Clear INT, keep GAIN, STBY, DSLEEP
|
||||||
|
cap1106_write_reg(data->client, 0x00,
|
||||||
|
cap1106_read_reg(data->client, 0x00) & 0xF0);
|
||||||
status = cap1106_read_reg(data->client, 0x03);
|
status = cap1106_read_reg(data->client, 0x03);
|
||||||
dc2 = cap1106_read_reg(prox_data->client, 0x11);
|
dc2 = cap1106_read_reg(data->client, 0x11);
|
||||||
//dc3 = cap1106_read_reg(prox_data->client, 0x12);
|
dc6 = cap1106_read_reg(data->client, 0x15);
|
||||||
dc6 = cap1106_read_reg(prox_data->client, 0x15);
|
bc2 = cap1106_read_reg(data->client, 0x51);
|
||||||
bc2 = cap1106_read_reg(prox_data->client, 0x51);
|
bc6 = cap1106_read_reg(data->client, 0x55);
|
||||||
//bc3 = cap1106_read_reg(prox_data->client, 0x52);
|
CAP_DEBUG(
|
||||||
bc6 = cap1106_read_reg(prox_data->client, 0x55);
|
"status: 0x%02X, bc2=0x%02X, dc2=0x%02X, bc6=0x%02X, dc6=0x%02X\n",
|
||||||
//PROX_DEBUG("Status: 0x%02X, BC2=0x%02X, DC2=0x%02X, BC3=0x%02X, DC3=0x%02X, BC6=0x%02X, DC6=0x%02X\n", status, bc2, dc2, bc3, dc3, bc6, dc6);
|
status, bc2, dc2, bc6, dc6);
|
||||||
PROX_DEBUG("Status: 0x%02X, BC2=0x%02X, DC2=0x%02X, BC6=0x%02X, DC6=0x%02X\n", status, bc2, dc2, bc6, dc6);
|
|
||||||
if (is_wood_sensitivity == 0) {
|
if (is_wood_sensitivity == 0) {
|
||||||
if (machine_is_apq8064_deb()) {
|
data->obj_detect = (status & 0x22) ? 1 : 0;
|
||||||
//data->obj_detect = status & 0x26 ? 1 : 0;
|
CAP_DEBUG("obj_detect: %d", data->obj_detect);
|
||||||
data->obj_detect = status & 0x22 ? 1 : 0;
|
switch_set_state(&cap_sdev, data->obj_detect);
|
||||||
switch_set_state(&prox_sdev, data->obj_detect);
|
if (data->app2mdm_enable) {
|
||||||
if ((status == 0x02 && dc2 == 0x7F)
|
gpio_set_value(data->sar_gpio, data->obj_detect);
|
||||||
//|| (status == 0x04 && dc3 == 0x7F)
|
}
|
||||||
|| (status == 0x20 && dc6 == 0x7F)
|
if ((status == 0x02 && dc2 == 0x7F) || (status == 0x20 && dc6 == 0x7F)
|
||||||
//|| (status == 0x06 && (dc2 == 0x7F || dc3 == 0x7F))
|
|
||||||
|| (status == 0x22 && (dc2 == 0x7F || dc6 == 0x7F))) {
|
|| (status == 0x22 && (dc2 == 0x7F || dc6 == 0x7F))) {
|
||||||
//|| (status == 0x24 && (dc3 == 0x7F || dc6 == 0x7F))
|
CAP_DEBUG("is_wood_sensitivity = 1\n");
|
||||||
//|| (status == 0x26 && (dc2 == 0x7F || dc3 == 0x7F || dc6 == 0x7F))) {
|
|
||||||
PROX_DEBUG("Deb, set to wood sensitivity------>\n");
|
|
||||||
//set sensitivity and threshold for wood touch
|
//set sensitivity and threshold for wood touch
|
||||||
cap1106_write_reg(prox_data->client, 0x1f, 0x4f);
|
cap1106_write_reg(data->client, 0x1F, 0x4F);
|
||||||
cap1106_write_reg(prox_data->client, 0x31, 0x50);
|
cap1106_write_reg(data->client, 0x31, 0x5F);
|
||||||
//cap1106_write_reg(prox_data->client, 0x32, 0x50);
|
cap1106_write_reg(data->client, 0x35, 0x5F);
|
||||||
cap1106_write_reg(prox_data->client, 0x35, 0x50);
|
|
||||||
is_wood_sensitivity = 1;
|
is_wood_sensitivity = 1;
|
||||||
data->overflow_status = status;
|
data->overflow_status = status;
|
||||||
ac2 = 0;
|
ac2 = 0;
|
||||||
//ac3 = 0;
|
|
||||||
ac6 = 0;
|
ac6 = 0;
|
||||||
} else {
|
} else {
|
||||||
if (dc2 >= 0x08 && dc2 <= 0x3F)
|
if (dc2 >= 0x0A && dc2 <= 0x3F) ac2++;
|
||||||
ac2++;
|
if (dc6 >= 0x0A && dc6 <= 0x3F) ac6++;
|
||||||
//if (dc3 >= 0x08 && dc3 <= 0x3F)
|
|
||||||
// ac3++;
|
|
||||||
if (dc6 >= 0x0a && dc6 <= 0x3F)
|
|
||||||
ac6++;
|
|
||||||
|
|
||||||
//PROX_DEBUG("Deb, ac2=%d, ac3=%d, ac6=%d\n", ac2, ac3, ac6);
|
CAP_DEBUG("ac2=%d, ac6=%d\n", ac2, ac6);
|
||||||
PROX_DEBUG("Deb, ac2=%d, ac6=%d\n", ac2, ac6);
|
|
||||||
//if (ac2 >= ac_limit || ac3 >= ac_limit || ac6 >= ac_limit) {
|
|
||||||
if (ac2 >= ac_limit || ac6 >= ac_limit) {
|
if (ac2 >= ac_limit || ac6 >= ac_limit) {
|
||||||
PROX_DEBUG("Deb, +++ FORCE RECALIBRATION +++\n");
|
CAP_DEBUG("+++ FORCE RECALIBRATION +++\n");
|
||||||
//cap1106_write_reg(data->client, 0x26, 0x26);
|
|
||||||
cap1106_write_reg(data->client, 0x26, 0x22);
|
cap1106_write_reg(data->client, 0x26, 0x22);
|
||||||
ac2 = 0;
|
ac2 = 0;
|
||||||
//ac3 = 0;
|
|
||||||
ac6 = 0;
|
ac6 = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
enable_irq(data->client->irq);
|
enable_irq(data->client->irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t cap1106_interrupt_handler(int irq, void *dev)
|
static irqreturn_t cap1106_interrupt_handler(int irq, void *dev)
|
||||||
{
|
{
|
||||||
struct cap1106_data *data = i2c_get_clientdata(dev);
|
struct cap1106_data *data = i2c_get_clientdata(dev);
|
||||||
queue_delayed_work(prox_wq, &data->work, 0);
|
queue_delayed_work(data->cap_wq, &data->work, 0);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cap1106_config_irq(struct i2c_client *client)
|
static int cap1106_config_irq(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int rc = 0 ;
|
int rc = 0;
|
||||||
unsigned gpio = SAR_DET_3G;
|
|
||||||
const char *label = "cap1106_alert";
|
|
||||||
|
|
||||||
rc = gpio_request(gpio, label);
|
struct cap1106_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
if (data->app2mdm_enable && gpio_is_valid(data->sar_gpio)) {
|
||||||
|
rc = gpio_request(data->sar_gpio, data->sar_gpio_name);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
PROX_ERROR("%s: gpio_request failed for gpio %s\n", __func__, "SAR_DET_3G");
|
CAP_ERROR("APP2MDM_SAR_gpio_request_failed, rc=%d\n", rc);
|
||||||
goto err_gpio_request_failed;
|
goto err_APP2MDM_SAR_gpio_request_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = gpio_direction_input(gpio) ;
|
rc = gpio_direction_output(data->sar_gpio, 0);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
PROX_ERROR("%s: gpio_direction_input failed for gpio %s\n", __func__, "SAR_DET_3G");
|
CAP_ERROR("APP2MDM_SAR_gpio_direction_output_failed, rc=%d\n", rc);
|
||||||
goto err_gpio_direction_input_failed;
|
goto err_APP2MDM_SAR_gpio_direction_output_failed;
|
||||||
|
}
|
||||||
|
CAP_INFO("GPO=%02d OK", data->sar_gpio);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = request_irq(client->irq, cap1106_interrupt_handler, IRQF_TRIGGER_FALLING, label, client);
|
if (gpio_is_valid(data->det_gpio)) {
|
||||||
if(rc){
|
rc = gpio_request(data->det_gpio, data->det_gpio_name);
|
||||||
PROX_ERROR("Could not register for %s interrupt, irq = %d, rc = %d\n", label, client->irq, rc);
|
if (rc) {
|
||||||
goto err_gpio_request_irq_failed;
|
CAP_ERROR("SAR_DET_3G_gpio_request_failed, rc=%d\n", rc);
|
||||||
|
goto err_SAR_DET_3G_gpio_request_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
PROX_INFO("GPIO=0x%02X, IRQ=0x%02X, SAR_DET_3G=0x%02X\n", gpio, client->irq, gpio_get_value(SAR_DET_3G));
|
rc = gpio_direction_input(data->det_gpio);
|
||||||
|
if (rc) {
|
||||||
|
CAP_ERROR("SAR_DET_3G_gpio_direction_input_failed, rc=%d\n", rc);
|
||||||
|
goto err_SAR_DET_3G_gpio_direction_input_failed;
|
||||||
|
}
|
||||||
|
|
||||||
#if PROX_SENSOR_VERBOSE_DEBUG
|
rc = request_irq(client->irq, cap1106_interrupt_handler,
|
||||||
dump_registers(client);
|
IRQF_TRIGGER_FALLING, data->det_gpio_name, client);
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0 ;
|
if (rc) {
|
||||||
err_gpio_request_irq_failed:
|
CAP_ERROR("SAR_DET_3G_request_irq_failed, rc=%d\n", rc);
|
||||||
err_gpio_direction_input_failed:
|
goto err_SAR_DET_3G_request_irq_failed;
|
||||||
gpio_free(gpio);
|
}
|
||||||
err_gpio_request_failed:
|
|
||||||
|
CAP_INFO("GPI=%02d, VALUE=%d OK\n",
|
||||||
|
data->det_gpio, gpio_get_value(data->det_gpio));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_SAR_DET_3G_request_irq_failed:
|
||||||
|
err_SAR_DET_3G_gpio_direction_input_failed:
|
||||||
|
gpio_free(data->det_gpio);
|
||||||
|
err_SAR_DET_3G_gpio_request_failed:
|
||||||
|
err_APP2MDM_SAR_gpio_direction_output_failed:
|
||||||
|
gpio_free(data->sar_gpio);
|
||||||
|
err_APP2MDM_SAR_gpio_request_failed:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cap1106_init_sensor(struct i2c_client *client)
|
static int cap1106_init_sensor(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
u8 bIdx;
|
unsigned char bIdx;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
const u8 init_table_deb[] = {
|
struct cap1106_data *data = i2c_get_clientdata(client);
|
||||||
0x1f, 0x1f, // Data sensitivity (need to be fine tune for real system).
|
|
||||||
0x20, 0x20, // MAX duration disable
|
|
||||||
//0x21, 0x26, // Enable CS2+CS3+CS6.
|
|
||||||
0x21, 0x22, // Enable CS2+CS6.
|
|
||||||
0x22, 0xff, // MAX duration time to max , repeat period time to max
|
|
||||||
0x24, 0x39, // digital count update time to 140*64ms
|
|
||||||
//0x27, 0x26, // Enable INT. for CS2+CS3+CS6.
|
|
||||||
0x27, 0x22, // Enable INT. for CS2+CS6.
|
|
||||||
0x28, 0x22, // disable repeat irq
|
|
||||||
0x2a, 0x00, // all channel run in the same time
|
|
||||||
0x31, 0x08, // Threshold of CS 2 (need to be fine tune for real system).
|
|
||||||
//0x32, 0x0a, // Threshold of CS 3 (need to be fine tune for real system).
|
|
||||||
0x35, 0x0a, // Threshold of CS 6 (need to be fine tune for real system).
|
|
||||||
//0x26, 0x26, // force re-cal CS2+CS3+CS6
|
|
||||||
0x26, 0x22, // force re-cal CS2+CS6
|
|
||||||
0x00, 0x00, // Reset INT. bit.
|
|
||||||
};
|
|
||||||
|
|
||||||
PROX_DEBUG("NAME: %s, ADDR: 0x%X\n", client->name, client->addr);
|
for (bIdx = 0; bIdx < CAP1106_INIT_TABLE_SIZE; bIdx += 2) {
|
||||||
|
if ((rc = cap1106_write_reg(client, *(data->init_table + bIdx),
|
||||||
if (machine_is_apq8064_deb()) {
|
*(data->init_table + bIdx + 1)))) {
|
||||||
for (bIdx = 0; bIdx < sizeof(init_table_deb) / sizeof(init_table_deb[0]); bIdx += 2) {
|
CAP_ERROR("I2C write error, rc=0x%X\n", rc);
|
||||||
if ((rc = cap1106_write_reg(client, init_table_deb[bIdx],
|
|
||||||
init_table_deb[bIdx + 1]))) {
|
|
||||||
PROX_ERROR("=== Deb, Write Error, rc=0x%X\n", rc);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if PROX_SENSOR_VERBOSE_DEBUG
|
CAP_INFO("I2C_NAME: %s, I2C_ADDR: 0x%X %s\n", client->name, client->addr, rc ? "FAIL" : "OK");
|
||||||
dump_registers(client);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cap1106_checking_work_function(struct work_struct *work) {
|
static void cap1106_checking_work_function(struct work_struct *work)
|
||||||
|
{
|
||||||
int status;
|
int status;
|
||||||
//int dc2, dc3, dc6;
|
|
||||||
//int bc2, bc3, bc6;
|
|
||||||
int dc2, dc6;
|
|
||||||
int bc2, bc6;
|
int bc2, bc6;
|
||||||
|
int dc2, dc6;
|
||||||
|
|
||||||
if (is_wood_sensitivity == 1){
|
struct cap1106_data *data =
|
||||||
mutex_lock(&prox_mtx);
|
container_of((struct delayed_work *)work, struct cap1106_data, checking_work);
|
||||||
if (prox_data->enable) {
|
|
||||||
status = cap1106_read_reg(prox_data->client, 0x03);
|
if (is_wood_sensitivity == 1) {
|
||||||
dc2 = cap1106_read_reg(prox_data->client, 0x11);
|
mutex_lock(&cap_mtx);
|
||||||
//dc3 = cap1106_read_reg(prox_data->client, 0x12);
|
if (data->enable) {
|
||||||
dc6 = cap1106_read_reg(prox_data->client, 0x15);
|
status = cap1106_read_reg(data->client, 0x03);
|
||||||
bc2 = cap1106_read_reg(prox_data->client, 0x51);
|
dc2 = cap1106_read_reg(data->client, 0x11);
|
||||||
//bc3 = cap1106_read_reg(prox_data->client, 0x52);
|
dc6 = cap1106_read_reg(data->client, 0x15);
|
||||||
bc6 = cap1106_read_reg(prox_data->client, 0x55);
|
bc2 = cap1106_read_reg(data->client, 0x51);
|
||||||
//PROX_DEBUG("Status: 0x%02X, BC2=0x%02X, DC2=0x%02X, BC3=0x%02X, DC3=0x%02X, BC6=0x%02X, DC6=0x%02X\n", status, bc2, dc2, bc3, dc3, bc6, dc6);
|
bc6 = cap1106_read_reg(data->client, 0x55);
|
||||||
PROX_DEBUG("Status: 0x%02X, BC2=0x%02X, DC2=0x%02X, BC6=0x%02X, DC6=0x%02X\n", status, bc2, dc2, bc6, dc6);
|
CAP_DEBUG(
|
||||||
if (machine_is_apq8064_deb()) {
|
"status: 0x%02X, bc2=0x%02X, dc2=0x%02X, bc6=0x%02X, dc6=0x%02X\n",
|
||||||
if (//(dc2 == 0x00 && dc3 == 0x00)
|
status, bc2, dc2, bc6, dc6);
|
||||||
//|| (dc2 == 0xFF && dc3 == 0xFF)
|
if ((dc2 == 0x00 && dc6 == 0x00)
|
||||||
//|| (dc2 == 0x00 && dc3 == 0xFF)
|
|
||||||
//|| (dc2 == 0xFF && dc3 == 0x00)
|
|
||||||
(dc2 == 0x00 && dc6 == 0x00)
|
|
||||||
|| (dc2 == 0xFF && dc6 == 0xFF)
|
|| (dc2 == 0xFF && dc6 == 0xFF)
|
||||||
|| (dc2 == 0x00 && dc6 == 0xFF)
|
|| (dc2 == 0x00 && dc6 == 0xFF)
|
||||||
|| (dc2 == 0xFF && dc6 == 0x00)
|
|| (dc2 == 0xFF && dc6 == 0x00)
|
||||||
//|| (dc3 == 0x00 && dc6 == 0x00)
|
|| (data->overflow_status == 0x02 && (dc2 > 0x5F) && (dc2 <= 0x7F))
|
||||||
//|| (dc3 == 0xFF && dc6 == 0xFF)
|
|| (data->overflow_status == 0x20 && (dc6 > 0x5F) && (dc6 <= 0x7F))
|
||||||
//|| (dc3 == 0x00 && dc6 == 0xFF)
|
|| (data->overflow_status == 0x22 && (((dc2 > 0x5F) && (dc2 <= 0x7F)) || ((dc6 > 0x5F) && (dc6 <= 0x7F))))) {
|
||||||
//|| (dc3 == 0xFF && dc6 == 0x00)
|
CAP_DEBUG("is_wood_sensitivity = 0\n");
|
||||||
|| (prox_data->overflow_status == 0x02 && (dc2 > 0x50) && (dc2 <= 0x7F))
|
|
||||||
//|| (prox_data->overflow_status == 0x04 && (dc3 > 0x50) && (dc3 <= 0x7F))
|
|
||||||
|| (prox_data->overflow_status == 0x20 && (dc6 > 0x50) && (dc6 <= 0x7F))
|
|
||||||
//|| (prox_data->overflow_status == 0x06 && (((dc2 > 0x50) && (dc2 <= 0x7F)) || ((dc3 > 0x50) && (dc3 <= 0x7F))))
|
|
||||||
|| (prox_data->overflow_status == 0x22 && (((dc2 > 0x50) && (dc2 <= 0x7F)) || ((dc6 > 0x50) && (dc6 <= 0x7F))))) {
|
|
||||||
//|| (prox_data->overflow_status == 0x24 && (((dc3 > 0x50) && (dc3 <= 0x7F)) || ((dc6 > 0x50) && (dc6 <= 0x7F))))
|
|
||||||
//|| (prox_data->overflow_status == 0x26 && (((dc2 > 0x50) && (dc2 <= 0x7F)) || ((dc3 > 0x50) && (dc3 <= 0x7F)) || ((dc6 > 0x50) && (dc6 <= 0x7F))))) {
|
|
||||||
PROX_DEBUG("Deb, unset is_wood_sensitivity to 0\n");
|
|
||||||
//set sensitivity and threshold for 2cm body distance
|
//set sensitivity and threshold for 2cm body distance
|
||||||
cap1106_write_reg(prox_data->client, 0x1f, 0x1f);
|
cap1106_write_reg(data->client, 0x1F, 0x1F);
|
||||||
cap1106_write_reg(prox_data->client, 0x31, 0x08);
|
cap1106_write_reg(data->client, 0x31, 0x0A);
|
||||||
//cap1106_write_reg(prox_data->client, 0x32, 0x0a);
|
cap1106_write_reg(data->client, 0x35, 0x0A);
|
||||||
cap1106_write_reg(prox_data->client, 0x35, 0x0a);
|
|
||||||
is_wood_sensitivity = 0;
|
is_wood_sensitivity = 0;
|
||||||
queue_delayed_work(prox_wq, &prox_data->work, 0);
|
queue_delayed_work(data->cap_wq, &data->work, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&cap_mtx);
|
||||||
}
|
}
|
||||||
mutex_unlock(&prox_mtx);
|
queue_delayed_work(data->cap_wq, &data->checking_work,
|
||||||
}
|
msecs_to_jiffies(500));
|
||||||
queue_delayed_work(prox_wq, &prox_data->checking_work, checking_work_period);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit cap1106_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
static int __devinit cap1106_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
prox_data->client = client;
|
struct cap1106_data *data;
|
||||||
|
struct cap1106_i2c_platform_data *pdata;
|
||||||
|
|
||||||
/* Touch data processing workqueue initialization */
|
data = kzalloc(sizeof(struct cap1106_data), GFP_KERNEL);
|
||||||
INIT_DELAYED_WORK(&prox_data->work, cap1106_work_function);
|
if (!data) {
|
||||||
INIT_DELAYED_WORK(&prox_data->checking_work,cap1106_checking_work_function);
|
CAP_ERROR("kzalloc failed!\n");
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto err_kzalloc_failed;
|
||||||
|
}
|
||||||
|
|
||||||
i2c_set_clientdata(client, prox_data);
|
data->cap_wq = create_singlethread_workqueue("cap_wq");
|
||||||
prox_data->client->flags = 0;
|
if (!data->cap_wq) {
|
||||||
strlcpy(prox_data->client->name, "cap1106", I2C_NAME_SIZE);
|
CAP_ERROR("create_singlethread_workqueue failed!\n");
|
||||||
prox_data->enable = 0;
|
rc = -ENOMEM;
|
||||||
|
goto err_create_singlethread_workqueue_failed;
|
||||||
|
}
|
||||||
|
|
||||||
rc = cap1106_init_sensor(prox_data->client);
|
INIT_DELAYED_WORK(&data->work, cap1106_work_function);
|
||||||
|
INIT_DELAYED_WORK(&data->checking_work, cap1106_checking_work_function);
|
||||||
|
|
||||||
|
data->client = client;
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
|
||||||
|
pdata = client->dev.platform_data;
|
||||||
|
|
||||||
|
if (likely(pdata != NULL)) {
|
||||||
|
data->app2mdm_enable = pdata->app2mdm_enable;
|
||||||
|
data->sar_gpio = pdata->sar_gpio;
|
||||||
|
data->sar_gpio_name = pdata->sar_gpio_name;
|
||||||
|
data->det_gpio = pdata->det_gpio;
|
||||||
|
data->det_gpio_name = pdata->det_gpio_name;
|
||||||
|
data->init_table = pdata->init_table;
|
||||||
|
|
||||||
|
CAP_INFO("data->app2mdm_enable: %d\n", data->app2mdm_enable);
|
||||||
|
CAP_INFO("data->sar_gpio: %d\n", data->sar_gpio);
|
||||||
|
CAP_INFO("data->sar_gpio_name: %s\n", data->sar_gpio_name);
|
||||||
|
CAP_INFO("data->det_gpio: %d\n", data->det_gpio);
|
||||||
|
CAP_INFO("data->det_gpio_name: %s\n", data->det_gpio_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->client->flags = 0;
|
||||||
|
strlcpy(data->client->name, CAP1106_I2C_NAME, I2C_NAME_SIZE);
|
||||||
|
data->enable = 0;
|
||||||
|
|
||||||
|
rc = cap1106_init_sensor(data->client);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
PROX_ERROR("Sensor initialization failed!\n");
|
CAP_ERROR("Sensor initialization failed!\n");
|
||||||
goto err_init_sensor_failed;
|
goto err_init_sensor_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (machine_is_apq8064_deb())
|
data->attrs.attrs = cap1106_attr_deb;
|
||||||
prox_data->attrs.attrs = cap1106_attr_deb;
|
|
||||||
|
|
||||||
rc = sysfs_create_group(&prox_data->client->dev.kobj, &prox_data->attrs);
|
rc = sysfs_create_group(&data->client->dev.kobj, &data->attrs);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
PROX_ERROR("Create the sysfs group failed!\n");
|
CAP_ERROR("Create the sysfs group failed!\n");
|
||||||
goto err_create_sysfs_group_failed;
|
goto err_create_sysfs_group_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register switch class */
|
/* register switch class */
|
||||||
prox_sdev.name = NAME_RIL_PROX;
|
cap_sdev.name = CAP_SDEV_NAME;
|
||||||
prox_sdev.print_name = print_prox_name;
|
cap_sdev.print_name = print_cap_name;
|
||||||
prox_sdev.print_state = print_prox_state;
|
cap_sdev.print_state = print_cap_state;
|
||||||
|
|
||||||
rc = switch_dev_register(&prox_sdev);
|
rc = switch_dev_register(&cap_sdev);
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
PROX_ERROR("Switch device registration failed!\n");
|
CAP_ERROR("Switch device registration failed!\n");
|
||||||
goto err_register_switch_class_failed;
|
goto err_register_switch_class_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = cap1106_config_irq(prox_data->client);
|
rc = cap1106_config_irq(data->client);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
PROX_ERROR("Sensor INT configuration failed!\n");
|
CAP_ERROR("Sensor INT configuration failed!\n");
|
||||||
goto err_config_irq_failed;
|
goto err_config_irq_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
prox_data->enable = 1;
|
data->enable = 1;
|
||||||
prox_data->overflow_status = 0x0;
|
data->overflow_status = 0x0;
|
||||||
queue_delayed_work(prox_wq, &prox_data->work, msecs_to_jiffies(200));
|
queue_delayed_work(data->cap_wq, &data->work, msecs_to_jiffies(200));
|
||||||
queue_delayed_work(prox_wq, &prox_data->checking_work, checking_work_period);
|
queue_delayed_work(data->cap_wq, &data->checking_work,
|
||||||
|
msecs_to_jiffies(500));
|
||||||
|
|
||||||
PROX_INFO("OK\n");
|
pivate_data = data;
|
||||||
|
|
||||||
|
CAP_INFO("OK\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_config_irq_failed:
|
err_config_irq_failed:
|
||||||
err_register_switch_class_failed:
|
err_register_switch_class_failed:
|
||||||
sysfs_remove_group(&prox_data->client->dev.kobj, &prox_data->attrs);
|
sysfs_remove_group(&data->client->dev.kobj, &data->attrs);
|
||||||
err_create_sysfs_group_failed:
|
err_create_sysfs_group_failed:
|
||||||
err_init_sensor_failed:
|
err_init_sensor_failed:
|
||||||
|
destroy_workqueue(data->cap_wq);
|
||||||
|
err_create_singlethread_workqueue_failed:
|
||||||
|
kfree(data);
|
||||||
|
err_kzalloc_failed:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devexit cap1106_remove(struct i2c_client *client)
|
static int __devexit cap1106_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
PROX_DEBUG("\n");
|
struct cap1106_data *data = i2c_get_clientdata(client);
|
||||||
switch_dev_unregister(&prox_sdev);
|
CAP_DEBUG("+\n");
|
||||||
sysfs_remove_group(&client->dev.kobj, &prox_data->attrs);
|
switch_dev_unregister(&cap_sdev);
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||||
free_irq(client->irq, client);
|
free_irq(client->irq, client);
|
||||||
kfree(prox_data);
|
if (data->cap_wq) destroy_workqueue(data->cap_wq);
|
||||||
|
kfree(data);
|
||||||
|
CAP_DEBUG("-\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cap1106_suspend(struct i2c_client *client, pm_message_t mesg)
|
static int cap1106_suspend(struct i2c_client *client, pm_message_t mesg)
|
||||||
{
|
{
|
||||||
PROX_DEBUG("+\n");
|
CAP_DEBUG("+\n");
|
||||||
mutex_lock(&prox_mtx);
|
mutex_lock(&cap_mtx);
|
||||||
cap1106_enable_sensor(client, 0);
|
cap1106_enable_sensor(client, 0);
|
||||||
mutex_unlock(&prox_mtx);
|
mutex_unlock(&cap_mtx);
|
||||||
PROX_DEBUG("-\n");
|
CAP_DEBUG("-\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cap1106_resume(struct i2c_client *client)
|
static int cap1106_resume(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
PROX_DEBUG("+\n");
|
CAP_DEBUG("+\n");
|
||||||
mutex_lock(&prox_mtx);
|
mutex_lock(&cap_mtx);
|
||||||
if (force_enable)
|
if (force_enable) cap1106_enable_sensor(client, 1);
|
||||||
cap1106_enable_sensor(client, 1);
|
mutex_unlock(&cap_mtx);
|
||||||
mutex_unlock(&prox_mtx);
|
CAP_DEBUG("-\n");
|
||||||
PROX_DEBUG("-\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init cap1106_init(void)
|
static int __init cap1106_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
CAP_INFO("\n");
|
||||||
|
return i2c_add_driver(&cap1106_driver);
|
||||||
PROX_INFO("+++\n");
|
|
||||||
|
|
||||||
if (!machine_is_apq8064_deb()) {
|
|
||||||
PROX_ERROR("Cap1106 driver doesn't support this project\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
prox_wq = create_singlethread_workqueue("prox_wq");
|
|
||||||
if(!prox_wq) {
|
|
||||||
PROX_ERROR("create_singlethread_workqueue failed!\n");
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_create_singlethread_workqueue_failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
prox_data = kzalloc(sizeof(struct cap1106_data), GFP_KERNEL);
|
|
||||||
if (!prox_data) {
|
|
||||||
PROX_ERROR("kzalloc failed!\n");
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_kzalloc_failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = i2c_add_driver(&cap1106_driver);
|
|
||||||
if (rc) {
|
|
||||||
PROX_ERROR("i2c_add_driver failed!\n");
|
|
||||||
goto err_i2c_add_driver_failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
PROX_INFO("---\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_i2c_add_driver_failed:
|
|
||||||
kfree(prox_data);
|
|
||||||
err_kzalloc_failed:
|
|
||||||
destroy_workqueue(prox_wq);
|
|
||||||
err_create_singlethread_workqueue_failed:
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit cap1106_exit(void)
|
static void __exit cap1106_exit(void)
|
||||||
{
|
{
|
||||||
PROX_DEBUG("\n");
|
CAP_INFO("\n");
|
||||||
|
|
||||||
if (!machine_is_apq8064_deb()) {
|
|
||||||
PROX_ERROR("Cap1106 driver doesn't support this project\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
i2c_del_driver(&cap1106_driver);
|
i2c_del_driver(&cap1106_driver);
|
||||||
|
|
||||||
if (prox_wq)
|
|
||||||
destroy_workqueue(prox_wq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(cap1106_init);
|
module_init(cap1106_init);
|
||||||
module_exit(cap1106_exit);
|
module_exit(cap1106_exit);
|
||||||
|
MODULE_DESCRIPTION("SMSC CAP1106 Driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|||||||
21
include/linux/i2c/cap1106.h
Normal file
21
include/linux/i2c/cap1106.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
#ifndef _LINUX_I2C_CAP1106_H
|
||||||
|
#define _LINUX_I2C_CAP1106_H
|
||||||
|
|
||||||
|
#define CAP1106_I2C_NAME "cap1106"
|
||||||
|
#define CAP1106_SAR_GPIO 1 /* APP2MDM_SAR */
|
||||||
|
#define CAP1106_SAR_GPIO_NAME "APP2MDM_SAR"
|
||||||
|
#define CAP1106_DET_GPIO 52 /* SAR_DET_3G */
|
||||||
|
#define CAP1106_DET_GPIO_NAME "SAR_DET_3G"
|
||||||
|
#define CAP1106_INIT_TABLE_SIZE 24
|
||||||
|
|
||||||
|
struct cap1106_i2c_platform_data {
|
||||||
|
int app2mdm_enable;
|
||||||
|
int sar_gpio;
|
||||||
|
char *sar_gpio_name;
|
||||||
|
int det_gpio;
|
||||||
|
char *det_gpio_name;
|
||||||
|
const unsigned char init_table[CAP1106_INIT_TABLE_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _LINUX_I2C_CAP1106_H */
|
||||||
Reference in New Issue
Block a user