diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2022-02-18 12:59:21 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2022-02-18 12:59:21 +0100 |
commit | 37fddd1ae02aac9f10eacd16bbd6142198ed7342 (patch) | |
tree | e621ad4d7dadc0fa18e267c2414c1032f3ac9963 /drivers | |
parent | 9481ada6ad354cfe38418354afee48ceca438c05 (diff) | |
parent | 2efa9e490569f909c6ba796d192b623ec9766b82 (diff) | |
download | barebox-37fddd1ae02aac9f10eacd16bbd6142198ed7342.tar.gz barebox-37fddd1ae02aac9f10eacd16bbd6142198ed7342.tar.xz |
Merge branch 'for-next/misc'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/efi-block-io.c | 42 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 6 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/rn5t568.c | 165 | ||||
-rw-r--r-- | drivers/mtd/devices/mtdram.c | 35 | ||||
-rw-r--r-- | drivers/of/of_path.c | 2 | ||||
-rw-r--r-- | drivers/power/reset/Kconfig | 3 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 6 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/rn5t568_wdt.c | 146 |
10 files changed, 373 insertions, 34 deletions
diff --git a/drivers/block/efi-block-io.c b/drivers/block/efi-block-io.c index ff0e467d2c..086afb378a 100644 --- a/drivers/block/efi-block-io.c +++ b/drivers/block/efi-block-io.c @@ -52,6 +52,7 @@ struct efi_bio_priv { struct device_d *dev; struct block_device blk; u32 media_id; + void (*efi_info)(struct device_d *); }; static int efi_bio_read(struct block_device *blk, void *buffer, sector_t block, @@ -101,35 +102,40 @@ static struct block_device_ops efi_bio_ops = { .flush = efi_bio_flush, }; -static void efi_bio_print_info(struct efi_bio_priv *priv) +static void efi_bio_print_info(struct device_d *dev) { + struct efi_bio_priv *priv = dev->priv; struct efi_block_io_media *media = priv->protocol->media; u64 revision = priv->protocol->revision; - dev_dbg(priv->dev, "revision: 0x%016llx\n", revision); - dev_dbg(priv->dev, "media_id: 0x%08x\n", media->media_id); - dev_dbg(priv->dev, "removable_media: %d\n", media->removable_media); - dev_dbg(priv->dev, "media_present: %d\n", media->media_present); - dev_dbg(priv->dev, "logical_partition: %d\n", media->logical_partition); - dev_dbg(priv->dev, "read_only: %d\n", media->read_only); - dev_dbg(priv->dev, "write_caching: %d\n", media->write_caching); - dev_dbg(priv->dev, "block_size: 0x%08x\n", media->block_size); - dev_dbg(priv->dev, "io_align: 0x%08x\n", media->io_align); - dev_dbg(priv->dev, "last_block: 0x%016llx\n", media->last_block); + printf("Block I/O Media:\n"); + printf(" revision: 0x%016llx\n", revision); + printf(" media_id: 0x%08x\n", media->media_id); + printf(" removable_media: %d\n", media->removable_media); + printf(" media_present: %d\n", media->media_present); + printf(" logical_partition: %d\n", media->logical_partition); + printf(" read_only: %d\n", media->read_only); + printf(" write_caching: %d\n", media->write_caching); + printf(" block_size: 0x%08x\n", media->block_size); + printf(" io_align: 0x%08x\n", media->io_align); + printf(" last_block: 0x%016llx\n", media->last_block); if (revision < EFI_BLOCK_IO_PROTOCOL_REVISION2) return; - dev_dbg(priv->dev, "u64 lowest_aligned_lba: 0x%08llx\n", + printf(" lowest_aligned_lba: 0x%08llx\n", media->lowest_aligned_lba); - dev_dbg(priv->dev, "logical_blocks_per_physical_block: 0x%08x\n", + printf(" logical_blocks_per_physical_block: 0x%08x\n", media->logical_blocks_per_physical_block); if (revision < EFI_BLOCK_IO_PROTOCOL_REVISION3) return; - dev_dbg(priv->dev, "optimal_transfer_length_granularity: 0x%08x\n", + printf(" optimal_transfer_length_granularity: 0x%08x\n", media->optimal_transfer_length_granularity); + + if (priv->efi_info) + priv->efi_info(dev); } static bool is_bio_usbdev(struct efi_device *efidev) @@ -143,6 +149,7 @@ static int efi_bio_probe(struct efi_device *efidev) int instance; struct efi_bio_priv *priv; struct efi_block_io_media *media; + struct device_d *dev = &efidev->dev; priv = xzalloc(sizeof(*priv)); @@ -151,8 +158,13 @@ static int efi_bio_probe(struct efi_device *efidev) if (!priv->protocol) return -ENODEV; + dev->priv = priv; + priv->efi_info = dev->info; + dev->info = efi_bio_print_info; + media = priv->protocol->media; - efi_bio_print_info(priv); + if (__is_defined(DEBUG)) + efi_bio_print_info(dev); priv->dev = &efidev->dev; if (is_bio_usbdev(efidev)) { diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 8468a2d1d1..160248072a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -68,6 +68,12 @@ config MFD_STPMIC1 help Select this to support communication with the STPMIC1. +config MFD_RN568PMIC + depends on I2C + bool "Ricoh RN5T568 MFD driver" + help + Select this to support communication with the Ricoh RN5T568 PMIC. + config MFD_SUPERIO bool diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2bcf90078a..50f54cfcf2 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MFD_TWL4030) += twl4030.o obj-$(CONFIG_MFD_TWL6030) += twl6030.o obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o +obj-$(CONFIG_MFD_RN568PMIC) += rn5t568.o obj-$(CONFIG_MFD_SUPERIO) += superio.o obj-$(CONFIG_FINTEK_SUPERIO) += fintek-superio.o obj-$(CONFIG_SMSC_SUPERIO) += smsc-superio.o diff --git a/drivers/mfd/rn5t568.c b/drivers/mfd/rn5t568.c new file mode 100644 index 0000000000..c1c792cbec --- /dev/null +++ b/drivers/mfd/rn5t568.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MFD core driver for Ricoh RN5T618 PMIC + * Note: Manufacturer is now Nisshinbo Micro Devices Inc. + * + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> + * Copyright (C) 2016 Toradex AG + */ + +#include <common.h> +#include <driver.h> +#include <errno.h> +#include <i2c/i2c.h> +#include <init.h> +#include <of.h> +#include <regmap.h> +#include <reset_source.h> +#include <restart.h> + +#define RN5T568_LSIVER 0x00 +#define RN5T568_OTPVER 0x01 +#define RN5T568_PONHIS 0x09 +# define RN5T568_PONHIS_ON_EXTINPON BIT(3) +# define RN5T568_PONHIS_ON_REPWRPON BIT(1) +# define RN5T568_PONHIS_ON_PWRONPON BIT(0) +#define RN5T568_POFFHIS 0x0a +# define RN5T568_POFFHIS_N_OEPOFF BIT(7) +# define RN5T568_POFFHIS_DCLIMPOFF BIT(6) +# define RN5T568_POFFHIS_WDGPOFF BIT(5) +# define RN5T568_POFFHIS_CPUPOFF BIT(4) +# define RN5T568_POFFHIS_IODETPOFF BIT(3) +# define RN5T568_POFFHIS_VINDETPOFF BIT(2) +# define RN5T568_POFFHIS_TSHUTPOFF BIT(1) +# define RN5T568_POFFHIS_PWRONPOFF BIT(0) +#define RN5T568_SLPCNT 0x0e +# define RN5T568_SLPCNT_SWPPWROFF BIT(0) +#define RN5T568_REPCNT 0x0f +# define RN5T568_REPCNT_OFF_RESETO_16MS 0x30 +# define RN5T568_REPCNT_OFF_REPWRTIM_1000MS 0x06 +# define RN5T568_REPCNT_OFF_REPWRON BIT(0) +#define RN5T568_MAX_REG 0xbc + +struct rn5t568 { + struct restart_handler restart; + struct regmap *regmap; +}; + +static void rn5t568_restart(struct restart_handler *rst) +{ + struct rn5t568 *rn5t568 = container_of(rst, struct rn5t568, restart); + + regmap_write(rn5t568->regmap, RN5T568_SLPCNT, RN5T568_SLPCNT_SWPPWROFF); +} + +static int rn5t568_reset_reason_detect(struct device_d *dev, struct regmap *regmap) +{ + unsigned int reg; + int ret; + + ret = regmap_read(regmap, RN5T568_PONHIS, ®); + if (ret) + return ret; + + dev_dbg(dev, "Power-on history: %x\n", reg); + + if (reg == 0) { + dev_info(dev, "No power-on reason available\n"); + return 0; + } + + if (reg & RN5T568_PONHIS_ON_EXTINPON) { + reset_source_set_device(dev, RESET_POR); + return 0; + } else if (reg & RN5T568_PONHIS_ON_PWRONPON) { + reset_source_set_device(dev, RESET_POR); + return 0; + } else if (!(reg & RN5T568_PONHIS_ON_REPWRPON)) + return -EINVAL; + + ret = regmap_read(regmap, RN5T568_POFFHIS, ®); + if (ret) + return ret; + + dev_dbg(dev, "Power-off history: %x\n", reg); + + if (reg & RN5T568_POFFHIS_PWRONPOFF) + reset_source_set_device(dev, RESET_POR); + else if (reg & RN5T568_POFFHIS_TSHUTPOFF) + reset_source_set_device(dev, RESET_THERM); + else if (reg & RN5T568_POFFHIS_VINDETPOFF) + reset_source_set_device(dev, RESET_BROWNOUT); + else if (reg & RN5T568_POFFHIS_IODETPOFF) + reset_source_set_device(dev, RESET_UKWN); + else if (reg & RN5T568_POFFHIS_CPUPOFF) + reset_source_set_device(dev, RESET_RST); + else if (reg & RN5T568_POFFHIS_WDGPOFF) + reset_source_set_device(dev, RESET_WDG); + else if (reg & RN5T568_POFFHIS_DCLIMPOFF) + reset_source_set_device(dev, RESET_BROWNOUT); + else if (reg & RN5T568_POFFHIS_N_OEPOFF) + reset_source_set_device(dev, RESET_EXT); + else + return -EINVAL; + + return 0; +} + +static const struct regmap_config rn5t568_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RN5T568_MAX_REG, +}; + +static int __init rn5t568_i2c_probe(struct device_d *dev) +{ + struct rn5t568 *pmic_instance; + unsigned char reg[2]; + int ret; + + pmic_instance = xzalloc(sizeof(struct rn5t568)); + pmic_instance->regmap = regmap_init_i2c(to_i2c_client(dev), &rn5t568_regmap_config); + if (IS_ERR(pmic_instance->regmap)) + return PTR_ERR(pmic_instance->regmap); + + ret = regmap_register_cdev(pmic_instance->regmap, NULL); + if (ret) + return ret; + + ret = regmap_bulk_read(pmic_instance->regmap, RN5T568_LSIVER, ®, 2); + if (ret) { + dev_err(dev, "Failed to read PMIC version via I2C\n"); + return ret; + } + + dev_info(dev, "Found NMD RN5T568 LSI %x, OTP: %x\n", reg[0], reg[1]); + + /* Settings used to trigger software reset and by a watchdog trigger */ + regmap_write(pmic_instance->regmap, RN5T568_REPCNT, RN5T568_REPCNT_OFF_RESETO_16MS | + RN5T568_REPCNT_OFF_REPWRTIM_1000MS | RN5T568_REPCNT_OFF_REPWRON); + + pmic_instance->restart.priority = of_get_restart_priority(dev->device_node); + pmic_instance->restart.name = "RN5T568"; + pmic_instance->restart.restart = &rn5t568_restart; + restart_handler_register(&pmic_instance->restart); + dev_dbg(dev, "RN5t: Restart handler with priority %d registered\n", pmic_instance->restart.priority); + + ret = rn5t568_reset_reason_detect(dev, pmic_instance->regmap); + if (ret) + dev_warn(dev, "Failed to query reset reason\n"); + + return of_platform_populate(dev->device_node, NULL, dev); +} + +static __maybe_unused const struct of_device_id rn5t568_of_match[] = { + { .compatible = "ricoh,rn5t568", .data = NULL, }, + { } +}; + +static struct driver_d rn5t568_i2c_driver = { + .name = "rn5t568-i2c", + .probe = rn5t568_i2c_probe, + .of_compatible = DRV_OF_COMPAT(rn5t568_of_match), +}; + +coredevice_i2c_driver(rn5t568_i2c_driver); diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index ee1cbf792d..abef07d9c0 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -16,11 +16,6 @@ #include <malloc.h> #include <of.h> -struct mtdram_priv_data { - struct mtd_info mtd; - void *base; -}; - static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) { memset((char *)mtd->priv + instr->addr, 0xff, instr->len); @@ -43,11 +38,10 @@ static int ram_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retle static int mtdram_probe(struct device_d *dev) { + long type; struct resource *iores; - void __iomem *base; int device_id; struct mtd_info *mtd; - struct resource *res; loff_t size; int ret = 0; @@ -60,9 +54,11 @@ static int mtdram_probe(struct device_d *dev) mtd->name = xstrdup(alias); } + type = (long)device_get_match_data(dev); + if (!mtd->name) { device_id = DEVICE_ID_DYNAMIC; - mtd->name = "mtdram"; + mtd->name = type == MTD_RAM ? "mtdram" : "mtdrom"; } iores = dev_request_mem_resource(dev, 0); @@ -70,22 +66,23 @@ static int mtdram_probe(struct device_d *dev) ret = PTR_ERR(iores); goto nobase; } - base = IOMEM(iores->start); - res = dev_get_resource(dev, IORESOURCE_MEM, 0); - size = (unsigned long) resource_size(res); - mtd->priv = base; + mtd->priv = IOMEM(iores->start); + size = (unsigned long) resource_size(iores); - mtd->type = MTD_RAM; + mtd->type = type; mtd->writesize = 1; mtd->writebufsize = 64; - mtd->flags = MTD_CAP_RAM; mtd->size = size; mtd->_read = ram_read; - mtd->_write = ram_write; - mtd->_erase = ram_erase; - mtd->erasesize = 1; + + if (type == MTD_RAM) { + mtd->flags = MTD_CAP_RAM; + mtd->_write = ram_write; + mtd->_erase = ram_erase; + mtd->erasesize = 1; + } mtd->dev.parent = dev; @@ -101,6 +98,10 @@ nobase: static __maybe_unused struct of_device_id mtdram_dt_ids[] = { { .compatible = "mtd-ram", + .data = (void *)MTD_RAM + }, { + .compatible = "mtd-rom", + .data = (void *)MTD_ROM }, { /* sentinel */ } diff --git a/drivers/of/of_path.c b/drivers/of/of_path.c index 40154bf5e9..05c28bf052 100644 --- a/drivers/of/of_path.c +++ b/drivers/of/of_path.c @@ -31,7 +31,7 @@ struct device_d *of_find_device_by_node_path(const char *path) * * @node: The node to find the cdev for, can be the device or a * partition in the device - * @part: Optionally, a description of a parition of @node. See of_find_path + * @part: Optionally, a description of a partition of @node. See of_find_path * @outpath: if this function returns 0 outpath will contain the path belonging * to the input path description. Must be freed with free(). * @flags: use OF_FIND_PATH_FLAGS_BB to return the .bb device if available diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 968d4b8ba4..564b77ecba 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -12,7 +12,8 @@ config SYSCON_REBOOT_MODE help Say y here will enable reboot mode driver. This will get reboot mode arguments and store it in SYSCON mapped - register, then the bootloader can read it to take different + register, then the bootloader can read it and take different + action according to the mode. config NVMEM_REBOOT_MODE bool "Generic NVMEM reboot mode driver" diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 70c8be7ca9..b8772e016f 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -109,6 +109,12 @@ config STPMIC1_WATCHDOG help Enable to support configuration of the stpmic1's built-in watchdog. +config RN568_WATCHDOG + bool "Ricoh RN5t568 PMIC based Watchdog" + depends on MFD_RN568PMIC + help + Enable to support system control via the PMIC based watchdog. + config F71808E_WDT bool "Fintek F718xx, F818xx Super I/O Watchdog" depends on X86 diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 0d2f273f78..265ae179f1 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_BCM283X) += bcm2835_wdt.o obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o obj-$(CONFIG_STM32_IWDG_WATCHDOG) += stm32_iwdg.o obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o +obj-$(CONFIG_RN568_WATCHDOG) += rn5t568_wdt.o obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o obj-$(CONFIG_ITCO_WDT) += itco_wdt.o diff --git a/drivers/watchdog/rn5t568_wdt.c b/drivers/watchdog/rn5t568_wdt.c new file mode 100644 index 0000000000..a6443609e2 --- /dev/null +++ b/drivers/watchdog/rn5t568_wdt.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Watchdog driver for Ricoh RN5T618 PMIC + * + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> + */ + +#include <common.h> +#include <init.h> +#include <watchdog.h> +#include <regmap.h> +#include <of.h> + +#define RN5T568_WATCHDOG 0x0b +# define RN5T568_WATCHDOG_WDPWROFFEN BIT(2) +# define RN5T568_WATCHDOG_WDOGTIM_M (BIT(0) | BIT(1)) +#define RN5T568_PWRIREN 0x12 +# define RN5T568_PWRIREN_EN_WDOG BIT(6) +#define RN5T568_PWRIRQ 0x13 +# define RN5T568_PWRIRQ_IR_WDOG BIT(6) + +struct rn5t568_wdt { + struct watchdog wdd; + struct regmap *regmap; + unsigned int timeout; +}; + +struct rn5t568_wdt_tim { + u8 reg_val; + u8 time; +}; + +static const struct rn5t568_wdt_tim rn5t568_wdt_timeout[] = { + { .reg_val = 0, .time = 1, }, + { .reg_val = 1, .time = 8, }, + { .reg_val = 2, .time = 32, }, + { .reg_val = 3, .time = 128, }, +}; + +#define PMIC_WDT_MAX_TIMEOUT 128 + +static int rn5t568_wdt_start(struct regmap *regmap, int idx) +{ + int ret; + + ret = regmap_update_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDOGTIM_M, + rn5t568_wdt_timeout[idx].reg_val); + if (ret) + return ret; + + regmap_clear_bits(regmap, RN5T568_PWRIRQ, RN5T568_PWRIRQ_IR_WDOG); + regmap_set_bits(regmap, RN5T568_PWRIREN, RN5T568_PWRIREN_EN_WDOG); + + pr_debug("RN5t: Starting the watchdog with %u seconds\n", rn5t568_wdt_timeout[idx].time); + + return regmap_set_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDPWROFFEN); +} + +static int rn5t568_wdt_stop(struct regmap *regmap) +{ + int ret; + + ret = regmap_clear_bits(regmap, RN5T568_PWRIREN, RN5T568_PWRIREN_EN_WDOG); + if (ret) + return ret; + + return regmap_clear_bits(regmap, RN5T568_WATCHDOG, RN5T568_WATCHDOG_WDPWROFFEN); +} + +static int rn5t568_wdt_ping(struct regmap *regmap) +{ + unsigned int val; + int ret; + + ret = regmap_read(regmap, RN5T568_WATCHDOG, &val); + if (ret) + return ret; + + return regmap_write(regmap, RN5T568_WATCHDOG, val); +} + +static int rn5t568_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout) +{ + struct rn5t568_wdt *wdt = container_of(wdd, struct rn5t568_wdt, wdd); + int ret, i; + + if (!timeout) + return rn5t568_wdt_stop(wdt->regmap); + + for (i = 0; i < ARRAY_SIZE(rn5t568_wdt_timeout); i++) { + if (timeout < rn5t568_wdt_timeout[i].time) + break; + } + + if (i == ARRAY_SIZE(rn5t568_wdt_timeout)) + return -EINVAL; + + if (wdt->timeout == timeout) + return rn5t568_wdt_ping(wdt->regmap); + + ret = rn5t568_wdt_start(wdt->regmap, i); + if (ret) + return ret; + + wdt->timeout = rn5t568_wdt_timeout[i].time; + + return ret; +} + +static int rn5t568_wdt_probe(struct device_d *dev) +{ + struct rn5t568_wdt *wdt; + struct watchdog *wdd; + unsigned int val; + int ret; + + wdt = xzalloc(sizeof(*wdt)); + + wdt->regmap = dev_get_regmap(dev->parent, NULL); + if (IS_ERR(wdt->regmap)) + return PTR_ERR(wdt->regmap); + + wdd = &wdt->wdd; + wdd->hwdev = dev; + wdd->set_timeout = rn5t568_wdt_set_timeout; + wdd->timeout_max = PMIC_WDT_MAX_TIMEOUT; + + ret = regmap_read(wdt->regmap, RN5T568_WATCHDOG, &val); + if (ret == 0) + wdd->running = val & RN5T568_WATCHDOG_WDPWROFFEN ? + WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING; + + return watchdog_register(wdd); +} + +static __maybe_unused const struct of_device_id rn5t568_wdt_of_match[] = { + { .compatible = "ricoh,rn5t568-wdt" }, + { /* sentinel */ } +}; + +static struct driver_d rn5t568_wdt_driver = { + .name = "rn5t568-wdt", + .probe = rn5t568_wdt_probe, + .of_compatible = DRV_OF_COMPAT(rn5t568_wdt_of_match), +}; +device_platform_driver(rn5t568_wdt_driver); |