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
