Merge "power: supply: bq256xx: Register interrupt after extcon"
This commit is contained in:
commit
e544433d30
1 changed files with 123 additions and 12 deletions
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue