All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>
To: linux-kernel@vger.kernel.org
Cc: "Lee Jones" <lee.jones@linaro.org>,
	"Rob Herring" <robh+dt@kernel.org>,
	"Jonathan Neuschäfer" <j.neuschaefer@gmx.net>,
	"Thierry Reding" <thierry.reding@gmail.com>,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
	"Alessandro Zummo" <a.zummo@towertech.it>,
	"Alexandre Belloni" <alexandre.belloni@bootlin.com>,
	"Shawn Guo" <shawnguo@kernel.org>,
	"Sascha Hauer" <s.hauer@pengutronix.de>,
	"Pengutronix Kernel Team" <kernel@pengutronix.de>,
	"Fabio Estevam" <festevam@gmail.com>,
	"NXP Linux Team" <linux-imx@nxp.com>,
	"Sam Ravnborg" <sam@ravnborg.org>,
	"Linus Walleij" <linus.walleij@linaro.org>,
	"Heiko Stuebner" <heiko.stuebner@theobroma-systems.com>,
	"Stephan Gerhold" <stephan@gerhold.net>,
	"Lubomir Rintel" <lkundrak@v3.sk>,
	"Mark Brown" <broonie@kernel.org>, allen <allen.chen@ite.com.tw>,
	"Mauro Carvalho Chehab" <mchehab+huawei@kernel.org>,
	"David S. Miller" <davem@davemloft.net>,
	devicetree@vger.kernel.org, linux-pwm@vger.kernel.org,
	linux-rtc@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	"Heiko Stuebner" <heiko@sntech.de>,
	"Josua Mayer" <josua.mayer@jm0.eu>,
	"Andreas Kemnade" <andreas@kemnade.info>,
	"Arnd Bergmann" <arnd@arndb.de>,
	"Daniel Palmer" <daniel@0x0f.com>,
	"Andy Shevchenko" <andy.shevchenko@gmail.com>
Subject: [PATCH v3 3/7] mfd: Add base driver for Netronix embedded controller
Date: Thu, 24 Sep 2020 21:24:51 +0200	[thread overview]
Message-ID: <20200924192455.2484005-4-j.neuschaefer@gmx.net> (raw)
In-Reply-To: <20200924192455.2484005-1-j.neuschaefer@gmx.net>

The Netronix embedded controller is a microcontroller found in some
e-book readers designed by the ODM Netronix, Inc. It contains RTC,
battery monitoring, system power management, and PWM functionality.

This driver implements register access and version detection.

Third-party hardware documentation is available at:

  https://github.com/neuschaefer/linux/wiki/Netronix-MSP430-embedded-controller

The EC supports interrupts, but the driver doesn't make use of them so
far.

Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
---

v3:
- Add (EC) to CONFIG_MFD_NTXEC prompt
- Relicense as GPLv2 or later
- Add email address to copyright line
- remove empty lines in ntxec_poweroff and ntxec_restart functions
- Split long lines
- Remove 'Install ... handler' comments
- Make naming of struct i2c_client parameter consistent
- Remove struct ntxec_info
- Rework 'depends on' lines in Kconfig, hard-depend on I2C, select REGMAP_I2C and
  MFD_CORE
- Register subdevices via mfd_cells
- Move 8-bit register conversion to ntxec.h

v2:
- https://lore.kernel.org/lkml/20200905133230.1014581-4-j.neuschaefer@gmx.net/
- Add a description of the device to the patch text
- Unify spelling as 'Netronix embedded controller'.
  'Netronix' is the proper name of the manufacturer, but 'embedded controller'
  is just a label that I have assigned to the device.
- Switch to regmap, avoid regmap use in poweroff and reboot handlers.
  Inspired by cf84dc0bb40f4 ("mfd: rn5t618: Make restart handler atomic safe")
- Use a list of known-working firmware versions instead of checking for a
  known-incompatible version
