kernel-power v49 -> kernel-bfs
[kernel-bfs] / kernel-bfs-2.6.28 / debian / patches / bq27x00-upstream.diff
index abe9637..4e59166 100644 (file)
@@ -1,5 +1,5 @@
---- kernel-power-2.6.28/drivers/power/bq27x00_battery.c        2011-09-15 00:34:44.600070307 +0200
-+++ kernel-power-2.6.28/drivers/power/bq27x00_battery.c        2011-09-21 13:16:45.007978008 +0200
+--- kernel-power-2.6.28/drivers/power/bq27x00_battery.c        2011-10-09 17:10:05.891697314 +0200
++++ kernel-power-2.6.28/drivers/power/bq27x00_battery.c        2011-10-31 22:08:03.185443335 +0100
 @@ -3,6 +3,8 @@
   *
   * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
@@ -9,7 +9,7 @@
   *
   * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
   *
-@@ -15,6 +17,13 @@
+@@ -15,153 +17,488 @@
   * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   *
   */
  #include <linux/module.h>
  #include <linux/param.h>
  #include <linux/jiffies.h>
-@@ -24,144 +33,455 @@
+ #include <linux/workqueue.h>
+ #include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
+ #include <linux/platform_device.h>
  #include <linux/power_supply.h>
  #include <linux/idr.h>
  #include <linux/i2c.h>
 +#include <linux/slab.h>
  #include <asm/unaligned.h>
++#include <asm/uaccess.h>
++
++#include <linux/power/bq27x00_battery.h>
  
 -#define DRIVER_VERSION                        "1.0.0"
-+#include <linux/power/bq27x00_battery.h>
-+
 +#define DRIVER_VERSION                        "1.2.0"
  
  #define BQ27x00_REG_TEMP              0x06
 +      int capacity;
 +      int energy;
 +      int flags;
++};
++
++struct bq27x00_reg_device {
++      struct miscdevice miscdev;
++      struct bq27x00_device_info *di;
++      struct list_head list;
  };
  
  struct bq27x00_device_info {
        struct device           *dev;
++      struct bq27x00_reg_device *regdev;
        int                     id;
 -      int                     voltage_uV;
 -      int                     current_uA;
 +MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \
 +                              "0 disables polling");
 +
++/* If the system has several batteries we need a different name for each
++ * of them...
++ */
++static DEFINE_IDR(battery_id);
++static DEFINE_MUTEX(battery_mutex);
++static LIST_HEAD(battery_list);
++
  /*
   * Common code for BQ27x00 devices
   */
 -      int ret;
 +      return di->bus.read(di, reg, single);
 +}
--      ret = di->bus->read(reg, rt_value, b_single, di);
--      *rt_value = be16_to_cpu(*rt_value);
++
 +/*
 + * Return the battery Relative State-of-Charge
 + * Or < 0 if something fails.
 +{
 +      int rsoc;
  
--      return ret;
+-      ret = di->bus->read(reg, rt_value, b_single, di);
+-      *rt_value = be16_to_cpu(*rt_value);
 +      if (di->chip == BQ27500)
 +              rsoc = bq27x00_read(di, BQ27500_REG_SOC, false);
 +      else
 +              rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true);
-+
+-      return ret;
 +      if (rsoc < 0)
-+              dev_err(di->dev, "error reading relative State-of-Charge\n");
++              dev_dbg(di->dev, "error reading relative State-of-Charge\n");
 +
 +      return rsoc;
  }
 -      if (ret) {
 +      charge = bq27x00_read(di, reg, false);
 +      if (charge < 0) {
-+              dev_err(di->dev, "error reading charge register %02x: %d\n", reg, charge);
++              dev_dbg(di->dev, "error reading charge register %02x: %d\n", reg, charge);
 +              return charge;
 +      }
 +
 +              ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true);
 +
 +      if (ilmd < 0) {
-+              dev_err(di->dev, "error reading initial last measured discharge\n");
++              dev_dbg(di->dev, "error reading initial last measured discharge\n");
 +              return ilmd;
 +      }
 +
 +
 +      ae = bq27x00_read(di, BQ27x00_REG_AE, false);
 +      if (ae < 0) {
-+              dev_err(di->dev, "error reading available energy\n");
++              dev_dbg(di->dev, "error reading available energy\n");
 +              return ae;
 +      }
 +
 +
 +      tval = bq27x00_read(di, reg, false);
 +      if (tval < 0) {
-+              dev_err(di->dev, "error reading time register %02x: %d\n", reg, tval);
++              dev_dbg(di->dev, "error reading time register %02x: %d\n", reg, tval);
 +              return tval;
 +      }
 +
 +      cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500);
 +      if (cache.flags >= 0) {
 +              if (!is_bq27500 && (cache.flags & BQ27000_FLAG_CI)) {
-+                      dev_err(di->dev, "battery is not calibrated! ignoring capacity values\n");
++                      dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n");
 +                      cache.capacity = -ENODATA;
 +                      cache.energy = -ENODATA;
 +                      cache.time_to_empty = -ENODATA;
 +              /* We only have to read charge design full once */
 +              if (di->charge_design_full <= 0)
 +                      di->charge_design_full = bq27x00_battery_read_ilmd(di);
