Merge "power: supply: bq256xx: Register interrupt after extcon"

This commit is contained in:
QCTECMDR Service 2024-10-03 23:58:39 -07:00 committed by Gerrit - the friendly Code Review server
commit e544433d30

View file

@ -18,6 +18,8 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/extcon-provider.h>
#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#define BQ256XX_MANUFACTURER "Texas Instruments"
@ -145,6 +147,8 @@
#define BQ256XX_REG_RST BIT(7)
#define BQ256XX_MAX_INPUT_VOLTAGE_UV 5400000
/**
* struct bq256xx_init_data -
* @ichg: fast charge current
@ -216,6 +220,7 @@ enum bq256xx_id {
* @charger: power supply registered for the charger
* @battery: power supply registered for the battery
* @lock: mutex lock structure
* @irq_lock: mutex lock structure for irq
*
* @usb2_phy: usb_phy identifier
* @usb3_phy: usb_phy identifier
@ -229,6 +234,9 @@ enum bq256xx_id {
* @chip_info: device variant information
* @state: device status and faults
* @watchdog_timer: watchdog timer value in milliseconds
*
* @irq_waiting: flag for status of irq waiting
* @resume_completed: suspend/resume flag
*/
struct bq256xx_device {
struct i2c_client *client;
@ -236,6 +244,8 @@ struct bq256xx_device {
struct power_supply *charger;
struct power_supply *battery;
struct mutex lock;
struct mutex irq_lock;
struct regmap *regmap;
struct usb_phy *usb2_phy;
@ -252,6 +262,11 @@ struct bq256xx_device {
int watchdog_timer;
/* extcon for VBUS / ID notification to USB*/
struct extcon_dev *extcon;
bool irq_waiting;
bool resume_completed;
/* debug_board_gpio to deteect the debug board*/
int debug_board_gpio;
};
/**
@ -1170,6 +1185,15 @@ static irqreturn_t bq256xx_irq_handler_thread(int irq, void *private)
struct bq256xx_state state;
int ret;
mutex_lock(&bq->irq_lock);
bq->irq_waiting = true;
if (!bq->resume_completed) {
pr_debug("IRQ triggered before device-resume\n");
disable_irq_nosync(irq);
mutex_unlock(&bq->irq_lock);
return IRQ_HANDLED;
}
ret = bq256xx_get_state(bq, &state);
if (ret < 0)
goto irq_out;
@ -1184,6 +1208,8 @@ static irqreturn_t bq256xx_irq_handler_thread(int irq, void *private)
power_supply_changed(bq->charger);
irq_out:
bq->irq_waiting = false;
mutex_unlock(&bq->irq_lock);
return IRQ_HANDLED;
}
@ -1524,6 +1550,30 @@ static int bq256xx_power_supply_init(struct bq256xx_device *bq,
return 0;
}
static int bq256xx_debug_board_detect(struct bq256xx_device *bq)
{
int ret = 0;
if (!of_find_property(bq->dev->of_node, "debugboard-detect-gpio", NULL))
return ret;
bq->debug_board_gpio = of_get_named_gpio(bq->dev->of_node,
"debugboard-detect-gpio", 0);
if (IS_ERR(&bq->debug_board_gpio)) {
ret = PTR_ERR(&bq->debug_board_gpio);
dev_err(bq->dev, "Failed to initialize debugboard_detecte gpio\n");
return ret;
}
gpio_direction_input(bq->debug_board_gpio);
if (gpio_get_value(bq->debug_board_gpio)) {
bq->init_data.vindpm = BQ256XX_MAX_INPUT_VOLTAGE_UV;
dev_info(bq->dev,
"debug_board detected, setting vindpm to %d\n", bq->init_data.vindpm);
}
return ret;
}
static int bq256xx_hw_init(struct bq256xx_device *bq)
{
struct power_supply_battery_info *bat_info;
@ -1579,6 +1629,10 @@ static int bq256xx_hw_init(struct bq256xx_device *bq)
bat_info->constant_charge_voltage_max_uv;
}
ret = bq256xx_debug_board_detect(bq);
if (ret)
return ret;
ret = bq->chip_info->bq256xx_set_vindpm(bq, bq->init_data.vindpm);
if (ret)
return ret;
@ -1661,8 +1715,10 @@ static int bq256xx_probe(struct i2c_client *client,
bq->client = client;
bq->dev = dev;
bq->chip_info = &bq256xx_chip_info_tbl[id->driver_data];
bq->resume_completed = true;
mutex_init(&bq->lock);
mutex_init(&bq->irq_lock);
strncpy(bq->model_name, id->name, I2C_NAME_SIZE);
@ -1701,18 +1757,6 @@ static int bq256xx_probe(struct i2c_client *client,
usb_register_notifier(bq->usb3_phy, &bq->usb_nb);
}
if (client->irq) {
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq256xx_irq_handler_thread,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
dev_name(&client->dev), bq);
if (ret < 0) {
dev_err(dev, "get irq fail: %d\n", ret);
return ret;
}
}
ret = bq256xx_power_supply_init(bq, &psy_cfg, dev);
if (ret) {
dev_err(dev, "Failed to register power supply\n");
@ -1747,6 +1791,23 @@ static int bq256xx_probe(struct i2c_client *client,
extcon_set_state_sync(bq->extcon, EXTCON_USB, !!state.vbus_gd);
if (client->irq) {
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq256xx_irq_handler_thread,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
dev_name(&client->dev), bq);
if (ret < 0) {
dev_err(dev, "get irq fail: %d\n", ret);
return ret;
}
enable_irq_wake(client->irq);
}
dev_dbg(dev, "bq256xx successfully probed. charger=0x%x\n",
state.vbus_gd);
return ret;
}
@ -1786,11 +1847,61 @@ static const struct acpi_device_id bq256xx_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, bq256xx_acpi_match);
static int bq256xx_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bq256xx_device *bq = i2c_get_clientdata(client);
mutex_lock(&bq->irq_lock);
bq->resume_completed = false;
mutex_unlock(&bq->irq_lock);
return 0;
}
static int bq256xx_suspend_noirq(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bq256xx_device *bq = i2c_get_clientdata(client);
if (bq->irq_waiting) {
dev_err_ratelimited(dev, "Aborting suspend, an interrupt was detected while suspending\n");
return -EBUSY;
}
return 0;
}
static int bq256xx_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bq256xx_device *bq = i2c_get_clientdata(client);
mutex_lock(&bq->irq_lock);
bq->resume_completed = true;
mutex_unlock(&bq->irq_lock);
if (bq->irq_waiting) {
/* irq was pending, call the handler */
bq256xx_irq_handler_thread(client->irq, bq);
enable_irq(client->irq);
}
return 0;
}
static const struct dev_pm_ops bq256xx_pm_ops = {
.suspend = bq256xx_suspend,
.suspend_noirq = bq256xx_suspend_noirq,
.resume = bq256xx_resume,
};
static struct i2c_driver bq256xx_driver = {
.driver = {
.name = "bq256xx-charger",
.of_match_table = bq256xx_of_match,
.acpi_match_table = bq256xx_acpi_match,
.pm = &bq256xx_pm_ops,
},
.probe = bq256xx_probe,
.id_table = bq256xx_i2c_ids,