cap1106: implement controling by state change of RMNET interface

1. If kconfig CAP_SENSOR_RMNET_CTL is checked, cap1106 will be disabled
   if and only if all of the rmnet_usb network interfaces turn off.
2. cap1106 is disabled by default now.

Bug: 9148999

Change-Id: I9e9fa65265e5972f31a607487cb86942bb6384dc
Signed-off-by: Raphanus Lo <raphanus_lo@asus.com>
This commit is contained in:
Raphanus Lo 2013-06-25 16:06:08 -07:00 committed by Iliyan Malchev
parent e69941931c
commit ad49c7f9fe
4 changed files with 125 additions and 1 deletions

View File

@ -306,6 +306,7 @@ CONFIG_BATTERY_ASUS_BQ27541=y
CONFIG_SENSORS_PM8XXX_ADC=y
CONFIG_SENSORS_EPM_ADC=y
CONFIG_SENSORS_CAP1106=y
CONFIG_CAP_SENSOR_RMNET_CTL=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8960=y
CONFIG_THERMAL_PM8XXX=y

View File

@ -1435,6 +1435,13 @@ config SENSORS_CAP1106
To compile this driver as a module, choose m here. The module will
be called cap1106.
config CAP_SENSOR_RMNET_CTL
bool "RMNET-controled SMSC CAP1106"
depends on MSM_RMNET_USB && SENSORS_CAP1106
help
Enable/disable SMSC 1106 cap sensor by state change of RMNET-related
network interface.
if ACPI
comment "ACPI drivers"

View File

@ -20,10 +20,15 @@
#include <linux/switch.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/netdevice.h>
#include <asm/mach-types.h>
#include <linux/i2c/cap1106.h>
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
extern bool rmnet_netdev_cmp(struct net_device *);
#endif
/*
* Debug Utility
*/
@ -54,6 +59,9 @@ struct cap1106_data {
int det_gpio;
char *det_gpio_name;
const unsigned char *init_table;
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
struct notifier_block netdev_obs;
#endif
};
static DEFINE_MUTEX(cap_mtx);
@ -63,7 +71,11 @@ static int is_wood_sensitivity = 0;
static int ac2 = 0; // Accumulated Count Ch2
static int ac6 = 0; // Accumulated Count Ch6
static int ac_limit = 10;
static int force_enable = 1;
static int force_enable = 0;
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
static int rmnet_ctl = 1;
static int rmnet_if_up = 0;
#endif
/*
* Function Declaration
@ -82,6 +94,9 @@ static void cap1106_work_function(struct work_struct *work);
static int cap1106_init_sensor(struct i2c_client *client);
static int cap1106_config_irq(struct i2c_client *client);
static void cap1106_enable_sensor(struct i2c_client *client, int enable);
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
static void rmnet_state_changed(struct i2c_client *client);
#endif
static ssize_t show_attrs_handler(struct device *dev,
struct device_attribute *devattr, char *buf);
static ssize_t store_attrs_handler(struct device *dev,
@ -125,6 +140,9 @@ 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_app2mdm_sar, 0644, NULL, store_attrs_handler);
DEVICE_ATTR(sensor_main, 0644, show_attrs_handler, NULL);
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
DEVICE_ATTR(sensor_rmnetctl, 0644, show_attrs_handler, store_attrs_handler);
#endif
static struct attribute *cap1106_attr_deb[] = {
&dev_attr_obj_detect.attr, // 1
@ -141,6 +159,9 @@ static struct attribute *cap1106_attr_deb[] = {
&dev_attr_sensor_recal.attr, // 12
&dev_attr_sensor_app2mdm_sar.attr, // 13
&dev_attr_sensor_main.attr, // 14
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
&dev_attr_sensor_rmnetctl.attr, // 15
#endif
NULL
};
@ -186,6 +207,10 @@ static ssize_t show_attrs_handler(struct device *dev,
cap1106_read_reg(client, 0x26) == 0x0 ? "OK\n" : "FAIL\n");
} else if (!strcmp(attr_name, dev_attr_sensor_main.attr.name)) {
ret = sprintf(buf, "%02X\n", cap1106_read_reg(client, 0x00));
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
} else if (!strcmp(attr_name, dev_attr_sensor_rmnetctl.attr.name)) {
ret = sprintf(buf, "%d\n", rmnet_ctl);
#endif
}
} else {
if (!strcmp(attr_name, dev_attr_sensor_main.attr.name)) {
@ -234,19 +259,35 @@ static ssize_t store_attrs_handler(struct device *dev,
} else if (!strcmp(attr_name, dev_attr_sensor_onoff.attr.name)) {
if (value == 0) {
force_enable = 0;
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
rmnet_ctl = 0;
#endif
cap1106_enable_sensor(client, 0);
}
} else if (!strcmp(attr_name, dev_attr_sensor_recal.attr.name)) {
cap1106_write_reg(client, 0x26, 0x22);
} else if (!strcmp(attr_name, dev_attr_sensor_app2mdm_sar.attr.name)) {
gpio_set_value(data->sar_gpio, value);
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
} else if (!strcmp(attr_name, dev_attr_sensor_rmnetctl.attr.name)) {
rmnet_ctl = value;
rmnet_state_changed(client);
#endif
}
} else {
if (!strcmp(attr_name, dev_attr_sensor_onoff.attr.name)) {
if (value == 1) {
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
rmnet_ctl = 0;
#endif
force_enable = 1;
cap1106_enable_sensor(client, 1);
}
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
} else if (!strcmp(attr_name, dev_attr_sensor_rmnetctl.attr.name)) {
rmnet_ctl = value;
rmnet_state_changed(client);
#endif
}
}
mutex_unlock(&cap_mtx);
@ -270,6 +311,47 @@ static ssize_t print_cap_state(struct switch_dev *sdev, char *buf)
else
return sprintf(buf, "0\n");
}
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
static int netdev_changed_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
struct cap1106_data *data = container_of(this, struct cap1106_data, netdev_obs);
int before_if_up = rmnet_if_up;
CAP_DEBUG("+\n");
if (!rmnet_netdev_cmp(dev))
goto done;
mutex_lock(&cap_mtx);
switch (event) {
case NETDEV_UP:
++rmnet_if_up;
CAP_DEBUG("netdev %s is up, rmnet_if_up=%d\n", dev->name, rmnet_if_up);
break;
case NETDEV_DOWN:
--rmnet_if_up;
CAP_DEBUG("netdev %s is down, rmnet_if_up=%d\n", dev->name, rmnet_if_up);
break;
default:
break;
}
if (rmnet_if_up < 0) {
CAP_ERROR("rmnet_if_up is negative! Unbalanced netdev state change?\n");
rmnet_if_up = 0;
}
if (before_if_up != rmnet_if_up)
rmnet_state_changed(data->client);
mutex_unlock(&cap_mtx);
done:
CAP_DEBUG("-\n");
return NOTIFY_DONE;
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void cap1106_enable_sensor(struct i2c_client *client, int enable)
@ -302,6 +384,16 @@ static void cap1106_enable_sensor(struct i2c_client *client, int enable)
}
}
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
static void rmnet_state_changed(struct i2c_client *client)
{
if (force_enable || (rmnet_ctl && rmnet_if_up > 0))
cap1106_enable_sensor(client, 1);
else
cap1106_enable_sensor(client, 0);
}
#endif
static s32 cap1106_read_reg(struct i2c_client *client, u8 command)
{
return i2c_smbus_read_byte_data(client, command);
@ -579,6 +671,11 @@ static int __devinit cap1106_probe(struct i2c_client *client,
queue_delayed_work(data->cap_wq, &data->checking_work,
msecs_to_jiffies(1000));
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
data->netdev_obs.notifier_call = netdev_changed_event;
register_netdevice_notifier(&data->netdev_obs);
#endif
pivate_data = data;
CAP_INFO("OK\n");
@ -601,6 +698,9 @@ static int __devexit cap1106_remove(struct i2c_client *client)
{
struct cap1106_data *data = i2c_get_clientdata(client);
CAP_DEBUG("+\n");
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
unregister_netdevice_notifier(&data->netdev_obs);
#endif
switch_dev_unregister(&cap_sdev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
free_irq(client->irq, client);

View File

@ -95,6 +95,22 @@ module_param(no_rmnet_insts_per_dev, uint, S_IRUGO | S_IWUSR);
static int rmnet_data_start(void);
static bool rmnet_data_init;
#if defined(CONFIG_CAP_SENSOR_RMNET_CTL)
bool rmnet_netdev_cmp(struct net_device *dev)
{
int i;
const char *rmnet_name;
for (i = 0; i < 2; ++i) {
rmnet_name = rmnet_names[i];
if (0 == strncmp(dev->name, rmnet_name, strlen(rmnet_name)-2))
return true;
}
return false;
}
EXPORT_SYMBOL(rmnet_netdev_cmp);
#endif
static int rmnet_init(const char *val, const struct kernel_param *kp)
{
int ret = 0;