]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
power: lc709203f:implement interrupt feature
authorVenkat Reddy Talla <vreddytalla@nvidia.com>
Wed, 19 Mar 2014 11:40:52 +0000 (17:10 +0530)
committerSimone Willett <swillett@nvidia.com>
Tue, 1 Apr 2014 20:09:30 +0000 (13:09 -0700)
implement interrupt support to generate low voltage/soc
events when battery voltage measured below threshold value.
update binding doc with lc709203f parameters.

Bug 1474634

Change-Id: I89f3b009548132d1e00bc28fb202e1f6babdfab1
Signed-off-by: Venkat Reddy Talla <vreddytalla@nvidia.com>
Reviewed-on: http://git-master/r/383844
(cherry picked from commit 40ad39bb1e3bd8c62e4ee3a506650c1aa5a354b8)
Reviewed-on: http://git-master/r/386962
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>
Documentation/devicetree/bindings/power_supply/lc709203f_battery.txt
drivers/power/lc709203f_battery.c

index 0a2d75200a905b5f435993d16ca3ed23289c9e55..cab2883167762ab79a58db42cf517805bb99c6bf 100644 (file)
@@ -17,6 +17,8 @@ Optional properties:
        Kernel read maximum SoC from device for given battery. Kernel
        translate the SoC to 100% before reporting to framework if it
        reads equal/more than this value.
+ - onsemi,alert-low-rsoc : Alarm low RSOC programed to generate event
+ - onsemi,alert-low-voltage : Alarm low Voltage programed to generate event
 
 Note: The device has capabilty to read battery temp through thermistor.
 This also calulate SoC based on temperature of battery. If thermistor
@@ -41,4 +43,6 @@ Example:
                onsemi,initial-rsoc = 0xAA55;
                onsemi,kernel-threshold-soc = <5>;
                onsemi,kernel-maximum-soc = <99>;
+               onsemi,alert-low-rsoc = <0x0>;
+               onsemi,alert-low-voltage = <0x0>;
        };
index dbbdefb9c45aeaf586d04e73dd6943e11a32a33a..5e019ad35ba30fb3d987abbe040dd9006518c8db 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/power/battery-charger-gauge-comm.h>
 #include <linux/pm.h>
 #include <linux/jiffies.h>
+#include <linux/interrupt.h>
 
 #define LC709203F_THERMISTOR_B         0x06
 #define LC709203F_INITIAL_RSOC         0x07
@@ -60,6 +61,8 @@ struct lc709203f_platform_data {
        u32 therm_adjustment;
        u32 threshold_soc;
        u32 maximum_soc;
+       u32 alert_low_rsoc;
+       u32 alert_low_voltage;
 };
 
 struct lc709203f_chip {
@@ -304,6 +307,23 @@ static struct battery_gauge_info lc709203f_bgi = {
        .bg_ops = &lc709203f_bg_ops,
 };
 
+static irqreturn_t lc709203f_irq(int id, void *dev)
+{
+       struct lc709203f_chip *chip = dev;
+       struct i2c_client *client = chip->client;
+
+       dev_info(&client->dev, "%s(): STATUS_VL\n", __func__);
+       /* Forced set SOC 0 to power off */
+       chip->soc = 0;
+       chip->lasttime_soc = chip->soc;
+       chip->status = chip->lasttime_status;
+       chip->health = POWER_SUPPLY_HEALTH_DEAD;
+       chip->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+       power_supply_changed(&chip->battery);
+
+       return IRQ_HANDLED;
+}
+
 static void of_lc709203f_parse_platform_data(struct i2c_client *client,
                                struct lc709203f_platform_data *pdata)
 {
@@ -347,6 +367,14 @@ static void of_lc709203f_parse_platform_data(struct i2c_client *client,
                pdata->maximum_soc = pval;
        else
                pdata->maximum_soc = 100;
+
+       ret = of_property_read_u32(np, "onsemi,alert-low-rsoc", &pval);
+       if (!ret)
+               pdata->alert_low_rsoc = pval;
+
+       ret = of_property_read_u32(np, "onsemi,alert-low-voltage", &pval);
+       if (!ret)
+               pdata->alert_low_voltage = pval;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -456,6 +484,20 @@ static int lc709203f_probe(struct i2c_client *client,
                        chip->pdata->initial_rsoc);
        }
 
+       ret = lc709203f_write_word(chip->client,
+               LC709203F_ALARM_LOW_CELL_RSOC, chip->pdata->alert_low_rsoc);
+       if (ret < 0) {
+               dev_err(&client->dev, "LOW_RSOC write failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = lc709203f_write_word(chip->client,
+               LC709203F_ALARM_LOW_CELL_VOLT, chip->pdata->alert_low_voltage);
+       if (ret < 0) {
+               dev_err(&client->dev, "LOW_VOLT write failed: %d\n", ret);
+               return ret;
+       }
+
        if (chip->pdata->appli_adjustment) {
                ret = lc709203f_write_word(chip->client,
                        LC709203F_ADJUSTMENT_PACK_APPLI,
@@ -525,7 +567,24 @@ skip_thermistor_config:
 
        lc709203f_debugfs_init(client);
 
+       if (client->irq) {
+               ret = devm_request_threaded_irq(&client->dev, client->irq,
+                       NULL, lc709203f_irq,
+                       IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+                       dev_name(&client->dev), chip);
+               if (ret < 0) {
+                       dev_err(&client->dev,
+                               "%s: request IRQ %d fail, err = %d\n",
+                               __func__, client->irq, ret);
+                       client->irq = 0;
+                       goto irq_reg_error;
+               }
+       }
+       device_set_wakeup_capable(&client->dev, 1);
+
        return 0;
+irq_reg_error:
+       cancel_delayed_work_sync(&chip->work);
 bg_err:
        power_supply_unregister(&chip->battery);
 error:
@@ -562,12 +621,20 @@ static int lc709203f_suspend(struct device *dev)
 {
        struct lc709203f_chip *chip = dev_get_drvdata(dev);
        cancel_delayed_work_sync(&chip->work);
+
+       if (device_may_wakeup(&chip->client->dev))
+               enable_irq_wake(chip->client->irq);
+
        return 0;
 }
 
 static int lc709203f_resume(struct device *dev)
 {
        struct lc709203f_chip *chip = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(&chip->client->dev))
+               disable_irq_wake(chip->client->irq);
+
        schedule_delayed_work(&chip->work, LC709203F_DELAY);
        return 0;
 }