linux-pwm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Jonathan Neuschäfer" <j.neuschaefer-hi6Y0CQ0nG0@public.gmane.org>
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: "Lee Jones" <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	"Rob Herring" <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	"Jonathan Neuschäfer"
	<j.neuschaefer-hi6Y0CQ0nG0@public.gmane.org>,
	"Thierry Reding"
	<thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	"Uwe Kleine-König"
	<u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>,
	"Alessandro Zummo"
	<a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org>,
	"Alexandre Belloni"
	<alexandre.belloni-LDxbnhwyfcJBDgjK7y7TUQ@public.gmane.org>,
	"Shawn Guo" <shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	"Sascha Hauer" <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>,
	"Pengutronix Kernel Team"
	<kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>,
	"Fabio Estevam"
	<festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	"NXP Linux Team" <linux-imx-3arQi8VN3Tc@public.gmane.org>,
	"Sam Ravnborg" <sam-uyr5N9Q2VtJg9hUCZPvPmw@public.gmane.org>,
	"Linus Walleij"
	<linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	"Heiko Stuebner"
	<heiko.stuebner-SN7IsUiht6C/RdPyistoZJqQE7yCjDx5@public.gmane.org>,
	"Stephan Gerhold"
	<stephan-3XONVrnlUWDR7s880joybQ@public.gmane.org>,
	"Lubomir Rintel" <lkundrak-NGH9Lh4a5iE@public.gmane.org>,
	"Mark Brown" <broonie@kernel.>
Subject: [RFC PATCH 04/10] mfd: Add base driver for Netronix embedded controller
Date: Sun, 21 Jun 2020 00:42:15 +0200	[thread overview]
Message-ID: <20200620224222.1312520-3-j.neuschaefer@gmx.net> (raw)
In-Reply-To: <20200620224222.1312520-1-j.neuschaefer-hi6Y0CQ0nG0@public.gmane.org>

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.

Known problems:
- The reboot handler is installed in such a way that it directly calls
  into the i2c subsystem to send the reboot command to the EC. This
  means that the reboot handler may sleep, which is not allowed.

Signed-off-by: Jonathan Neuschäfer <j.neuschaefer-hi6Y0CQ0nG0@public.gmane.org>
---
 drivers/mfd/Kconfig       |   7 ++
 drivers/mfd/Makefile      |   1 +
 drivers/mfd/ntxec.c       | 188 ++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/ntxec.h |  30 ++++++
 4 files changed, 226 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 a37d7d1713820..78410b928648e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -978,6 +978,13 @@ 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