-+      }
-+
-+      if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) {
-+              di->cache = cache;
-+              power_supply_changed(&di->bat);
        }
  
 -      return volt;
++      if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) {
++              di->cache = cache;
++              power_supply_changed(&di->bat);
++      }
++
 +      di->last_update = jiffies;
 +}
 +
  
 -      ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
 -      if (ret) {
--              dev_err(di->dev, "error reading current\n");
--              return 0;
 +      curr = bq27x00_read(di, BQ27x00_REG_AI, false);
 +      if (curr < 0) {
-+              dev_err(di->dev, "error reading current");
+               dev_err(di->dev, "error reading current\n");
+-              return 0;
 +              return curr;
 +      }
 +
  }
  
  #define to_bq27x00_device_info(x) container_of((x), \
-@@ -171,89 +491,167 @@ static int bq27x00_battery_get_property(
+@@ -171,89 +508,278 @@ static int bq27x00_battery_get_property(
                                        enum power_supply_property psp,
                                        union power_supply_propval *val)
  {
                return -EINVAL;
        }
  
--      return 0;
 +      return ret;
- }
--static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
++}
++
 +static void bq27x00_external_power_changed(struct power_supply *psy)
- {
++{
 +      struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
 +
 +      cancel_delayed_work_sync(&di->work);
 +      schedule_delayed_work(&di->work, 0);
 +}
 +
-+static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
++/* Code for register device access */
++
++static struct bq27x00_reg_device * bq27x00_battery_reg_find_device(int minor)
++{
++      struct bq27x00_reg_device *regdev;
++
++      list_for_each_entry(regdev, &battery_list, list)
++              if (regdev->miscdev.minor == minor)
++                      return regdev;
++
++      return NULL;
++}
++
++static long bq27x00_battery_reg_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 +{
 +      int ret;
++      int minor = iminor(filp->f_dentry->d_inode);
++      struct bq27x00_reg_parms param;
++      struct bq27x00_reg_device *regdev = bq27x00_battery_reg_find_device(minor);
++
++      if (!regdev)
++              return -ENXIO;
++
++      if (cmd != BQ27X00_READ_REG)
++              return -EINVAL;
++
++      ret = copy_from_user(&param, (void __user *)arg, sizeof(param));
++      if (ret != 0)
++              return -EACCES;
++
++      param.ret = bq27x00_read(regdev->di, param.reg, param.single);
++
++      ret = copy_to_user((void __user *)arg, &param, sizeof(param));
++      if (ret != 0)
++              return -EACCES;
++
++      return 0;
++}
++
++static int bq27x00_battery_reg_open(struct inode *inode, struct file *file)
++{
++      if (!try_module_get(THIS_MODULE))
++              return -EPERM;
++
++      return 0;
++}
++
++static int bq27x00_battery_reg_release(struct inode *inode, struct file *file)
++{
++      module_put(THIS_MODULE);
++      return 0;
++}
++
++static struct file_operations bq27x00_reg_fileops = {
++      .owner = THIS_MODULE,
++      .unlocked_ioctl = bq27x00_battery_reg_ioctl,
++      .open = bq27x00_battery_reg_open,
++      .release = bq27x00_battery_reg_release,
++};
++
++static int bq27x00_battery_reg_init(struct bq27x00_device_info *di)
++{
++      struct bq27x00_reg_device *regdev;
++      int ret;
++
++      di->regdev = NULL;
++
++      regdev = kzalloc(sizeof *regdev, GFP_KERNEL);
++      if (!regdev)
++              return -ENOMEM;
++
++      regdev->miscdev.minor = MISC_DYNAMIC_MINOR;
++      regdev->miscdev.name = di->bat.name;
++      regdev->miscdev.fops = &bq27x00_reg_fileops;
++
++      ret = misc_register(&regdev->miscdev);
++      if (ret != 0) {
++              kfree(regdev);
++              return ret;
++      }
++
++      regdev->di = di;
++      di->regdev = regdev;
++
++      INIT_LIST_HEAD(&regdev->list);
++
++      mutex_lock(&battery_mutex);
++      list_add(&regdev->list, &battery_list);
++      mutex_unlock(&battery_mutex);
++
+       return 0;
+ }
+-static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
++static void bq27x00_battery_reg_exit(struct bq27x00_device_info *di)
++{
++      if (!di->regdev)
++              return;
++
++      misc_deregister(&di->regdev->miscdev);
++
++      mutex_lock(&battery_mutex);
++      list_del(&di->regdev->list);
++      mutex_unlock(&battery_mutex);
++
++      kfree(di->regdev);
++      di->regdev = NULL;
++}
++
++static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
+ {
++      int ret;
 +
        di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
        di->bat.properties = bq27x00_battery_props;
 +      dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 +
 +      bq27x00_update(di);
++      bq27x00_battery_reg_init(di);
 +
 +      return 0;
  }
  
 -/*
 - * BQ27200 specific code
+- */
 +static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di)
 +{
++      /* power_supply_unregister call bq27x00_battery_get_property which call bq27x00_battery_poll */
++      /* make sure that bq27x00_battery_poll will not call schedule_delayed_work again after unregister (which cause OOPS) */
++      poll_interval = 0;
++
 +      cancel_delayed_work_sync(&di->work);
 +
++      bq27x00_battery_reg_exit(di);
+-static int bq27200_read(u8 reg, int *rt_value, int b_single,
+-                      struct bq27x00_device_info *di)
 +      power_supply_unregister(&di->bat);
 +
 +      mutex_destroy(&di->lock);
 +/* i2c specific code */
 +#ifdef CONFIG_BATTERY_BQ27X00_I2C
 +
-+/* If the system has several batteries we need a different name for each
-+ * of them...
-  */
-+static DEFINE_IDR(battery_id);
-+static DEFINE_MUTEX(battery_mutex);
--static int bq27200_read(u8 reg, int *rt_value, int b_single,
--                      struct bq27x00_device_info *di)
 +static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single)
  {
 -      struct i2c_client *client = di->client;
 +              msg[1].len = 1;
 +      else
 +              msg[1].len = 2;
++
++      mutex_lock(&battery_mutex);
++      ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
++      mutex_unlock(&battery_mutex);
++      if (ret < 0)
++              return ret;
  
 -              msg->flags = I2C_M_RD;
 -              err = i2c_transfer(client->adapter, msg, 1);
 -                              *rt_value = get_unaligned_be16(data);
 -                      else
 -                              *rt_value = data[0];
-+      ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
-+      if (ret < 0)
-+              return ret;
++      if (!single)
++              ret = get_unaligned_le16(data);
++      else
++              ret = data[0];
  
 -                      return 0;
 -              }
 -      }
 -      return err;
