[RFC,2/3] watchdog: da9062: avoid regmap in restart handler

Message ID 20181007153937.16787-3-contact@stefanchrist.eu
State New
Headers show
Series
  • [RFC,1/3] i2c: imx: implement master_xfer_irqless callback
Related show

Commit Message

Stefan Lengfeld Oct. 7, 2018, 3:39 p.m.
Using i2c_transfer() directly to set the shutdown bit is more reliable
than using regmap in atomic contexts, because calls to 'schedule()' or
'sleep()' must be avoided in call code paths.

Tested on a phyCORE-i.MX6 Solo board.

Signed-off-by: Stefan Lengfeld <contact@stefanchrist.eu>
---
 drivers/mfd/da9062-core.c       |  1 +
 drivers/watchdog/da9062_wdt.c   | 17 +++++++++++++----
 include/linux/mfd/da9062/core.h |  1 +
 3 files changed, 15 insertions(+), 4 deletions(-)

Comments

Andy Shevchenko Oct. 8, 2018, 10:07 a.m. | #1
On Sun, Oct 07, 2018 at 05:39:36PM +0200, Stefan Lengfeld wrote:
> Using i2c_transfer() directly to set the shutdown bit is more reliable
> than using regmap in atomic contexts, because calls to 'schedule()' or
> 'sleep()' must be avoided in call code paths.

>  #include <linux/platform_device.h>
>  #include <linux/uaccess.h>
>  #include <linux/slab.h>
> +#include <linux/i2c.h>
>  #include <linux/delay.h>
>  #include <linux/jiffies.h>
>  #include <linux/mfd/da9062/registers.h>

The rule of thumb when extending a header inclusion block is that try to
squeeze the new inclusion in the longest sorted part of the list.

Rationale behind is easy maintenance.

Patch

diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
index 9f6105906c09..b6a01054ba0f 100644
--- a/drivers/mfd/da9062-core.c
+++ b/drivers/mfd/da9062-core.c
@@ -609,6 +609,7 @@  static int da9062_i2c_probe(struct i2c_client *i2c,
 
 	i2c_set_clientdata(i2c, chip);
 	chip->dev = &i2c->dev;
+	chip->i2c = i2c;
 
 	if (!i2c->irq) {
 		dev_err(chip->dev, "No IRQ configured\n");
diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c
index fe169d8e1fb2..ad6483d25f83 100644
--- a/drivers/watchdog/da9062_wdt.c
+++ b/drivers/watchdog/da9062_wdt.c
@@ -11,6 +11,7 @@ 
 #include <linux/platform_device.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/jiffies.h>
 #include <linux/mfd/da9062/registers.h>
@@ -152,12 +153,20 @@  static int da9062_wdt_restart(struct watchdog_device *wdd, unsigned long action,
 			      void *data)
 {
 	struct da9062_watchdog *wdt = watchdog_get_drvdata(wdd);
+	struct i2c_client *client = wdt->hw->i2c;
+	__u8 buf[3] = {DA9062AA_CONTROL_F, DA9062AA_SHUTDOWN_MASK, 0x0};
+	struct i2c_msg msgs[1] = {
+		{
+			.addr = client->addr,
+			.flags = (client->flags & I2C_M_TEN),
+			.len = sizeof(buf),
+			.buf = buf,
+		}
+	};
 	int ret;
 
-	ret = regmap_write(wdt->hw->regmap,
-			   DA9062AA_CONTROL_F,
-			   DA9062AA_SHUTDOWN_MASK);
-	if (ret)
+	ret = i2c_transfer(client->adapter, msgs, sizeof(msgs));
+	if (ret < 0)
 		dev_alert(wdt->hw->dev, "Failed to shutdown (err = %d)\n",
 			  ret);
 
diff --git a/include/linux/mfd/da9062/core.h b/include/linux/mfd/da9062/core.h
index 74d33a01ddae..c994293b3aef 100644
--- a/include/linux/mfd/da9062/core.h
+++ b/include/linux/mfd/da9062/core.h
@@ -68,6 +68,7 @@  enum da9062_irqs {
 struct da9062 {
 	struct device *dev;
 	struct regmap *regmap;
+	struct i2c_client *i2c;
 	struct regmap_irq_chip_data *regmap_irq;
 	enum da9062_compatible_types chip_type;
 };