+	bool "Netronix Embedded Controller"
+	depends on I2C && OF
+	help
+	  Say yes here if you want to support the embedded controller of
+	  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 9367a92f795a6..19d9391ed6f32 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -218,6 +218,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..82adea34ea746
--- /dev/null
+++ b/drivers/mfd/ntxec.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright 2020 Jonathan Neuschäfer
+//
+// MFD driver for the usually MSP430-based embedded controller used in certain
+// Netronix ebook reader board designs
+
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mfd/ntxec.h>
+#include <linux/of_platform.h>
+#include <linux/pm.h>
+#include <linux/reboot.h>
+#include <linux/types.h>
+
+
+#define NTXEC_VERSION		0x00
+#define NTXEC_POWEROFF		0x50
+#define NTXEC_POWERKEEP		0x70
+#define NTXEC_RESET		0x90
+
+
+/* Register access */
+
+int ntxec_read16(struct ntxec *ec, u8 addr)
+{
+	u8 request[1] = { addr };
+	u8 response[2];
+	int res;
+
+	struct i2c_msg msgs[] = {
+		{
+			.addr = ec->client->addr,
+			.flags = ec->client->flags,
+			.len = sizeof(request),
+			.buf = request
+		}, {
+			.addr = ec->client->addr,
+			.flags = ec->client->flags | I2C_M_RD,
+			.len = sizeof(response),
+			.buf = response
+		}
+	};
+
+	res = i2c_transfer(ec->client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (res < 0)
+		return res;
+	if (res != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	return get_unaligned_be16(response);
+}
+EXPORT_SYMBOL(ntxec_read16);
+
+int ntxec_write16(struct ntxec *ec, u8 addr, u16 value)
+{
+	u8 request[3] = { addr, };
+	int res;
+
+	put_unaligned_be16(value, request + 1);
+
+	res = i2c_transfer_buffer_flags(ec->client, request, sizeof(request),
+					ec->client->flags);
+	if (res < 0)
+		return res;
+
+	return 0;
+}
+EXPORT_SYMBOL(ntxec_write16);
+
+int ntxec_read8(struct ntxec *ec, u8 addr)
+{
+	int res = ntxec_read16(ec, addr);
+
+	if (res < 0)
+		return res;
+
+	return (res >> 8) & 0xff;
+}
+EXPORT_SYMBOL(ntxec_read8);
+
+int ntxec_write8(struct ntxec *ec, u8 addr, u8 value)
+{
+	return ntxec_write16(ec, addr, value << 8);
+}
+EXPORT_SYMBOL(ntxec_write8);
+
+
+/* Reboot/poweroff handling */
+
+static struct ntxec *poweroff_restart_instance;
+
+static void ntxec_poweroff(void)
+{
+	ntxec_write8(poweroff_restart_instance, NTXEC_POWEROFF, 0x01);
+	msleep(5000);
+}
+
+static int ntxec_restart(struct notifier_block *nb,
+		unsigned long action, void *data)
+{
+	/* FIXME: The I2C driver sleeps, but restart handlers may not sleep */
+	ntxec_write8(poweroff_restart_instance, NTXEC_RESET, 0xff);
+	/* TODO: delay? */
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ntxec_restart_handler = {
+	.notifier_call = ntxec_restart,
+	.priority = 128
+};
+
+
+/* Driver setup */
+
+static int ntxec_probe(struct i2c_client *client,
+			    const struct i2c_device_id *ids)
+{
+	struct ntxec *ec;
+	int res;
+
+	ec = devm_kmalloc(&client->dev, sizeof(*ec), GFP_KERNEL);
+	if (!ec)
+		return -ENOMEM;
+
+	ec->dev = &client->dev;
+	ec->client = client;
+
+	/* Determine the firmware version */
+	res = ntxec_read16(ec, NTXEC_VERSION);
+	if (res < 0) {
+		dev_dbg(ec->dev, "Failed to read firmware version number\n");
+		return res;
+	}
+	ec->version = res;
+
+	dev_info(ec->dev,
+		 "Netronix embedded controller version %04x detected.\n",
+		 ec->version);
+
+	/* For now, we don't support the new register layout. */
+	if (ntxec_has_new_layout(ec))
+		return -EOPNOTSUPP;
+
+	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 = ntxec_write8(ec, NTXEC_POWERKEEP, 0x08);
+		if (res < 0)
+			return res;
+
+		/* Install poweroff handler */
+		WARN_ON(poweroff_restart_instance);
+		poweroff_restart_instance = ec;
+		if (pm_power_off != NULL)
+			/* TODO: Refactor among all poweroff drivers */
+			dev_err(ec->dev, "pm_power_off already assigned\n");
+		else
+			pm_power_off = ntxec_poweroff;
+
+		/* Install board reset handler */
+		res = register_restart_handler(&ntxec_restart_handler);
+		if (res < 0)
+			dev_err(ec->dev,
+				"Failed to register restart handler: %d\n", res);
+	}
+
+	i2c_set_clientdata(client, ec);
+
+	return devm_of_platform_populate(ec->dev);
+}
+
+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		= ntxec_probe,
+};
+builtin_i2c_driver(ntxec_driver);
diff --git a/include/linux/mfd/ntxec.h b/include/linux/mfd/ntxec.h
new file mode 100644
index 0000000000000..9f9d6f2141751
--- /dev/null
+++ b/include/linux/mfd/ntxec.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2020 Jonathan Neuschäfer
+ *
+ * MFD access functions for the Netronix embedded controller.
+ */
+
+#ifndef NTXEC_H
+#define NTXEC_H
+
+#include <linux/types.h>
+
+struct ntxec {
+	struct device *dev;
+	struct i2c_client *client;
+	u16 version;
+	/* TODO: Add a mutex to protect actions consisting of multiple accesses? */
+};
+
+static inline bool ntxec_has_new_layout(struct ntxec *ec)
+{
+	return ec->version == 0xe916;
+}
+
+int ntxec_read16(struct ntxec *ec, u8 addr);
+int ntxec_write16(struct ntxec *ec, u8 addr, u16 value);
+int ntxec_read8(struct ntxec *ec, u8 addr);
+int ntxec_write8(struct ntxec *ec, u8 addr, u8 value);
+
+#endif
--
2.27.0

  parent reply	other threads:[~2020-06-20 22:42 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-20 22:42 [RFC PATCH 02/10] dt-bindings: Add vendor prefix for Netronix, Inc Jonathan Neuschäfer
     [not found] ` <20200620224222.1312520-1-j.neuschaefer-hi6Y0CQ0nG0@public.gmane.org>
2020-06-20 22:42   ` [RFC PATCH 03/10] dt-bindings: mfd: Add binding for Netronix's embedded controller Jonathan Neuschäfer
2020-06-20 22:42   ` Jonathan Neuschäfer [this message]
2020-06-22 10:55     ` [RFC PATCH 04/10] mfd: Add base driver for Netronix " Lee Jones
2020-06-28  8:11       ` Jonathan Neuschäfer
2020-06-27  8:17     ` Andreas Kemnade
2020-06-28  8:29       ` Jonathan Neuschäfer
2020-06-20 22:42   ` [RFC PATCH 05/10] dt-bindings: pwm: Add bindings for PWM function in Netronix EC Jonathan Neuschäfer
     [not found]     ` <20200620224222.1312520-4-j.neuschaefer-hi6Y0CQ0nG0@public.gmane.org>
2020-06-21 18:41       ` Andreas Kemnade
2020-08-23 22:42         ` Jonathan Neuschäfer
2020-06-20 22:42   ` [RFC PATCH 09/10] MAINTAINERS: Add entry for Netronix embedded controller Jonathan Neuschäfer
2020-06-20 22:42 ` [RFC PATCH 06/10] pwm: ntxec: Add driver for PWM function in Netronix EC Jonathan Neuschäfer
2020-06-22  8:18   ` Uwe Kleine-König
     [not found]     ` <20200622081802.pv4xmb7vn4te5r5t-T6qyLwKrzP+Pq0V0m3QNwQq/OYV65a7L4Y2cMoPwMik@public.gmane.org>
2020-07-03 16:15       ` Jonathan Neuschäfer
2020-06-20 22:42 ` [RFC PATCH 07/10] dt-bindings: rtc: Add bindings for Netronix embedded controller RTC Jonathan Neuschäfer
     [not found]   ` <20200620224222.1312520-6-j.neuschaefer-hi6Y0CQ0nG0@public.gmane.org>
2020-06-21  0:02     ` Alexandre Belloni
     [not found]       ` <20200621000220.GB131826-m++hUPXGwpdeoWH0uzbU5w@public.gmane.org>
2020-06-26 21:55         ` Andreas Kemnade
     [not found]           ` <20200626235552.7820a999-cLv4Z9ELZ06ZuzBka8ofvg@public.gmane.org>
2020-07-03 17:04             ` Jonathan Neuschäfer
2020-06-20 22:42 ` [RFC PATCH 08/10] rtc: New driver for RTC in Netronix embedded controller Jonathan Neuschäfer
     [not found]   ` <20200620224222.1312520-7-j.neuschaefer-hi6Y0CQ0nG0@public.gmane.org>
2020-06-21  0:11     ` Alexandre Belloni
     [not found]       ` <20200621001106.GC131826-m++hUPXGwpdeoWH0uzbU5w@public.gmane.org>
2020-07-04 19:23         ` Jonathan Neuschäfer
2020-06-20 22:42 ` [RFC PATCH 10/10] ARM: dts: imx50-kobo-aura: Add " Jonathan Neuschäfer
2020-06-20 22:46 ` [RFC PATCH 02/10] dt-bindings: Add vendor prefix for Netronix, Inc 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=20200620224222.1312520-3-j.neuschaefer@gmx.net \
    --to=j.neuschaefer-hi6y0cq0ng0@public.gmane.org \
    --cc=a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org \
    --cc=alexandre.belloni-LDxbnhwyfcJBDgjK7y7TUQ@public.gmane.org \
    --cc=broonie@kernel. \
    --cc=festevam-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=heiko.stuebner-SN7IsUiht6C/RdPyistoZJqQE7yCjDx5@public.gmane.org \
    --cc=kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org \
    --cc=lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=linux-imx-3arQi8VN3Tc@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=lkundrak-NGH9Lh4a5iE@public.gmane.org \
    --cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org \
    --cc=sam-uyr5N9Q2VtJg9hUCZPvPmw@public.gmane.org \
    --cc=shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=stephan-3XONVrnlUWDR7s880joybQ@public.gmane.org \
    --cc=thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).