-+      if (!single)
-+              ret = get_unaligned_le16(data);
-+      else
-+              ret = data[0];
-+
 +      return ret;
  }
  
        int num;
        int retval = 0;
  
-@@ -267,7 +665,7 @@ static int bq27200_battery_probe(struct
+@@ -267,7 +793,7 @@ static int bq27200_battery_probe(struct
        if (retval < 0)
                return retval;
  
        if (!name) {
                dev_err(&client->dev, "failed to allocate device name\n");
                retval = -ENOMEM;
-@@ -280,37 +678,20 @@ static int bq27200_battery_probe(struct
+@@ -280,37 +806,20 @@ static int bq27200_battery_probe(struct
                retval = -ENOMEM;
                goto batt_failed_2;
        }
  batt_failed_3:
        kfree(di);
  batt_failed_2:
-@@ -323,11 +704,11 @@ batt_failed_1:
+@@ -323,11 +832,11 @@ batt_failed_1:
        return retval;
  }
  
  
        kfree(di->bat.name);
  
-@@ -340,31 +721,180 @@ static int bq27200_battery_remove(struct
+@@ -340,31 +849,180 @@ static int bq27200_battery_remove(struct
        return 0;
  }
  
 +              dev_err(&pdev->dev, "no hdq read callback supplied\n");
 +              return -EINVAL;
 +      }
-+
+-static struct i2c_driver bq27200_battery_driver = {
 +      di = kzalloc(sizeof(*di), GFP_KERNEL);
 +      if (!di) {
 +              dev_err(&pdev->dev, "failed to allocate device info data\n");
 +
 +      di->bat.name = pdata->name ?: dev_name(&pdev->dev);
 +      di->bus.read = &bq27000_read_platform;
--static struct i2c_driver bq27200_battery_driver = {
++
 +      ret = bq27x00_powersupply_init(di);
 +      if (ret)
 +              goto err_free;
  
        return ret;
  }
-@@ -372,7 +902,8 @@ module_init(bq27x00_battery_init);
+@@ -372,7 +1030,8 @@ module_init(bq27x00_battery_init);
  
  static void __exit bq27x00_battery_exit(void)
  {