- Prefix registers with NTXEC_REG_
- Define register values as constants
- Various style cleanups as suggested by Lee Jones
- Don't align = signs in struct initializers [Uwe Kleine-König]
- Don't use dev_dbg for an error message
- Explain sleep in poweroff handler
- Remove (struct ntxec).client
- Switch to .probe_new in i2c driver
- Add .remove callback
- Make CONFIG_MFD_NTXEC a tristate option
---
 drivers/mfd/Kconfig       |  10 ++
 drivers/mfd/Makefile      |   1 +
 drivers/mfd/ntxec.c       | 206 ++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ntxec.h |  31 ++++++
 4 files changed, 248 insertions(+)
 create mode 100644 drivers/mfd/ntxec.c
 create mode 100644 include/linux/mfd/ntxec.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 33df0837ab415..b313103151508 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -978,6 +978,16 @@ config MFD_VIPERBOARD
 	  You need to select the mfd cell drivers separately.
 	  The drivers do not support all features the board exposes.

+config MFD_NTXEC
+	tristate "Netronix embedded controller (EC)"
+	depends on OF || COMPILE_TEST
+	depends on I2C
+	select REGMAP_I2C
+	select MFD_CORE
+	help
+	  Say yes here if you want to support the embedded controller found in
+	  certain e-book readers designed by the ODM Netronix.
+
 config MFD_RETU
 	tristate "Nokia Retu and Tahvo multi-function device"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index a60e5f835283e..236a8acd917a0 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -217,6 +217,7 @@ obj-$(CONFIG_MFD_INTEL_MSIC)	+= intel_msic.o
 obj-$(CONFIG_MFD_INTEL_PMC_BXT)	+= intel_pmc_bxt.o
 obj-$(CONFIG_MFD_PALMAS)	+= palmas.o
 obj-$(CONFIG_MFD_VIPERBOARD)    += viperboard.o
+obj-$(CONFIG_MFD_NTXEC)		+= ntxec.o
 obj-$(CONFIG_MFD_RC5T583)	+= rc5t583.o rc5t583-irq.o
 obj-$(CONFIG_MFD_RK808)		+= rk808.o
 obj-$(CONFIG_MFD_RN5T618)	+= rn5t618.o
diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
new file mode 100644
index 0000000000000..93611b85a32e0
--- /dev/null
+++ b/drivers/mfd/ntxec.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * The Netronix embedded controller is a microcontroller found in some
+ * e-book readers designed by the ODM Netronix, Inc. It contains RTC,
+ * battery monitoring, system power management, and PWM functionality.
+ *
+ * This driver implements register access, version detection, and system
+ * power-off/reset.
+ *
+ * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net>
+ */
+
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ntxec.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define NTXEC_REG_VERSION	0x00
+#define NTXEC_REG_POWEROFF	0x50
+#define NTXEC_REG_POWERKEEP	0x70
+#define NTXEC_REG_RESET		0x90
+
+#define NTXEC_POWEROFF_VALUE	0x0100
+#define NTXEC_POWERKEEP_VALUE	0x0800
+#define NTXEC_RESET_VALUE	0xff00
+
+static struct i2c_client *poweroff_restart_client;
+
+static void ntxec_poweroff(void)
+{
+	int res;
+	u8 buf[] = {
+		NTXEC_REG_POWEROFF,
+		(NTXEC_POWEROFF_VALUE >> 8) & 0xff,
+		NTXEC_POWEROFF_VALUE & 0xff,
+	};
+	struct i2c_msg msgs[] = {
+		{
+			.addr = poweroff_restart_client->addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf
+		}
+	};
+
+	res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (res < 0)
+		dev_alert(&poweroff_restart_client->dev,
+			  "Failed to power off (err = %d)\n", res);
+
+	/*
+	 * The time from the register write until the host CPU is powered off
+	 * has been observed to be about 2.5 to 3 seconds. Sleep long enough to
+	 * safely avoid returning from the poweroff handler.
+	 */
+	msleep(5000);
+}
+
+static int ntxec_restart(struct notifier_block *nb,
+			 unsigned long action, void *data)
+{
+	int res;
+	/*
+	 * NOTE: The lower half of the reset value is not sent, because sending
+	 * it causes an error
+	 */
+	u8 buf[] = {
+		NTXEC_REG_RESET,
+		(NTXEC_RESET_VALUE >> 8) & 0xff,
+	};
+	struct i2c_msg msgs[] = {
+		{
+			.addr = poweroff_restart_client->addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf
+		}
+	};
+
+	res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (res < 0)
+		dev_alert(&poweroff_restart_client->dev,
+			  "Failed to restart (err = %d)\n", res);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ntxec_restart_handler = {
+	.notifier_call = ntxec_restart,
+	.priority = 128
+};
+
+static const struct regmap_config regmap_config = {
+	.name = "ntxec",
+	.reg_bits = 8,
+	.val_bits = 16,
+	.cache_type = REGCACHE_NONE,
+	.val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static const struct mfd_cell ntxec_subdevices[] = {
+	{ .name = "ntxec-rtc" },
+	{ .name = "ntxec-pwm" },
+};
+
+static int ntxec_probe(struct i2c_client *client)
+{
+	struct ntxec *ec;
+	unsigned int version;
+	int res;
+
+	ec = devm_kmalloc(&client->dev, sizeof(*ec), GFP_KERNEL);
+	if (!ec)
+		return -ENOMEM;
+
+	ec->dev = &client->dev;
+
+	ec->regmap = devm_regmap_init_i2c(client, &regmap_config);
+	if (IS_ERR(ec->regmap)) {
+		dev_err(ec->dev, "Failed to set up regmap for device\n");
+		return res;
+	}
+
+	/* Determine the firmware version */
+	res = regmap_read(ec->regmap, NTXEC_REG_VERSION, &version);
+	if (res < 0) {
+		dev_err(ec->dev, "Failed to read firmware version number\n");
+		return res;
+	}
+	dev_info(ec->dev,
+		 "Netronix embedded controller version %04x detected.\n",
+		 version);
+
+	/* Bail out if we encounter an unknown firmware version */
+	switch (version) {
+	case 0xd726: /* found in Kobo Aura */
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	if (of_device_is_system_power_controller(ec->dev->of_node)) {
+		/*
+		 * Set the 'powerkeep' bit. This is necessary on some boards
+		 * in order to keep the system running.
+		 */
+		res = regmap_write(ec->regmap, NTXEC_REG_POWERKEEP,
+				   NTXEC_POWERKEEP_VALUE);
+		if (res < 0)
+			return res;
+
+		WARN_ON(poweroff_restart_client);
+		poweroff_restart_client = client;
+		if (pm_power_off)
+			dev_err(ec->dev, "pm_power_off already assigned\n");
+		else
+			pm_power_off = ntxec_poweroff;
+
+		res = register_restart_handler(&ntxec_restart_handler);
+		if (res)
+			dev_err(ec->dev,
+				"Failed to register restart handler: %d\n", res);
+	}
+
+	i2c_set_clientdata(client, ec);
+
+	res = devm_mfd_add_devices(ec->dev, PLATFORM_DEVID_NONE, ntxec_subdevices,
+				   ARRAY_SIZE(ntxec_subdevices), NULL, 0, NULL);
+	if (res)
+		dev_warn(ec->dev, "Failed to add subdevices: %d\n", res);
+
+	return res;
+}
+
+static int ntxec_remove(struct i2c_client *client)
+{
+	if (client == poweroff_restart_client) {
+		poweroff_restart_client = NULL;
+		pm_power_off = NULL;
+		unregister_restart_handler(&ntxec_restart_handler);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id of_ntxec_match_table[] = {
+	{ .compatible = "netronix,ntxec", },
+	{}
+};
+
+static struct i2c_driver ntxec_driver = {
+	.driver = {
+		.name = "ntxec",
+		.of_match_table = of_ntxec_match_table,
+	},
+	.probe_new = ntxec_probe,
+	.remove = ntxec_remove,
+};
+module_i2c_driver(ntxec_driver);
diff --git a/include/linux/mfd/ntxec.h b/include/linux/mfd/ntxec.h
new file mode 100644
index 0000000000000..a39c85978f61b
--- /dev/null
+++ b/include/linux/mfd/ntxec.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2020 Jonathan Neuschäfer
+ *
+ * Register access and version information for the Netronix embedded
+ * controller.
+ */
+
+#ifndef NTXEC_H
+#define NTXEC_H
+
+#include <linux/types.h>
+
+struct ntxec {
+	struct device *dev;
+	struct regmap *regmap;
+};
+
+/*
+ * Some registers, such as the battery status register (0x41), are in
+ * big-endian, but others only have eight significant bits, which are in the
+ * first byte transmitted over I2C (the MSB of the big-endian value).
+ * This convenience function converts an 8-bit value to 16-bit for use in the
+ * second kind of register.
+ */
+static inline u16 ntxec_reg8(u8 value)
+{
+	return value << 8;
+}
+
+#endif
--
2.28.0


WARNING: multiple messages have this Message-ID (diff)
From: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>
To: linux-kernel@vger.kernel.org
Cc: "Alexandre Belloni" <alexandre.belloni@bootlin.com>,
	"Heiko Stuebner" <heiko@sntech.de>,
	linux-pwm@vger.kernel.org,
	"Linus Walleij" <linus.walleij@linaro.org>,
	"Thierry Reding" <thierry.reding@gmail.com>,
	"Fabio Estevam" <festevam@gmail.com>,
	linux-rtc@vger.kernel.org, "Arnd Bergmann" <arnd@arndb.de>,
	"Mauro Carvalho Chehab" <mchehab+huawei@kernel.org>,
	"Sam Ravnborg" <sam@ravnborg.org>,
	"Daniel Palmer" <daniel@0x0f.com>,
	"Andy Shevchenko" <andy.shevchenko@gmail.com>,
	"Andreas Kemnade" <andreas@kemnade.info>,
	"NXP Linux Team" <linux-imx@nxp.com>,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
	devicetree@vger.kernel.org,
	"Stephan Gerhold" <stephan@gerhold.net>,
	allen <allen.chen@ite.com.tw>,
	"Sascha Hauer" <s.hauer@pengutronix.de>,
	"Jonathan Neuschäfer" <j.neuschaefer@gmx.net>,
	"Lubomir Rintel" <lkundrak@v3.sk>,
	"Rob Herring" <robh+dt@kernel.org>,
	"Lee Jones" <lee.jones@linaro.org>,
	linux-arm-kernel@lists.infradead.org,
	"Alessandro Zummo" <a.zummo@towertech.it>,
	"Mark Brown" <broonie@kernel.org>,
	"Pengutronix Kernel Team" <kernel@pengutronix.de>,
	"Heiko Stuebner" <heiko.stuebner@theobroma-systems.com>,
	"Josua Mayer" <josua.mayer@jm0.eu>,
	"Shawn Guo" <shawnguo@kernel.org>,
	"David S. Miller" <davem@davemloft.net>
Subject: [PATCH v3 3/7] mfd: Add base driver for Netronix embedded controller
Date: Thu, 24 Sep 2020 21:24:51 +0200	[thread overview]
Message-ID: <20200924192455.2484005-4-j.neuschaefer@gmx.net> (raw)
In-Reply-To: <20200924192455.2484005-1-j.neuschaefer@gmx.net>

The Netronix embedded controller is a microcontroller found in some
e-book readers designed by the ODM Netronix, Inc. It contains RTC,
battery monitoring, system power management, and PWM functionality.

This driver implements register access and version detection.

Third-party hardware documentation is available at:

  https://github.com/neuschaefer/linux/wiki/Netronix-MSP430-embedded-controller

The EC supports interrupts, but the driver doesn't make use of them so
far.

Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
---

v3:
- Add (EC) to CONFIG_MFD_NTXEC prompt
- Relicense as GPLv2 or later
- Add email address to copyright line
- remove empty lines in ntxec_poweroff and ntxec_restart functions
- Split long lines
- Remove 'Install ... handler' comments
- Make naming of struct i2c_client parameter consistent
- Remove struct ntxec_info
- Rework 'depends on' lines in Kconfig, hard-depend on I2C, select REGMAP_I2C and
  MFD_CORE
- Register subdevices via mfd_cells
- Move 8-bit register conversion to ntxec.h

v2:
- https://lore.kernel.org/lkml/20200905133230.1014581-4-j.neuschaefer@gmx.net/
- Add a description of the device to the patch text
- Unify spelling as 'Netronix embedded controller'.
  'Netronix' is the proper name of the manufacturer, but 'embedded controller'
  is just a label that I have assigned to the device.
- Switch to regmap, avoid regmap use in poweroff and reboot handlers.
  Inspired by cf84dc0bb40f4 ("mfd: rn5t618: Make restart handler atomic safe")
- Use a list of known-working firmware versions instead of checking for a
  known-incompatible version
- Prefix registers with NTXEC_REG_
- Define register values as constants
- Various style cleanups as suggested by Lee Jones
- Don't align = signs in struct initializers [Uwe Kleine-König]
- Don't use dev_dbg for an error message
- Explain sleep in poweroff handler
- Remove (struct ntxec).client
- Switch to .probe_new in i2c driver
- Add .remove callback
- Make CONFIG_MFD_NTXEC a tristate option
---
 drivers/mfd/Kconfig       |  10 ++
 drivers/mfd/Makefile      |   1 +
 drivers/mfd/ntxec.c       | 206 ++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ntxec.h |  31 ++++++
 4 files changed, 248 insertions(+)
 create mode 100644 drivers/mfd/ntxec.c
 create mode 100644 include/linux/mfd/ntxec.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 33df0837ab415..b313103151508 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -978,6 +978,16 @@ config MFD_VIPERBOARD
 	  You need to select the mfd cell drivers separately.
 	  The drivers do not support all features the board exposes.

+config MFD_NTXEC
+	tristate "Netronix embedded controller (EC)"
+	depends on OF || COMPILE_TEST
+	depends on I2C
+	select REGMAP_I2C
+	select MFD_CORE
+	help
+	  Say yes here if you want to support the embedded controller found in
+	  certain e-book readers designed by the ODM Netronix.
+
 config MFD_RETU
 	tristate "Nokia Retu and Tahvo multi-function device"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index a60e5f835283e..236a8acd917a0 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -217,6 +217,7 @@ obj-$(CONFIG_MFD_INTEL_MSIC)	+= intel_msic.o
 obj-$(CONFIG_MFD_INTEL_PMC_BXT)	+= intel_pmc_bxt.o
 obj-$(CONFIG_MFD_PALMAS)	+= palmas.o
 obj-$(CONFIG_MFD_VIPERBOARD)    += viperboard.o
+obj-$(CONFIG_MFD_NTXEC)		+= ntxec.o
 obj-$(CONFIG_MFD_RC5T583)	+= rc5t583.o rc5t583-irq.o
 obj-$(CONFIG_MFD_RK808)		+= rk808.o
 obj-$(CONFIG_MFD_RN5T618)	+= rn5t618.o
diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c
new file mode 100644
index 0000000000000..93611b85a32e0
--- /dev/null
+++ b/drivers/mfd/ntxec.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * The Netronix embedded controller is a microcontroller found in some
+ * e-book readers designed by the ODM Netronix, Inc. It contains RTC,
+ * battery monitoring, system power management, and PWM functionality.
+ *
+ * This driver implements register access, version detection, and system
+ * power-off/reset.
+ *
+ * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net>
+ */
+
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ntxec.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define NTXEC_REG_VERSION	0x00
+#define NTXEC_REG_POWEROFF	0x50
+#define NTXEC_REG_POWERKEEP	0x70
+#define NTXEC_REG_RESET		0x90
+
+#define NTXEC_POWEROFF_VALUE	0x0100
+#define NTXEC_POWERKEEP_VALUE	0x0800
+#define NTXEC_RESET_VALUE	0xff00
+
+static struct i2c_client *poweroff_restart_client;
+
+static void ntxec_poweroff(void)
+{
+	int res;
+	u8 buf[] = {
+		NTXEC_REG_POWEROFF,
+		(NTXEC_POWEROFF_VALUE >> 8) & 0xff,
+		NTXEC_POWEROFF_VALUE & 0xff,
+	};
+	struct i2c_msg msgs[] = {
+		{
+			.addr = poweroff_restart_client->addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf
+		}
+	};
+
+	res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (res < 0)
+		dev_alert(&poweroff_restart_client->dev,
+			  "Failed to power off (err = %d)\n", res);
+
+	/*
+	 * The time from the register write until the host CPU is powered off
+	 * has been observed to be about 2.5 to 3 seconds. Sleep long enough to
+	 * safely avoid returning from the poweroff handler.
+	 */
+	msleep(5000);
+}
+
+static int ntxec_restart(struct notifier_block *nb,
+			 unsigned long action, void *data)
+{
+	int res;
+	/*
+	 * NOTE: The lower half of the reset value is not sent, because sending
+	 * it causes an error
+	 */
+	u8 buf[] = {
+		NTXEC_REG_RESET,
+		(NTXEC_RESET_VALUE >> 8) & 0xff,
+	};
+	struct i2c_msg msgs[] = {
+		{
+			.addr = poweroff_restart_client->addr,
+			.flags = 0,
+			.len = sizeof(buf),
+			.buf = buf
+		}
+	};
+
+	res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (res < 0)
+		dev_alert(&poweroff_restart_client->dev,
+			  "Failed to restart (err = %d)\n", res);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ntxec_restart_handler = {
+	.notifier_call = ntxec_restart,
+	.priority = 128
+};
+
+static const struct regmap_config regmap_config = {
+	.name = "ntxec",
+	.reg_bits = 8,
+	.val_bits = 16,
+	.cache_type = REGCACHE_NONE,
+	.val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static const struct mfd_cell ntxec_subdevices[] = {
+	{ .name = "ntxec-rtc" },
+	{ .name = "ntxec-pwm" },
+};
+
+static int ntxec_probe(struct i2c_client *client)
+{
+	struct ntxec *ec;
+	unsigned int version;
+	int res;
+
+	ec = devm_kmalloc(&client->dev, sizeof(*ec), GFP_KERNEL);
+	if (!ec)
+		return -ENOMEM;
+
+	ec->dev = &client->dev;
+
+	ec->regmap = devm_regmap_init_i2c(client, &regmap_config);
+	if (IS_ERR(ec->regmap)) {
+		dev_err(ec->dev, "Failed to set up regmap for device\n");
+		return res;
+	}
+
+	/* Determine the firmware version */
+	res = regmap_read(ec->regmap, NTXEC_REG_VERSION, &version);
+	if (res < 0) {
+		dev_err(ec->dev, "Failed to read firmware version number\n");
+		return res;
+	}
+	dev_info(ec->dev,
+		 "Netronix embedded controller version %04x detected.\n",
+		 version);
+
+	/* Bail out if we encounter an unknown firmware version */
+	switch (version) {
+	case 0xd726: /* found in Kobo Aura */
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	if (of_device_is_system_power_controller(ec->dev->of_node)) {
+		/*
+		 * Set the 'powerkeep' bit. This is necessary on some boards
+		 * in order to keep the system running.
+		 */
+		res = regmap_write(ec->regmap, NTXEC_REG_POWERKEEP,
+				   NTXEC_POWERKEEP_VALUE);
+		if (res < 0)
+			return res;
+
+		WARN_ON(poweroff_restart_client);
+		poweroff_restart_client = client;
+		if (pm_power_off)
+			dev_err(ec->dev, "pm_power_off already assigned\n");
+		else
+			pm_power_off = ntxec_poweroff;
+
+		res = register_restart_handler(&ntxec_restart_handler);
+		if (res)
+			dev_err(ec->dev,
+				"Failed to register restart handler: %d\n", res);
+	}
+
+	i2c_set_clientdata(client, ec);
+
+	res = devm_mfd_add_devices(ec->dev, PLATFORM_DEVID_NONE, ntxec_subdevices,
+				   ARRAY_SIZE(ntxec_subdevices), NULL, 0, NULL);
+	if (res)
+		dev_warn(ec->dev, "Failed to add subdevices: %d\n", res);
+
+	return res;
+}
+
+static int ntxec_remove(struct i2c_client *client)
+{
+	if (client == poweroff_restart_client) {
+		poweroff_restart_client = NULL;
+		pm_power_off = NULL;
+		unregister_restart_handler(&ntxec_restart_handler);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id of_ntxec_match_table[] = {
+	{ .compatible = "netronix,ntxec", },
+	{}
+};
+
+static struct i2c_driver ntxec_driver = {
+	.driver = {
+		.name = "ntxec",
+		.of_match_table = of_ntxec_match_table,
+	},
+	.probe_new = ntxec_probe,
+	.remove = ntxec_remove,
+};
+module_i2c_driver(ntxec_driver);
diff --git a/include/linux/mfd/ntxec.h b/include/linux/mfd/ntxec.h
new file mode 100644
index 0000000000000..a39c85978f61b
--- /dev/null
+++ b/include/linux/mfd/ntxec.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2020 Jonathan Neuschäfer
+ *
+ * Register access and version information for the Netronix embedded
+ * controller.
+ */
+
+#ifndef NTXEC_H
+#define NTXEC_H
+
+#include <linux/types.h>
+
+struct ntxec {
+	struct device *dev;
+	struct regmap *regmap;
+};
+
+/*
+ * Some registers, such as the battery status register (0x41), are in
+ * big-endian, but others only have eight significant bits, which are in the
+ * first byte transmitted over I2C (the MSB of the big-endian value).
+ * This convenience function converts an 8-bit value to 16-bit for use in the
+ * second kind of register.
+ */
+static inline u16 ntxec_reg8(u8 value)
+{
+	return value << 8;
+}
+
+#endif
--
2.28.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2020-09-24 19:26 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-24 19:24 [PATCH v3 0/7] Netronix embedded controller driver for Kobo and Tolino ebook readers Jonathan Neuschäfer
2020-09-24 19:24 ` Jonathan Neuschäfer
2020-09-24 19:24 ` [PATCH v3 1/7] dt-bindings: Add vendor prefix for Netronix, Inc Jonathan Neuschäfer
2020-09-24 19:24   ` Jonathan Neuschäfer
2020-10-12  7:19   ` Uwe Kleine-König
2020-10-12  7:19     ` Uwe Kleine-König
2020-10-12 11:48     ` Lee Jones
2020-10-12 11:48       ` Lee Jones
2020-09-24 19:24 ` [PATCH v3 2/7] dt-bindings: mfd: Add binding for Netronix embedded controller Jonathan Neuschäfer
2020-09-24 19:24   ` Jonathan Neuschäfer
2020-09-29 18:52   ` Rob Herring
2020-09-29 18:52     ` Rob Herring
2020-09-24 19:24 ` Jonathan Neuschäfer [this message]
2020-09-24 19:24   ` [PATCH v3 3/7] mfd: Add base driver " Jonathan Neuschäfer
2020-09-25  9:29   ` Andy Shevchenko
2020-09-25  9:29     ` Andy Shevchenko
2020-09-25 21:32     ` Jonathan Neuschäfer
2020-09-25 21:32       ` Jonathan Neuschäfer
2020-09-29 16:37       ` Andy Shevchenko
2020-09-29 16:37         ` Andy Shevchenko
2020-10-02 22:54         ` Jonathan Neuschäfer
2020-10-02 22:54           ` Jonathan Neuschäfer
2020-09-24 19:24 ` [PATCH v3 4/7] pwm: ntxec: Add driver for PWM function in Netronix EC Jonathan Neuschäfer
2020-09-24 19:24   ` Jonathan Neuschäfer
2020-09-25  6:30   ` Uwe Kleine-König
2020-09-25  6:30     ` Uwe Kleine-König
2020-09-27 21:10     ` Jonathan Neuschäfer
2020-09-27 21:10       ` Jonathan Neuschäfer
2020-09-28  8:35       ` Uwe Kleine-König
2020-09-28  8:35         ` Uwe Kleine-König
2020-10-02 23:36         ` Jonathan Neuschäfer
2020-10-02 23:36           ` Jonathan Neuschäfer
2020-10-03  8:17           ` Andy Shevchenko
2020-10-03  8:17             ` Andy Shevchenko
2020-09-24 19:24 ` [PATCH v3 5/7] rtc: New driver for RTC in Netronix embedded controller Jonathan Neuschäfer
2020-09-24 19:24   ` Jonathan Neuschäfer
2020-09-24 20:40   ` Andreas Kemnade
2020-09-24 20:40     ` Andreas Kemnade
2020-10-02 23:41     ` Jonathan Neuschäfer
2020-10-02 23:41       ` Jonathan Neuschäfer
2020-09-25  5:44   ` Uwe Kleine-König
2020-09-25  5:44     ` Uwe Kleine-König
2020-10-04  1:43     ` Jonathan Neuschäfer
2020-10-04  1:43       ` Jonathan Neuschäfer
2020-10-04  8:42       ` Alexandre Belloni
2020-10-04  8:42         ` Alexandre Belloni
2020-10-11 19:09         ` Jonathan Neuschäfer
2020-10-11 19:09           ` Jonathan Neuschäfer
2020-10-05  7:35       ` Uwe Kleine-König
2020-10-05  7:35         ` Uwe Kleine-König
2020-09-25  9:36   ` Alexandre Belloni
2020-09-25  9:36     ` Alexandre Belloni
2020-09-25 22:00     ` Jonathan Neuschäfer
2020-09-25 22:00       ` Jonathan Neuschäfer
2020-09-24 19:24 ` [PATCH v3 6/7] MAINTAINERS: Add entry for " Jonathan Neuschäfer
2020-09-24 19:24   ` Jonathan Neuschäfer
2020-09-25  5:08 ` [PATCH v3 7/7] ARM: dts: imx50-kobo-aura: Add " Jonathan Neuschäfer
2020-09-25  5:08   ` Jonathan Neuschäfer
2020-10-07  7:46   ` Krzysztof Kozlowski
2020-10-07  7:46     ` Krzysztof Kozlowski
2020-10-11 19:42     ` Jonathan Neuschäfer
2020-10-11 19:42       ` Jonathan Neuschäfer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200924192455.2484005-4-j.neuschaefer@gmx.net \
    --to=j.neuschaefer@gmx.net \
    --cc=a.zummo@towertech.it \
    --cc=alexandre.belloni@bootlin.com \
    --cc=allen.chen@ite.com.tw \
    --cc=andreas@kemnade.info \
    --cc=andy.shevchenko@gmail.com \
    --cc=arnd@arndb.de \
    --cc=broonie@kernel.org \
    --cc=daniel@0x0f.com \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=festevam@gmail.com \
    --cc=heiko.stuebner@theobroma-systems.com \
    --cc=heiko@sntech.de \
    --cc=josua.mayer@jm0.eu \
    --cc=kernel@pengutronix.de \
    --cc=lee.jones@linaro.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-imx@nxp.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=linux-rtc@vger.kernel.org \
    --cc=lkundrak@v3.sk \
    --cc=mchehab+huawei@kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=s.hauer@pengutronix.de \
    --cc=sam@ravnborg.org \
    --cc=shawnguo@kernel.org \
    --cc=stephan@gerhold.net \
    --cc=thierry.reding@gmail.com \
    --cc=u.kleine-koenig@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.