From 4e207a47ef04f50d9f9800bdf984663c87f2402a Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Wed, 18 Mar 2020 21:00:19 -0700 Subject: [PATCH] power: supply: qti_battery_charger: add SSR support Add subsystem restart (SSR) support to battery charger driver so that it can stop read/write properties when subsystem goes down. Also, send message to enable notification again once subsystem comes up. Change-Id: I64f3abfa1d12c4e6a65fd01d7f66155c8741e68a Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qti_battery_charger.c | 59 ++++++++++++++++++---- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index 205147504130..6110b9f78e76 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -148,6 +148,8 @@ struct battery_chg_dev { u32 *thermal_levels; int curr_thermal_level; int num_thermal_levels; + atomic_t state; + struct work_struct subsys_up_work; }; static const int battery_prop_map[BATT_PROP_MAX] = { @@ -198,6 +200,16 @@ static int battery_chg_write(struct battery_chg_dev *bcdev, void *data, { int rc; + /* + * When the subsystem goes down, it's better to return the last + * known values until it comes back up. Hence, return 0 so that + * pmic_glink_write() is not attempted until pmic glink is up. + */ + if (atomic_read(&bcdev->state) == PMIC_GLINK_STATE_DOWN) { + pr_debug("glink state is down\n"); + return 0; + } + mutex_lock(&bcdev->rw_lock); reinit_completion(&bcdev->ack); rc = pmic_glink_write(bcdev->client, data, len); @@ -268,6 +280,40 @@ static int get_property_id(struct psy_state *pst, return -ENOENT; } +static void battery_chg_notify_enable(struct battery_chg_dev *bcdev) +{ + struct battery_charger_set_notify_msg req_msg = { { 0 } }; + int rc; + + /* Send request to enable notification */ + req_msg.hdr.owner = MSG_OWNER_BC; + req_msg.hdr.type = MSG_TYPE_NOTIFY; + req_msg.hdr.opcode = BC_SET_NOTIFY_REQ; + + rc = battery_chg_write(bcdev, &req_msg, sizeof(req_msg)); + if (rc < 0) + pr_err("Failed to enable notification rc=%d\n", rc); +} + +static void battery_chg_subsys_up_work(struct work_struct *work) +{ + struct battery_chg_dev *bcdev = container_of(work, + struct battery_chg_dev, subsys_up_work); + + battery_chg_notify_enable(bcdev); +} + +static void battery_chg_state_cb(void *priv, enum pmic_glink_state state) +{ + struct battery_chg_dev *bcdev = priv; + + pr_debug("state: %d\n", state); + + atomic_set(&bcdev->state, state); + if (state == PMIC_GLINK_STATE_UP) + schedule_work(&bcdev->subsys_up_work); +} + /** * qti_battery_charger_get_prop() - Gets the property being requested * @@ -977,7 +1023,6 @@ static int battery_chg_probe(struct platform_device *pdev) struct battery_chg_dev *bcdev; struct device *dev = &pdev->dev; struct pmic_glink_client_data client_data = { }; - struct battery_charger_set_notify_msg req_msg = { { 0 } }; int rc, i; bcdev = devm_kzalloc(&pdev->dev, sizeof(*bcdev), GFP_KERNEL); @@ -1012,12 +1057,15 @@ static int battery_chg_probe(struct platform_device *pdev) mutex_init(&bcdev->rw_lock); init_completion(&bcdev->ack); + INIT_WORK(&bcdev->subsys_up_work, battery_chg_subsys_up_work); + atomic_set(&bcdev->state, PMIC_GLINK_STATE_UP); bcdev->dev = dev; client_data.id = MSG_OWNER_BC; client_data.name = "battery_charger"; client_data.msg_cb = battery_chg_callback; client_data.priv = bcdev; + client_data.state_cb = battery_chg_state_cb; bcdev->client = pmic_glink_register_client(dev, &client_data); if (IS_ERR(bcdev->client)) { @@ -1045,14 +1093,7 @@ static int battery_chg_probe(struct platform_device *pdev) goto error; } - /* Send request to enable notification */ - req_msg.hdr.owner = MSG_OWNER_BC; - req_msg.hdr.type = MSG_TYPE_NOTIFY; - req_msg.hdr.opcode = BC_SET_NOTIFY_REQ; - - rc = battery_chg_write(bcdev, &req_msg, sizeof(req_msg)); - if (rc < 0) - pr_err("Failed to enable notification rc=%d\n", rc); + battery_chg_notify_enable(bcdev); return 0; error: