From 92fb2212420d0376c83a4baa3cf9f270f57a940e Mon Sep 17 00:00:00 2001
From: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Date: Tue, 18 Jun 2019 18:57:04 +0200
Subject: [PATCH] power: tcl-sbs-battery: Expose a battery_reset attribute to
 userspace

Writing a '1' to this attribute should trigger a reset on battery
status and return the battery to its default values. This attribute is
used to init a battery after replacement.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
---
 drivers/power/supply/tcl-sbs-battery.c | 53 ++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/power/supply/tcl-sbs-battery.c b/drivers/power/supply/tcl-sbs-battery.c
index 5d4f2cf63fd6..1bf34dcef318 100644
--- a/drivers/power/supply/tcl-sbs-battery.c
+++ b/drivers/power/supply/tcl-sbs-battery.c
@@ -63,6 +63,9 @@
 /* Firmware version, 1 byte */
 #define SBS_FIRMWARE_VERSION		0x7d
 
+/* Command to reset battery after replacement */
+#define SBS_CMD_BATTERY_RESET		(SBS_MEMORY_MAP_SIZE + 1)
+
 /* MM SIZE + START(u16) + CHECKSUM(u16) */
 #define SPI_MSG_LENGTH		(SBS_MEMORY_MAP_SIZE + 4)
 #define SPI_MSG_DATA_BP		2
@@ -450,7 +453,57 @@ static ssize_t tcl_sbs_battery_program_store(struct device *dev,
 static DEVICE_ATTR(program, 0644, tcl_sbs_battery_program_show,
 		   tcl_sbs_battery_program_store);
 
+static ssize_t battery_reset_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf,
+				   size_t count)
+{
+	struct tcl_sbs_battery_data *data = dev_get_drvdata(dev->parent);
+	struct spi_device *spi = data->spi;
+	u8 cmd, res;
+	bool reset;
+	int err;
+
+	err = kstrtobool(buf, &reset);
+	if (err)
+		return err;
+	if (!reset)
+		return count;
+
+	/* stop polling the MCU */
+	cancel_delayed_work_sync(&data->bat_work);
+
+	cmd = SBS_CMD_BATTERY_RESET;
+	err = spi_write(spi, &cmd, 1);
+	if (err) {
+		dev_err(&spi->dev, "failed to write command\n");
+		count = err;
+		goto restart_delayed_work;
+	}
+
+	err = spi_read(spi, &res, 1);
+	if (err) {
+		dev_err(&spi->dev, "failed to read command result\n");
+		count = err;
+		goto restart_delayed_work;
+	}
+
+	if (res) {
+		dev_err(&spi->dev, "invalid command %u\n", cmd);
+		count = -EINVAL;
+	}
+
+restart_delayed_work:
+	/* re-start polling the MCU */
+	schedule_delayed_work(&data->bat_work, 0);
+
+	return count;
+}
+
+static DEVICE_ATTR_WO(battery_reset);
+
 static struct attribute *tcl_sbs_battery_attrs[] = {
+	&dev_attr_battery_reset.attr,
 	&dev_attr_fw_version.attr,
 	&dev_attr_program.attr,
 	NULL,
-- 
GitLab