[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20211031162428.22368-6-hdegoede@redhat.com>
Date: Sun, 31 Oct 2021 17:24:28 +0100
From: Hans de Goede <hdegoede@...hat.com>
To: "Rafael J . Wysocki" <rjw@...ysocki.net>,
Mika Westerberg <mika.westerberg@...ux.intel.com>,
Mark Gross <markgross@...nel.org>,
Andy Shevchenko <andy@...radead.org>,
Wolfram Sang <wsa@...-dreams.de>,
Sebastian Reichel <sre@...nel.org>,
MyungJoo Ham <myungjoo.ham@...sung.com>,
Chanwoo Choi <cw00.choi@...sung.com>,
Ard Biesheuvel <ardb@...nel.org>
Cc: Hans de Goede <hdegoede@...hat.com>, Len Brown <lenb@...nel.org>,
linux-acpi@...r.kernel.org, Yauhen Kharuzhy <jekhor@...il.com>,
Tsuchiya Yuto <kitakar@...il.com>,
platform-driver-x86@...r.kernel.org, linux-i2c@...r.kernel.org,
linux-pm@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-efi@...r.kernel.org
Subject: [RFC 5/5] power: supply: bq27xxx: Add support for ACPI enumeration
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@...hat.com>
---
drivers/power/supply/bq27xxx_battery_i2c.c | 38 ++++++++++++++++++----
1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c
index 0a1b922389e1..c3fe1e4b08bd 100644
--- a/drivers/power/supply/bq27xxx_battery_i2c.c
+++ b/drivers/power/supply/bq27xxx_battery_i2c.c
@@ -6,6 +6,7 @@
* Andrew F. Davis <afd@...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,
--
2.31.1
Powered by blists - more mailing lists