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:
tryout_chen
2013-05-02 16:39:00 +08:00
committed by Android Partner Code Review
parent c6833ee6ee
commit c7b57708c1
3 changed files with 529 additions and 521 deletions

View File

@@ -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
View 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");

View 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 */