The PMIC offers regulators, GPIOs and system restart. Add restart only for now. Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- drivers/mfd/Kconfig | 10 +++ drivers/mfd/Makefile | 2 + drivers/mfd/core.c | 25 +++++++ drivers/mfd/tps65086.c | 76 ++++++++++++++++++++ drivers/power/reset/Kconfig | 6 ++ drivers/power/reset/Makefile | 1 + drivers/power/reset/tps65086-restart.c | 55 +++++++++++++++ include/linux/mfd/core.h | 26 +++++++ include/linux/mfd/tps65086.h | 98 ++++++++++++++++++++++++++ 9 files changed, 299 insertions(+) create mode 100644 drivers/mfd/core.c create mode 100644 drivers/mfd/tps65086.c create mode 100644 drivers/power/reset/tps65086-restart.c create mode 100644 include/linux/mfd/core.h create mode 100644 include/linux/mfd/tps65086.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d7a8949bafc8..6c76c86fa0cc 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -40,6 +40,16 @@ config MFD_SYSCON help Select this option to enable accessing system control registers +config MFD_TPS65086 + bool "TI TPS65086 Power Management Integrated Chips (PMICs)" + depends on I2C + help + If you say yes here you get support for the TPS65086 series of + Power Management chips. + This driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. + config MFD_TWLCORE bool diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 690e53693ebc..45037e06d62b 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_MFD_MC34704) += mc34704.o obj-$(CONFIG_MFD_MC9SDZ60) += mc9sdz60.o obj-$(CONFIG_MFD_STMPE) += stmpe-i2c.o obj-$(CONFIG_MFD_SYSCON) += syscon.o +obj-$(CONFIG_MFD_TPS65086) += tps65086.o obj-$(CONFIG_MFD_TWLCORE) += twl-core.o obj-$(CONFIG_MFD_TWL4030) += twl4030.o obj-$(CONFIG_MFD_TWL6030) += twl6030.o @@ -17,3 +18,4 @@ obj-$(CONFIG_FINTEK_SUPERIO) += fintek-superio.o obj-$(CONFIG_SMSC_SUPERIO) += smsc-superio.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o +obj-y += core.o diff --git a/drivers/mfd/core.c b/drivers/mfd/core.c new file mode 100644 index 000000000000..ee600d4baafd --- /dev/null +++ b/drivers/mfd/core.c @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <linux/mfd/core.h> +#include <driver.h> + +int mfd_add_devices(struct device_d *parent, const struct mfd_cell *cells, int n_devs) +{ + struct device_d *dev; + int ret, i; + + for (i = 0; i < n_devs; i++) { + dev = device_alloc(cells[i].name, DEVICE_ID_DYNAMIC); + dev->parent = parent; + + ret = platform_device_register(dev); + if (ret) + return ret; + + ret = device_add_data(dev, (void *)&cells[i], sizeof(cells[i])); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c new file mode 100644 index 000000000000..12127922ad2b --- /dev/null +++ b/drivers/mfd/tps65086.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ + * Andrew F. Davis <afd@xxxxxx> + */ + +#include <common.h> +#include <driver.h> +#include <errno.h> +#include <i2c/i2c.h> +#include <linux/mfd/core.h> +#include <init.h> +#include <malloc.h> +#include <of.h> +#include <regmap.h> +#include <xfuncs.h> + +#include <linux/mfd/tps65086.h> + +static const struct mfd_cell tps65086_cells[] = { + { .name = "tps65086-regulator", }, + { .name = "tps65086-gpio", }, +}; + +static const struct regmap_config tps65086_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xB6, +}; + +static const struct of_device_id tps65086_of_match_table[] = { + { .compatible = "ti,tps65086", }, + { /* sentinel */ } +}; + +static int tps65086_probe(struct device_d *dev) +{ + struct tps65086 *tps; + unsigned int version; + int ret; + + tps = xzalloc(sizeof(*tps)); + tps->dev = dev; + + tps->regmap = regmap_init_i2c(to_i2c_client(dev), &tps65086_regmap_config); + if (IS_ERR(tps->regmap)) { + dev_err(tps->dev, "Failed to initialize register map\n"); + return PTR_ERR(tps->regmap); + } + + ret = regmap_read(tps->regmap, TPS65086_DEVICEID, &version); + if (ret) { + dev_err(tps->dev, "Failed to read revision register\n"); + return ret; + } + + dev_info(tps->dev, "Device: TPS65086%01lX, OTP: %c, Rev: %ld\n", + (version & TPS65086_DEVICEID_PART_MASK), + (char)((version & TPS65086_DEVICEID_OTP_MASK) >> 4) + 'A', + (version & TPS65086_DEVICEID_REV_MASK) >> 6); + + dev->priv = tps; + + return mfd_add_devices(tps->dev, tps65086_cells, ARRAY_SIZE(tps65086_cells)); +} + +static struct driver_d tps65086_driver = { + .name = "tps65086", + .of_compatible = tps65086_of_match_table, + .probe = tps65086_probe, +}; +device_i2c_driver(tps65086_driver); + +MODULE_AUTHOR("Andrew F. Davis <afd@xxxxxx>"); +MODULE_DESCRIPTION("TPS65086 PMIC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index dec1482ccd0c..09d6ba0d9031 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -44,3 +44,9 @@ config POWER_RESET_GPIO_RESTART This driver supports restarting your board via a GPIO line. If your board needs a GPIO high/low to restart, say Y and create a binding in your devicetree. + +config POWER_RESET_TPS65086 + bool "TPS65086 restart driver" + depends on MFD_TPS65086 + help + Reset TPS65086 PMIC on restart. diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 33d29d2d9546..b362400ba5ef 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o +obj-$(CONFIG_POWER_RESET_TPS65086) += tps65086-restart.o diff --git a/drivers/power/reset/tps65086-restart.c b/drivers/power/reset/tps65086-restart.c new file mode 100644 index 000000000000..686f215a7781 --- /dev/null +++ b/drivers/power/reset/tps65086-restart.c @@ -0,0 +1,55 @@ + +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Emil Renner Berthing + */ + +#include <common.h> +#include <init.h> +#include <regmap.h> +#include <restart.h> + +#include <linux/mfd/tps65086.h> + +struct tps65086_restart { + struct restart_handler handler; + struct tps65086 *tps; +}; + +static void __noreturn tps65086_restart_handle(struct restart_handler *this) +{ + struct tps65086_restart *tps65086_restart = + container_of(this, struct tps65086_restart, handler); + int ret; + + ret = regmap_write(tps65086_restart->tps->regmap, TPS65086_FORCESHUTDN, 1); + WARN_ON(ret); + + /* give it a little time */ + mdelay(200); + + panic("Unable to restart system\n"); +} + +static int tps65086_restart_probe(struct device_d *dev) +{ + struct tps65086_restart *tps65086_restart; + + tps65086_restart = xzalloc(sizeof(*tps65086_restart)); + tps65086_restart->tps = dev->parent->priv; + + tps65086_restart->handler.name = "tps65086-restart"; + tps65086_restart->handler.restart = tps65086_restart_handle; + tps65086_restart->handler.priority = 192; + + return restart_handler_register(&tps65086_restart->handler); +} + +static struct driver_d tps65086_restart_driver = { + .name = "tps65086-restart", + .probe = tps65086_restart_probe, +}; +device_platform_driver(tps65086_restart_driver); + +MODULE_AUTHOR("Emil Renner Berthing <kernel@xxxxxxxx>"); +MODULE_DESCRIPTION("TPS65086 restart driver"); diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h new file mode 100644 index 000000000000..b67ed25b1de8 --- /dev/null +++ b/include/linux/mfd/core.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/mfd/mfd-core.h + * + * core MFD support + * Copyright (c) 2006 Ian Molton + * Copyright (c) 2007 Dmitry Baryshkov + */ + +#ifndef MFD_CORE_H +#define MFD_CORE_H + +#include <driver.h> + +/* + * This struct describes the MFD part ("cell"). + * After registration the copy of this structure will become the platform data + * of the resulting device_d + */ +struct mfd_cell { + const char *name; +}; + +int mfd_add_devices(struct device_d *parent, const struct mfd_cell *cells, int n_devs); + +#endif diff --git a/include/linux/mfd/tps65086.h b/include/linux/mfd/tps65086.h new file mode 100644 index 000000000000..70ecde153ff2 --- /dev/null +++ b/include/linux/mfd/tps65086.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ + * Andrew F. Davis <afd@xxxxxx> + * + * Based on the TPS65912 driver + */ + +#ifndef __LINUX_MFD_TPS65086_H +#define __LINUX_MFD_TPS65086_H + +#include <driver.h> +#include <regmap.h> + +/* List of registers for TPS65086 */ +#define TPS65086_DEVICEID 0x01 +#define TPS65086_IRQ 0x02 +#define TPS65086_IRQ_MASK 0x03 +#define TPS65086_PMICSTAT 0x04 +#define TPS65086_SHUTDNSRC 0x05 +#define TPS65086_BUCK1CTRL 0x20 +#define TPS65086_BUCK2CTRL 0x21 +#define TPS65086_BUCK3DECAY 0x22 +#define TPS65086_BUCK3VID 0x23 +#define TPS65086_BUCK3SLPCTRL 0x24 +#define TPS65086_BUCK4CTRL 0x25 +#define TPS65086_BUCK5CTRL 0x26 +#define TPS65086_BUCK6CTRL 0x27 +#define TPS65086_LDOA2CTRL 0x28 +#define TPS65086_LDOA3CTRL 0x29 +#define TPS65086_DISCHCTRL1 0x40 +#define TPS65086_DISCHCTRL2 0x41 +#define TPS65086_DISCHCTRL3 0x42 +#define TPS65086_PG_DELAY1 0x43 +#define TPS65086_FORCESHUTDN 0x91 +#define TPS65086_BUCK1SLPCTRL 0x92 +#define TPS65086_BUCK2SLPCTRL 0x93 +#define TPS65086_BUCK4VID 0x94 +#define TPS65086_BUCK4SLPVID 0x95 +#define TPS65086_BUCK5VID 0x96 +#define TPS65086_BUCK5SLPVID 0x97 +#define TPS65086_BUCK6VID 0x98 +#define TPS65086_BUCK6SLPVID 0x99 +#define TPS65086_LDOA2VID 0x9A +#define TPS65086_LDOA3VID 0x9B +#define TPS65086_BUCK123CTRL 0x9C +#define TPS65086_PG_DELAY2 0x9D +#define TPS65086_PIN_EN_MASK1 0x9E +#define TPS65086_PIN_EN_MASK2 0x9F +#define TPS65086_SWVTT_EN 0x9F +#define TPS65086_PIN_EN_OVR1 0xA0 +#define TPS65086_PIN_EN_OVR2 0xA1 +#define TPS65086_GPOCTRL 0xA1 +#define TPS65086_PWR_FAULT_MASK1 0xA2 +#define TPS65086_PWR_FAULT_MASK2 0xA3 +#define TPS65086_GPO1PG_CTRL1 0xA4 +#define TPS65086_GPO1PG_CTRL2 0xA5 +#define TPS65086_GPO4PG_CTRL1 0xA6 +#define TPS65086_GPO4PG_CTRL2 0xA7 +#define TPS65086_GPO2PG_CTRL1 0xA8 +#define TPS65086_GPO2PG_CTRL2 0xA9 +#define TPS65086_GPO3PG_CTRL1 0xAA +#define TPS65086_GPO3PG_CTRL2 0xAB +#define TPS65086_LDOA1CTRL 0xAE +#define TPS65086_PG_STATUS1 0xB0 +#define TPS65086_PG_STATUS2 0xB1 +#define TPS65086_PWR_FAULT_STATUS1 0xB2 +#define TPS65086_PWR_FAULT_STATUS2 0xB3 +#define TPS65086_TEMPCRIT 0xB4 +#define TPS65086_TEMPHOT 0xB5 +#define TPS65086_OC_STATUS 0xB6 + +/* IRQ Register field definitions */ +#define TPS65086_IRQ_DIETEMP_MASK BIT(0) +#define TPS65086_IRQ_SHUTDN_MASK BIT(3) +#define TPS65086_IRQ_FAULT_MASK BIT(7) + +/* DEVICEID Register field definitions */ +#define TPS65086_DEVICEID_PART_MASK GENMASK(3, 0) +#define TPS65086_DEVICEID_OTP_MASK GENMASK(5, 4) +#define TPS65086_DEVICEID_REV_MASK GENMASK(7, 6) + +/* VID Masks */ +#define BUCK_VID_MASK GENMASK(7, 1) +#define VDOA1_VID_MASK GENMASK(4, 1) +#define VDOA23_VID_MASK GENMASK(3, 0) + +/** + * struct tps65086 - state holder for the tps65086 driver + * + * Device data may be used to access the TPS65086 chip + */ +struct tps65086 { + struct device_d *dev; + struct regmap *regmap; +}; + +#endif /* __LINUX_MFD_TPS65086_H */ -- 2.29.2 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox