From eeaabccc1c7b5220d8d5674669662e8ca0c07ec0 Mon Sep 17 00:00:00 2001 From: Bingzhe Cai Date: Tue, 6 May 2014 19:26:33 +0800 Subject: input: sensors: pull down 8916SKUH sensor GPIOs for power saving As sensor will power down during suspend, those GPIOs used by sensors also need pull down to minimize leakage. CRs-fixed: 655099 Change-Id: If9463e0cc89675204b9b4bee5eca2dd5a44515a5 Signed-off-by: Bingzhe Cai --- drivers/input/misc/lis3dh_acc.c | 62 +++++++++++++++++++++++++++++++++------ drivers/misc/apds993x.c | 64 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 113 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/lis3dh_acc.c b/drivers/input/misc/lis3dh_acc.c index d58ec0d5c374..662c27fe64c3 100644 --- a/drivers/input/misc/lis3dh_acc.c +++ b/drivers/input/misc/lis3dh_acc.c @@ -221,6 +221,9 @@ struct lis3dh_acc_data { struct i2c_client *client; struct lis3dh_acc_platform_data *pdata; struct sensors_classdev cdev; + struct pinctrl *pinctrl; + struct pinctrl_state *pin_default; + struct pinctrl_state *pin_sleep; struct mutex lock; struct delayed_work input_work; @@ -513,11 +516,6 @@ static void lis3dh_acc_device_power_off(struct lis3dh_acc_data *acc) if (err < 0) dev_err(&acc->client->dev, "soft power off failed: %d\n", err); - if (gpio_is_valid(acc->pdata->gpio_int1)) - disable_irq_nosync(acc->irq1); - if (gpio_is_valid(acc->pdata->gpio_int2)) - disable_irq_nosync(acc->irq2); - lis3dh_acc_config_regulator(acc, false); if (acc->hw_initialized) { @@ -540,10 +538,6 @@ static int lis3dh_acc_device_power_on(struct lis3dh_acc_data *acc) return err; } - if (gpio_is_valid(acc->pdata->gpio_int1)) - enable_irq(acc->irq1); - if (gpio_is_valid(acc->pdata->gpio_int2)) - enable_irq(acc->irq2); msleep(20); @@ -774,6 +768,10 @@ static int lis3dh_acc_enable(struct lis3dh_acc_data *acc) int err; if (!atomic_cmpxchg(&acc->enabled, 0, 1)) { + if (pinctrl_select_state(acc->pinctrl, acc->pin_default)) + dev_err(&acc->client->dev, + "Can't select pinctrl default state\n"); + err = lis3dh_acc_device_power_on(acc); if (err < 0) { atomic_set(&acc->enabled, 0); @@ -791,6 +789,9 @@ static int lis3dh_acc_disable(struct lis3dh_acc_data *acc) if (atomic_cmpxchg(&acc->enabled, 1, 0)) { cancel_delayed_work_sync(&acc->input_work); lis3dh_acc_device_power_off(acc); + if (pinctrl_select_state(acc->pinctrl, acc->pin_sleep)) + dev_err(&acc->client->dev, + "Can't select pinctrl sleep state\n"); } return 0; @@ -1300,6 +1301,33 @@ static void lis3dh_acc_input_cleanup(struct lis3dh_acc_data *acc) input_free_device(acc->input_dev); } +static int lis3dh_pinctrl_init(struct lis3dh_acc_data *acc) +{ + struct i2c_client *client = acc->client; + + acc->pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR_OR_NULL(acc->pinctrl)) { + dev_err(&client->dev, "Failed to get pinctrl\n"); + return PTR_ERR(acc->pinctrl); + } + + acc->pin_default = + pinctrl_lookup_state(acc->pinctrl, "lis3dh_default"); + if (IS_ERR_OR_NULL(acc->pin_default)) { + dev_err(&client->dev, "Failed to look up default state\n"); + return PTR_ERR(acc->pin_default); + } + + acc->pin_sleep = + pinctrl_lookup_state(acc->pinctrl, "lis3dh_sleep"); + if (IS_ERR_OR_NULL(acc->pin_sleep)) { + dev_err(&client->dev, "Failed to look up sleep state\n"); + return PTR_ERR(acc->pin_sleep); + } + + return 0; +} + #ifdef CONFIG_OF static int lis3dh_parse_dt(struct device *dev, struct lis3dh_acc_platform_data *pdata) @@ -1454,6 +1482,18 @@ static int lis3dh_acc_probe(struct i2c_client *client, goto exit_kfree_pdata; } + /* initialize pinctrl */ + err = lis3dh_pinctrl_init(acc); + if (err) { + dev_err(&client->dev, "Can't initialize pinctrl\n"); + goto exit_kfree_pdata; + } + err = pinctrl_select_state(acc->pinctrl, acc->pin_default); + if (err) { + dev_err(&client->dev, + "Can't select pinctrl default state\n"); + goto exit_kfree_pdata; + } if (acc->pdata->init) { err = acc->pdata->init(); @@ -1579,6 +1619,10 @@ static int lis3dh_acc_probe(struct i2c_client *client, disable_irq_nosync(acc->irq2); } + if (pinctrl_select_state(acc->pinctrl, acc->pin_sleep)) + dev_err(&client->dev, + "Can't select pinctrl sleep state\n"); + mutex_unlock(&acc->lock); dev_dbg(&client->dev, "%s: probed\n", LIS3DH_ACC_DEV_NAME); diff --git a/drivers/misc/apds993x.c b/drivers/misc/apds993x.c index fe76eb99d310..1305cb6c94d9 100644 --- a/drivers/misc/apds993x.c +++ b/drivers/misc/apds993x.c @@ -214,6 +214,9 @@ struct apds993x_data { struct regulator *vio; struct sensors_classdev als_cdev; struct sensors_classdev ps_cdev; + struct pinctrl *pinctrl; + struct pinctrl_state *pin_default; + struct pinctrl_state *pin_sleep; struct apds993x_platform_data *platform_data; int irq; @@ -2097,9 +2100,22 @@ static int sensor_regulator_power_on(struct apds993x_data *data, bool on) static int sensor_platform_hw_power_on(bool on) { + int err; + if (pdev_data == NULL) return -ENODEV; + if (!IS_ERR_OR_NULL(pdev_data->pinctrl)) { + if (on) + err = pinctrl_select_state(pdev_data->pinctrl, + pdev_data->pin_default); + else + err = pinctrl_select_state(pdev_data->pinctrl, + pdev_data->pin_sleep); + if (err) + dev_err(&pdev_data->client->dev, + "Can't select pinctrl state\n"); + } sensor_regulator_power_on(pdev_data, on); return 0; @@ -2153,6 +2169,33 @@ static void sensor_platform_hw_exit(void) gpio_free(data->platform_data->irq_gpio); } +static int apds993x_pinctrl_init(struct apds993x_data *data) +{ + struct i2c_client *client = data->client; + + data->pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR_OR_NULL(data->pinctrl)) { + dev_err(&client->dev, "Failed to get pinctrl\n"); + return PTR_ERR(data->pinctrl); + } + + data->pin_default = + pinctrl_lookup_state(data->pinctrl, "default"); + if (IS_ERR_OR_NULL(data->pin_default)) { + dev_err(&client->dev, "Failed to look up default state\n"); + return PTR_ERR(data->pin_default); + } + + data->pin_sleep = + pinctrl_lookup_state(data->pinctrl, "sleep"); + if (IS_ERR_OR_NULL(data->pin_sleep)) { + dev_err(&client->dev, "Failed to look up sleep state\n"); + return PTR_ERR(data->pin_sleep); + } + + return 0; +} + static int sensor_parse_dt(struct device *dev, struct apds993x_platform_data *pdata) { @@ -2300,6 +2343,19 @@ static int apds993x_probe(struct i2c_client *client, data->client = client; apds993x_i2c_client = client; + /* initialize pinctrl */ + err = apds993x_pinctrl_init(data); + if (err) { + dev_err(&client->dev, "Can't initialize pinctrl\n"); + goto exit_kfree; + } + err = pinctrl_select_state(data->pinctrl, data->pin_default); + if (err) { + dev_err(&client->dev, + "Can't select pinctrl default state\n"); + goto exit_kfree; + } + /* h/w initialization */ if (pdata->init) err = pdata->init(); @@ -2344,14 +2400,14 @@ static int apds993x_probe(struct i2c_client *client, err = apds993x_init_client(client); if (err) { pr_err("%s: Failed to init apds993x\n", __func__); - goto exit_kfree; + goto exit_uninit; } err = request_irq(data->irq, apds993x_interrupt, IRQF_TRIGGER_FALLING, APDS993X_DRV_NAME, (void *)client); if (err < 0) { pr_err("%s: Could not allocate APDS993X_INT !\n", __func__); - goto exit_kfree; + goto exit_uninit; } irq_set_irq_wake(client->irq, 1); @@ -2456,12 +2512,12 @@ exit_free_dev_ps: exit_free_dev_als: exit_free_irq: free_irq(data->irq, client); -exit_kfree: +exit_uninit: if (pdata->power_on) pdata->power_on(false); if (pdata->exit) pdata->exit(); - +exit_kfree: kfree(data); pdev_data = NULL; exit: -- cgit v1.2.3