[RFC PATCH 1/2] tcan4x5x: initial commit

Sean Nyekjaer <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
This driver will put the tcan4x5x device into sleep mode to reduce power
consumption.

Signed-off-by: Sean Nyekjaer <[email protected]>
---
Not many drivers use SPI. So leave this for others to see how it can be
done.
If this is appropriate for upstreaming, please comment :)

 drivers/misc/Kconfig    |   5 ++
 drivers/misc/Makefile   |   3 +
 drivers/misc/tcan4x5x.c | 135 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)
 create mode 100644 drivers/misc/tcan4x5x.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index dde773ab6b1..2abfdb5575c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -170,6 +170,11 @@ config CMD_CROS_EC
 	  updating its flash, accessing a small saved context area
 	  and talking to the I2C bus behind the EC (if there is one).
 
+config TCAN4X5X
+	bool "Enable TCAN4X5X"
+	depends on MISC
+	depends on DM_GPIO
+
 config CROS_EC
 	bool "Enable Chrome OS EC"
 	help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 1d950f7a0ab..57ebafff121 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -29,6 +29,9 @@ ifdef CONFIG_XPL_BUILD
 obj-$(CONFIG_SANDBOX) += spltest_sandbox.o
 endif
 endif
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_TCAN4X5X) += tcan4x5x.o
+endif
 obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o
 obj-$(CONFIG_ATSHA204A) += atsha204a-i2c.o
 obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
diff --git a/drivers/misc/tcan4x5x.c b/drivers/misc/tcan4x5x.c
new file mode 100644
index 00000000000..a304f3db9df
--- /dev/null
+++ b/drivers/misc/tcan4x5x.c
@@ -0,0 +1,135 @@
+#include <dm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+#include <spi.h>
+#include <log.h>
+
+#define TCAN4X5X_SPI_INSTRUCTION_WRITE 0x61
+#define TCAN4X5X_SPI_INSTRUCTION_READ 0x41
+
+#define TCAN4X5X_CONFIG 0x800
+#define TCAN4X5X_MODE_BITS (BIT(7) | BIT(6))
+
+struct tcan4x5x_transfer {
+	u8 cmd;
+	__be16 reg;
+	u8 length;
+	__be32 val;
+} __packed;
+
+static int tcan4x5x_write_reg(struct udevice *dev, u16 reg, u32 val)
+{
+	struct tcan4x5x_transfer tx;
+	int ret;
+
+	tx.cmd = TCAN4X5X_SPI_INSTRUCTION_WRITE;
+	tx.reg = cpu_to_be16(reg);
+	tx.length = 1;
+	tx.val = cpu_to_be32(val);
+
+	ret = dm_spi_claim_bus(dev);
+	if (ret)
+		return ret;
+
+	ret = dm_spi_xfer(dev, 64, &tx, NULL, SPI_XFER_ONCE);
+
+	dm_spi_release_bus(dev);
+
+	return ret;
+}
+
+static int tcan4x5x_read_reg(struct udevice *dev, u16 reg, u32 *val)
+{
+	struct tcan4x5x_transfer rx;
+	int ret;
+
+	rx.cmd = TCAN4X5X_SPI_INSTRUCTION_READ;
+	rx.reg = cpu_to_be16(reg);
+	rx.length = 1;
+
+	ret = dm_spi_claim_bus(dev);
+	if (ret)
+		return ret;
+
+	ret = dm_spi_xfer(dev, 64, &rx, &rx, SPI_XFER_ONCE);
+	if (ret)
+		return ret;
+
+	dm_spi_release_bus(dev);
+	if (ret)
+		return ret;
+
+	*val = be32_to_cpu(rx.val);
+
+	return 0;
+}
+
+static int tcan4x5x_enable_sleep(struct udevice *dev)
+{
+	u32 val;
+	int ret;
+
+	ret = tcan4x5x_read_reg(dev, TCAN4X5X_CONFIG, &val);
+	if (ret) {
+		log_err("reg read failed (%d)\n", ret);
+		return ret;
+	}
+
+	log_debug("read %x\n", val);
+	val &= ~(TCAN4X5X_MODE_BITS);
+	log_debug("write %x\n", val);
+
+	ret = tcan4x5x_write_reg(dev, TCAN4X5X_CONFIG, val);
+	if (ret)
+		log_err("reg write failed (%d)\n", ret);
+
+	return ret;
+}
+
+static int tcan4x5x_probe(struct udevice *dev)
+{
+	struct gpio_desc rst;
+	int ret;
+
+	ret = gpio_request_by_name(dev, "reset-gpios", 0, &rst, GPIOD_IS_OUT);
+	if (ret) {
+		log_debug("could not find reset-gpios\n");
+		return ret;
+	}
+
+	ret = dm_gpio_set_value(&rst, 1);
+	if (ret) {
+		log_err("can't set_value for rst gpio");
+		return ret;
+	}
+
+	//tPULSE_WIDTH = 30us
+	udelay(100);
+
+	ret = dm_gpio_set_value(&rst, 0);
+	if (ret) {
+		log_err("can't set_value for rst gpio");
+		return -1;
+	}
+
+	/*
+	 * After a RST has taken place, a wait time of ≥ 700 µs should be used
+	 * before reading or writing to the TCAN4550-Q1
+	 */
+	udelay(1000);
+
+	return tcan4x5x_enable_sleep(dev);
+}
+
+static const struct udevice_id tcan4x5x_ids[] = {
+	{ .compatible = "ti,tcan4x5x" },
+	{ }
+};
+
+U_BOOT_DRIVER(tcan4x5x) = {
+	.name = "tcan4x5x",
+	.id = UCLASS_MISC,
+	.of_match = tcan4x5x_ids,
+	.probe = tcan4x5x_probe,
+};
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.