@@ -6,6 +6,7 @@
* Andrew F. Davis <afd@ti.com>
*/
+#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -139,8 +140,10 @@ static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di,
static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ const struct acpi_device_id *acpi_id = NULL;
struct device *dev = &client->dev;
struct bq27xxx_device_info *di;
+ unsigned long irqflags = 0;
int ret;
char *name;
int num;
@@ -152,17 +155,31 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
if (num < 0)
return num;
- name = devm_kasprintf(dev, GFP_KERNEL, "%s-%d", id->name, num);
- if (!name)
- goto err_mem;
-
di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL);
if (!di)
goto err_mem;
+ if (id) {
+ di->chip = id->driver_data;
+ } else {
+ acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!acpi_id)
+ return -ENODEV;
+
+ irqflags = IRQF_TRIGGER_RISING;
+ di->chip = acpi_id->driver_data;
+ }
+
+ if (acpi_id && num == 0) {
+ name = "main-battery";
+ } else {
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s-%d", id->name, num);
+ if (!name)
+ goto err_mem;
+ }
+
di->id = num;
di->dev = dev;
- di->chip = id->driver_data;
di->name = name;
di->bus.read = bq27xxx_battery_i2c_read;
@@ -182,7 +199,7 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
if (client->irq) {
ret = devm_request_threaded_irq(dev, client->irq,
NULL, bq27xxx_battery_irq_handler_thread,
- IRQF_ONESHOT,
+ irqflags | IRQF_ONESHOT,
di->name, di);
if (ret) {
dev_err(dev, "Unable to register IRQ %d error %d\n",
@@ -292,10 +309,19 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = {
MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table);
#endif
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id bq27xxx_acpi_match[] = {
+ { "TXN27520", BQ2752X },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, bq27xxx_acpi_match);
+#endif
+
static struct i2c_driver bq27xxx_battery_i2c_driver = {
.driver = {
.name = "bq27xxx-battery",
.of_match_table = of_match_ptr(bq27xxx_battery_i2c_of_match_table),
+ .acpi_match_table = ACPI_PTR(bq27xxx_acpi_match),
},
.probe = bq27xxx_battery_i2c_probe,
.remove = bq27xxx_battery_i2c_remove,
Some x86/ACPI devices with a bq27xxx fuel-gauge do not use the standard ACPI battery API for battery monitoring. Instead they have an ACPI device describing the actual fuel-gauge IC and expect the OS to have a native driver for the fuel-gauge. Add support for such ACPI enumerated bq27xxx fuel-gauges. To get the fuel-gauge to work properly on ACPI devs 3 changes are needed: 1. Add an acpi_match_table and set di->chip based on this, note the new "if (id) check also fixes a NULL pointer deref when someone tries to manually bind the driver from sysfs. 2. When the charger IC has external power applied or removed, the psy-core should call bq27xxx_external_power_changed(). This requires a valid consumer<->supplier link between the charger and the fuel-gauge power-supplies. For ACPI enumerated fuel-gauges this link is missing. The charger-ICs used on these devices already contain a special power_supply_config.supplied_to default set to "main-battery". This commit makes use of this by setting the power-supply's name to "main-battery" when enumerated by ACPI, to establish the missing consumer<->supplier link. 3. Sometimes the irqflags in the ACPI tables are no good, override them. Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- drivers/power/supply/bq27xxx_battery_i2c.c | 38 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-)