Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'ib-mfd-watchdog-v5.13' into ibs-for-mfd-merged

Immutable branch between MFD and Watchdog due for the v5.13 merge window

+775
+123
Documentation/devicetree/bindings/mfd/rohm,bd9576-pmic.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/mfd/rohm,bd9576-pmic.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ROHM BD9576MUF and BD9573MUF Power Management Integrated Circuit bindings 8 + 9 + maintainers: 10 + - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> 11 + 12 + description: | 13 + BD9576MUF and BD9573MUF are power management ICs primarily intended for 14 + powering the R-Car series processors. 15 + The IC provides 6 power outputs with configurable sequencing and safety 16 + monitoring. A watchdog logic with slow ping/windowed modes is also included. 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - rohm,bd9576 22 + - rohm,bd9573 23 + 24 + reg: 25 + description: 26 + I2C slave address. 27 + maxItems: 1 28 + 29 + interrupts: 30 + maxItems: 1 31 + 32 + rohm,vout1-en-low: 33 + description: 34 + BD9576 and BD9573 VOUT1 regulator enable state can be individually 35 + controlled by a GPIO. This is dictated by state of vout1-en pin during 36 + the PMIC startup. If vout1-en is LOW during PMIC startup then the VOUT1 37 + enable sate is controlled via this pin. Set this property if vout1-en 38 + is wired to be down at PMIC start-up. 39 + type: boolean 40 + 41 + rohm,vout1-en-gpios: 42 + description: 43 + GPIO specifier to specify the GPIO connected to vout1-en for vout1 ON/OFF 44 + state control. 45 + maxItems: 1 46 + 47 + rohm,ddr-sel-low: 48 + description: 49 + The BD9576 and BD9573 output voltage for DDR can be selected by setting 50 + the ddr-sel pin low or high. Set this property if ddr-sel is grounded. 51 + type: boolean 52 + 53 + rohm,watchdog-enable-gpios: 54 + description: The GPIO line used to enable the watchdog. 55 + maxItems: 1 56 + 57 + rohm,watchdog-ping-gpios: 58 + description: The GPIO line used to ping the watchdog. 59 + maxItems: 1 60 + 61 + rohm,hw-timeout-ms: 62 + maxItems: 2 63 + description: 64 + Watchog timeout in milliseconds. If single value is given it is 65 + the maximum timeout. Eg. if pinging watchdog is not done within this time 66 + limit the watchdog will be triggered. If two values are given watchdog 67 + is configured in "window mode". Then first value is limit for short-ping 68 + Eg. if watchdog is pinged sooner than that the watchdog will trigger. 69 + When two values is given the second value is the maximum timeout. 70 + # (HW) minimum for short timeout is 2ms, maximum 220 ms. 71 + # (HW) minimum for max timeout is 4ms, maximum 4416 ms. 72 + 73 + regulators: 74 + $ref: ../regulator/rohm,bd9576-regulator.yaml 75 + description: 76 + List of child nodes that specify the regulators. 77 + 78 + required: 79 + - compatible 80 + - reg 81 + - regulators 82 + 83 + additionalProperties: false 84 + 85 + examples: 86 + - | 87 + #include <dt-bindings/gpio/gpio.h> 88 + #include <dt-bindings/leds/common.h> 89 + i2c { 90 + #address-cells = <1>; 91 + #size-cells = <0>; 92 + pmic: pmic@30 { 93 + compatible = "rohm,bd9576"; 94 + reg = <0x30>; 95 + rohm,vout1-en-low; 96 + rohm,vout1-en-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; 97 + rohm,ddr-sel-low; 98 + rohm,watchdog-enable-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; 99 + rohm,watchdog-ping-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>; 100 + rohm,hw-timeout-ms = <150>, <2300>; 101 + 102 + regulators { 103 + boost1: regulator-vd50 { 104 + regulator-name = "VD50"; 105 + }; 106 + buck1: regulator-vd18 { 107 + regulator-name = "VD18"; 108 + }; 109 + buck2: regulator-vdddr { 110 + regulator-name = "VDDDR"; 111 + }; 112 + buck3: regulator-vd10 { 113 + regulator-name = "VD10"; 114 + }; 115 + ldo: regulator-voutl1 { 116 + regulator-name = "VOUTL1"; 117 + }; 118 + sw: regulator-vouts1 { 119 + regulator-name = "VOUTS1"; 120 + }; 121 + }; 122 + }; 123 + };
+4
MAINTAINERS
··· 15478 15478 F: drivers/mfd/rohm-bd70528.c 15479 15479 F: drivers/mfd/rohm-bd71828.c 15480 15480 F: drivers/mfd/rohm-bd718x7.c 15481 + F: drivers/mfd/rohm-bd9576.c 15481 15482 F: drivers/power/supply/bd70528-charger.c 15482 15483 F: drivers/regulator/bd70528-regulator.c 15483 15484 F: drivers/regulator/bd71815-regulator.c 15484 15485 F: drivers/regulator/bd71828-regulator.c 15485 15486 F: drivers/regulator/bd718x7-regulator.c 15487 + F: drivers/regulator/bd9576-regulator.c 15486 15488 F: drivers/regulator/rohm-regulator.c 15487 15489 F: drivers/rtc/rtc-bd70528.c 15488 15490 F: drivers/watchdog/bd70528_wdt.c 15491 + F: drivers/watchdog/bd9576_wdt.c 15489 15492 F: include/linux/mfd/rohm-bd70528.h 15490 15493 F: include/linux/mfd/rohm-bd71815.h 15491 15494 F: include/linux/mfd/rohm-bd71828.h 15492 15495 F: include/linux/mfd/rohm-bd718x7.h 15496 + F: include/linux/mfd/rohm-bd957x.h 15493 15497 F: include/linux/mfd/rohm-generic.h 15494 15498 F: include/linux/mfd/rohm-shared.h 15495 15499
+11
drivers/mfd/Kconfig
··· 2001 2001 also a single-cell linear charger, a Coulomb counter, a real-time 2002 2002 clock (RTC), GPIOs and a 32.768 kHz clock gate. 2003 2003 2004 + config MFD_ROHM_BD957XMUF 2005 + tristate "ROHM BD9576MUF and BD9573MUF Power Management ICs" 2006 + depends on I2C=y 2007 + depends on OF 2008 + select REGMAP_I2C 2009 + select MFD_CORE 2010 + help 2011 + Select this option to get support for the ROHM BD9576MUF and 2012 + BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily 2013 + designed to be used to power R-Car series processors. 2014 + 2004 2015 config MFD_STM32_LPTIMER 2005 2016 tristate "Support for STM32 Low-Power Timer" 2006 2017 depends on (ARCH_STM32 && OF) || COMPILE_TEST
+1
drivers/mfd/Makefile
··· 262 262 obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o 263 263 obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o 264 264 obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o 265 + obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o 265 266 obj-$(CONFIG_MFD_STMFX) += stmfx.o 266 267 obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o 267 268 obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
+189
drivers/mfd/rohm-bd9576.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (C) 2021 ROHM Semiconductors 4 + * 5 + * ROHM BD9576MUF and BD9573MUF PMIC driver 6 + */ 7 + 8 + #include <linux/i2c.h> 9 + #include <linux/interrupt.h> 10 + #include <linux/ioport.h> 11 + #include <linux/irq.h> 12 + #include <linux/mfd/core.h> 13 + #include <linux/mfd/rohm-bd957x.h> 14 + #include <linux/mfd/rohm-generic.h> 15 + #include <linux/module.h> 16 + #include <linux/of_device.h> 17 + #include <linux/regmap.h> 18 + #include <linux/types.h> 19 + 20 + enum { 21 + BD957X_REGULATOR_CELL, 22 + BD957X_WDT_CELL, 23 + }; 24 + 25 + /* 26 + * Due to the BD9576MUF nasty IRQ behaiour we don't always populate IRQs. 27 + * These will be added to regulator resources only if IRQ information for the 28 + * PMIC is populated in device-tree. 29 + */ 30 + static const struct resource bd9576_regulator_irqs[] = { 31 + DEFINE_RES_IRQ_NAMED(BD9576_INT_THERM, "bd9576-temp"), 32 + DEFINE_RES_IRQ_NAMED(BD9576_INT_OVD, "bd9576-ovd"), 33 + DEFINE_RES_IRQ_NAMED(BD9576_INT_UVD, "bd9576-uvd"), 34 + }; 35 + 36 + static struct mfd_cell bd9573_mfd_cells[] = { 37 + [BD957X_REGULATOR_CELL] = { .name = "bd9573-regulator", }, 38 + [BD957X_WDT_CELL] = { .name = "bd9576-wdt", }, 39 + }; 40 + 41 + static struct mfd_cell bd9576_mfd_cells[] = { 42 + [BD957X_REGULATOR_CELL] = { .name = "bd9576-regulator", }, 43 + [BD957X_WDT_CELL] = { .name = "bd9576-wdt", }, 44 + }; 45 + 46 + static const struct regmap_range volatile_ranges[] = { 47 + regmap_reg_range(BD957X_REG_SMRB_ASSERT, BD957X_REG_SMRB_ASSERT), 48 + regmap_reg_range(BD957X_REG_PMIC_INTERNAL_STAT, 49 + BD957X_REG_PMIC_INTERNAL_STAT), 50 + regmap_reg_range(BD957X_REG_INT_THERM_STAT, BD957X_REG_INT_THERM_STAT), 51 + regmap_reg_range(BD957X_REG_INT_OVP_STAT, BD957X_REG_INT_SYS_STAT), 52 + regmap_reg_range(BD957X_REG_INT_MAIN_STAT, BD957X_REG_INT_MAIN_STAT), 53 + }; 54 + 55 + static const struct regmap_access_table volatile_regs = { 56 + .yes_ranges = &volatile_ranges[0], 57 + .n_yes_ranges = ARRAY_SIZE(volatile_ranges), 58 + }; 59 + 60 + static struct regmap_config bd957x_regmap = { 61 + .reg_bits = 8, 62 + .val_bits = 8, 63 + .volatile_table = &volatile_regs, 64 + .max_register = BD957X_MAX_REGISTER, 65 + .cache_type = REGCACHE_RBTREE, 66 + }; 67 + 68 + static struct regmap_irq bd9576_irqs[] = { 69 + REGMAP_IRQ_REG(BD9576_INT_THERM, 0, BD957X_MASK_INT_MAIN_THERM), 70 + REGMAP_IRQ_REG(BD9576_INT_OVP, 0, BD957X_MASK_INT_MAIN_OVP), 71 + REGMAP_IRQ_REG(BD9576_INT_SCP, 0, BD957X_MASK_INT_MAIN_SCP), 72 + REGMAP_IRQ_REG(BD9576_INT_OCP, 0, BD957X_MASK_INT_MAIN_OCP), 73 + REGMAP_IRQ_REG(BD9576_INT_OVD, 0, BD957X_MASK_INT_MAIN_OVD), 74 + REGMAP_IRQ_REG(BD9576_INT_UVD, 0, BD957X_MASK_INT_MAIN_UVD), 75 + REGMAP_IRQ_REG(BD9576_INT_UVP, 0, BD957X_MASK_INT_MAIN_UVP), 76 + REGMAP_IRQ_REG(BD9576_INT_SYS, 0, BD957X_MASK_INT_MAIN_SYS), 77 + }; 78 + 79 + static struct regmap_irq_chip bd9576_irq_chip = { 80 + .name = "bd9576_irq", 81 + .irqs = &bd9576_irqs[0], 82 + .num_irqs = ARRAY_SIZE(bd9576_irqs), 83 + .status_base = BD957X_REG_INT_MAIN_STAT, 84 + .mask_base = BD957X_REG_INT_MAIN_MASK, 85 + .ack_base = BD957X_REG_INT_MAIN_STAT, 86 + .init_ack_masked = true, 87 + .num_regs = 1, 88 + .irq_reg_stride = 1, 89 + }; 90 + 91 + static int bd957x_i2c_probe(struct i2c_client *i2c, 92 + const struct i2c_device_id *id) 93 + { 94 + int ret; 95 + struct regmap *regmap; 96 + struct mfd_cell *cells; 97 + int num_cells; 98 + unsigned long chip_type; 99 + struct irq_domain *domain; 100 + bool usable_irqs; 101 + 102 + chip_type = (unsigned long)of_device_get_match_data(&i2c->dev); 103 + 104 + switch (chip_type) { 105 + case ROHM_CHIP_TYPE_BD9576: 106 + cells = bd9576_mfd_cells; 107 + num_cells = ARRAY_SIZE(bd9576_mfd_cells); 108 + usable_irqs = !!i2c->irq; 109 + break; 110 + case ROHM_CHIP_TYPE_BD9573: 111 + cells = bd9573_mfd_cells; 112 + num_cells = ARRAY_SIZE(bd9573_mfd_cells); 113 + /* 114 + * BD9573 only supports fatal IRQs which we can not handle 115 + * because SoC is going to lose the power. 116 + */ 117 + usable_irqs = false; 118 + break; 119 + default: 120 + dev_err(&i2c->dev, "Unknown device type"); 121 + return -EINVAL; 122 + } 123 + 124 + regmap = devm_regmap_init_i2c(i2c, &bd957x_regmap); 125 + if (IS_ERR(regmap)) { 126 + dev_err(&i2c->dev, "Failed to initialize Regmap\n"); 127 + return PTR_ERR(regmap); 128 + } 129 + 130 + /* 131 + * BD9576 behaves badly. It kepts IRQ line asserted for the whole 132 + * duration of detected HW condition (like over temperature). So we 133 + * don't require IRQ to be populated. 134 + * If IRQ information is not given, then we mask all IRQs and do not 135 + * provide IRQ resources to regulator driver - which then just omits 136 + * the notifiers. 137 + */ 138 + if (usable_irqs) { 139 + struct regmap_irq_chip_data *irq_data; 140 + struct mfd_cell *regulators; 141 + 142 + regulators = &bd9576_mfd_cells[BD957X_REGULATOR_CELL]; 143 + regulators->resources = bd9576_regulator_irqs; 144 + regulators->num_resources = ARRAY_SIZE(bd9576_regulator_irqs); 145 + 146 + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq, 147 + IRQF_ONESHOT, 0, 148 + &bd9576_irq_chip, &irq_data); 149 + if (ret) { 150 + dev_err(&i2c->dev, "Failed to add IRQ chip\n"); 151 + return ret; 152 + } 153 + domain = regmap_irq_get_domain(irq_data); 154 + } else { 155 + ret = regmap_update_bits(regmap, BD957X_REG_INT_MAIN_MASK, 156 + BD957X_MASK_INT_ALL, 157 + BD957X_MASK_INT_ALL); 158 + if (ret) 159 + return ret; 160 + domain = NULL; 161 + } 162 + 163 + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, cells, 164 + num_cells, NULL, 0, domain); 165 + if (ret) 166 + dev_err(&i2c->dev, "Failed to create subdevices\n"); 167 + 168 + return ret; 169 + } 170 + 171 + static const struct of_device_id bd957x_of_match[] = { 172 + { .compatible = "rohm,bd9576", .data = (void *)ROHM_CHIP_TYPE_BD9576, }, 173 + { .compatible = "rohm,bd9573", .data = (void *)ROHM_CHIP_TYPE_BD9573, }, 174 + { }, 175 + }; 176 + MODULE_DEVICE_TABLE(of, bd957x_of_match); 177 + 178 + static struct i2c_driver bd957x_drv = { 179 + .driver = { 180 + .name = "rohm-bd957x", 181 + .of_match_table = bd957x_of_match, 182 + }, 183 + .probe = &bd957x_i2c_probe, 184 + }; 185 + module_i2c_driver(bd957x_drv); 186 + 187 + MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 188 + MODULE_DESCRIPTION("ROHM BD9576MUF and BD9573MUF Power Management IC driver"); 189 + MODULE_LICENSE("GPL");
+13
drivers/watchdog/Kconfig
··· 172 172 Alternatively say M to compile the driver as a module, 173 173 which will be called bd70528_wdt. 174 174 175 + config BD957XMUF_WATCHDOG 176 + tristate "ROHM BD9576MUF and BD9573MUF PMIC Watchdog" 177 + depends on MFD_ROHM_BD957XMUF 178 + select WATCHDOG_CORE 179 + help 180 + Support for the watchdog in the ROHM BD9576 and BD9573 PMICs. 181 + These PMIC ICs contain watchdog block which can be configured 182 + to toggle reset line if SoC fails to ping watchdog via GPIO. 183 + 184 + Say Y here to include support for the ROHM BD9576 or BD9573 185 + watchdog. Alternatively say M to compile the driver as a module, 186 + which will be called bd9576_wdt. 187 + 175 188 config DA9052_WATCHDOG 176 189 tristate "Dialog DA9052 Watchdog" 177 190 depends on PMIC_DA9052 || COMPILE_TEST
+1
drivers/watchdog/Makefile
··· 204 204 205 205 # Architecture Independent 206 206 obj-$(CONFIG_BD70528_WATCHDOG) += bd70528_wdt.o 207 + obj-$(CONFIG_BD957XMUF_WATCHDOG) += bd9576_wdt.o 207 208 obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o 208 209 obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o 209 210 obj-$(CONFIG_DA9062_WATCHDOG) += da9062_wdt.o
+291
drivers/watchdog/bd9576_wdt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (C) 2020 ROHM Semiconductors 4 + * 5 + * ROHM BD9576MUF and BD9573MUF Watchdog driver 6 + */ 7 + 8 + #include <linux/err.h> 9 + #include <linux/gpio/consumer.h> 10 + #include <linux/mfd/rohm-bd957x.h> 11 + #include <linux/module.h> 12 + #include <linux/of.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/regmap.h> 15 + #include <linux/watchdog.h> 16 + 17 + static bool nowayout; 18 + module_param(nowayout, bool, 0); 19 + MODULE_PARM_DESC(nowayout, 20 + "Watchdog cannot be stopped once started (default=\"false\")"); 21 + 22 + #define HW_MARGIN_MIN 2 23 + #define HW_MARGIN_MAX 4416 24 + #define BD957X_WDT_DEFAULT_MARGIN 4416 25 + #define WATCHDOG_TIMEOUT 30 26 + 27 + struct bd9576_wdt_priv { 28 + struct gpio_desc *gpiod_ping; 29 + struct gpio_desc *gpiod_en; 30 + struct device *dev; 31 + struct regmap *regmap; 32 + bool always_running; 33 + struct watchdog_device wdd; 34 + }; 35 + 36 + static void bd9576_wdt_disable(struct bd9576_wdt_priv *priv) 37 + { 38 + gpiod_set_value_cansleep(priv->gpiod_en, 0); 39 + } 40 + 41 + static int bd9576_wdt_ping(struct watchdog_device *wdd) 42 + { 43 + struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd); 44 + 45 + /* Pulse */ 46 + gpiod_set_value_cansleep(priv->gpiod_ping, 1); 47 + gpiod_set_value_cansleep(priv->gpiod_ping, 0); 48 + 49 + return 0; 50 + } 51 + 52 + static int bd9576_wdt_start(struct watchdog_device *wdd) 53 + { 54 + struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd); 55 + 56 + gpiod_set_value_cansleep(priv->gpiod_en, 1); 57 + 58 + return bd9576_wdt_ping(wdd); 59 + } 60 + 61 + static int bd9576_wdt_stop(struct watchdog_device *wdd) 62 + { 63 + struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd); 64 + 65 + if (!priv->always_running) 66 + bd9576_wdt_disable(priv); 67 + else 68 + set_bit(WDOG_HW_RUNNING, &wdd->status); 69 + 70 + return 0; 71 + } 72 + 73 + static const struct watchdog_info bd957x_wdt_ident = { 74 + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | 75 + WDIOF_SETTIMEOUT, 76 + .identity = "BD957x Watchdog", 77 + }; 78 + 79 + static const struct watchdog_ops bd957x_wdt_ops = { 80 + .owner = THIS_MODULE, 81 + .start = bd9576_wdt_start, 82 + .stop = bd9576_wdt_stop, 83 + .ping = bd9576_wdt_ping, 84 + }; 85 + 86 + /* Unit is hundreds of uS */ 87 + #define FASTNG_MIN 23 88 + 89 + static int find_closest_fast(int target, int *sel, int *val) 90 + { 91 + int i; 92 + int window = FASTNG_MIN; 93 + 94 + for (i = 0; i < 8 && window < target; i++) 95 + window <<= 1; 96 + 97 + *val = window; 98 + *sel = i; 99 + 100 + if (i == 8) 101 + return -EINVAL; 102 + 103 + return 0; 104 + 105 + } 106 + 107 + static int find_closest_slow_by_fast(int fast_val, int target, int *slowsel) 108 + { 109 + int sel; 110 + static const int multipliers[] = {2, 3, 7, 15}; 111 + 112 + for (sel = 0; sel < ARRAY_SIZE(multipliers) && 113 + multipliers[sel] * fast_val < target; sel++) 114 + ; 115 + 116 + if (sel == ARRAY_SIZE(multipliers)) 117 + return -EINVAL; 118 + 119 + *slowsel = sel; 120 + 121 + return 0; 122 + } 123 + 124 + static int find_closest_slow(int target, int *slow_sel, int *fast_sel) 125 + { 126 + static const int multipliers[] = {2, 3, 7, 15}; 127 + int i, j; 128 + int val = 0; 129 + int window = FASTNG_MIN; 130 + 131 + for (i = 0; i < 8; i++) { 132 + for (j = 0; j < ARRAY_SIZE(multipliers); j++) { 133 + int slow; 134 + 135 + slow = window * multipliers[j]; 136 + if (slow >= target && (!val || slow < val)) { 137 + val = slow; 138 + *fast_sel = i; 139 + *slow_sel = j; 140 + } 141 + } 142 + window <<= 1; 143 + } 144 + if (!val) 145 + return -EINVAL; 146 + 147 + return 0; 148 + } 149 + 150 + #define BD957X_WDG_TYPE_WINDOW BIT(5) 151 + #define BD957X_WDG_TYPE_SLOW 0 152 + #define BD957X_WDG_TYPE_MASK BIT(5) 153 + #define BD957X_WDG_NG_RATIO_MASK 0x18 154 + #define BD957X_WDG_FASTNG_MASK 0x7 155 + 156 + static int bd957x_set_wdt_mode(struct bd9576_wdt_priv *priv, int hw_margin, 157 + int hw_margin_min) 158 + { 159 + int ret, fastng, slowng, type, reg, mask; 160 + struct device *dev = priv->dev; 161 + 162 + /* convert to 100uS */ 163 + hw_margin *= 10; 164 + hw_margin_min *= 10; 165 + if (hw_margin_min) { 166 + int min; 167 + 168 + type = BD957X_WDG_TYPE_WINDOW; 169 + dev_dbg(dev, "Setting type WINDOW 0x%x\n", type); 170 + ret = find_closest_fast(hw_margin_min, &fastng, &min); 171 + if (ret) { 172 + dev_err(dev, "bad WDT window for fast timeout\n"); 173 + return ret; 174 + } 175 + 176 + ret = find_closest_slow_by_fast(min, hw_margin, &slowng); 177 + if (ret) { 178 + dev_err(dev, "bad WDT window\n"); 179 + return ret; 180 + } 181 + 182 + } else { 183 + type = BD957X_WDG_TYPE_SLOW; 184 + dev_dbg(dev, "Setting type SLOW 0x%x\n", type); 185 + ret = find_closest_slow(hw_margin, &slowng, &fastng); 186 + if (ret) { 187 + dev_err(dev, "bad WDT window\n"); 188 + return ret; 189 + } 190 + } 191 + 192 + slowng <<= ffs(BD957X_WDG_NG_RATIO_MASK) - 1; 193 + reg = type | slowng | fastng; 194 + mask = BD957X_WDG_TYPE_MASK | BD957X_WDG_NG_RATIO_MASK | 195 + BD957X_WDG_FASTNG_MASK; 196 + ret = regmap_update_bits(priv->regmap, BD957X_REG_WDT_CONF, 197 + mask, reg); 198 + 199 + return ret; 200 + } 201 + 202 + static int bd9576_wdt_probe(struct platform_device *pdev) 203 + { 204 + struct device *dev = &pdev->dev; 205 + struct device_node *np = dev->parent->of_node; 206 + struct bd9576_wdt_priv *priv; 207 + u32 hw_margin[2]; 208 + u32 hw_margin_max = BD957X_WDT_DEFAULT_MARGIN, hw_margin_min = 0; 209 + int ret; 210 + 211 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 212 + if (!priv) 213 + return -ENOMEM; 214 + 215 + platform_set_drvdata(pdev, priv); 216 + 217 + priv->dev = dev; 218 + priv->regmap = dev_get_regmap(dev->parent, NULL); 219 + if (!priv->regmap) { 220 + dev_err(dev, "No regmap found\n"); 221 + return -ENODEV; 222 + } 223 + 224 + priv->gpiod_en = devm_gpiod_get_from_of_node(dev, dev->parent->of_node, 225 + "rohm,watchdog-enable-gpios", 226 + 0, GPIOD_OUT_LOW, 227 + "watchdog-enable"); 228 + if (IS_ERR(priv->gpiod_en)) 229 + return dev_err_probe(dev, PTR_ERR(priv->gpiod_en), 230 + "getting watchdog-enable GPIO failed\n"); 231 + 232 + priv->gpiod_ping = devm_gpiod_get_from_of_node(dev, dev->parent->of_node, 233 + "rohm,watchdog-ping-gpios", 234 + 0, GPIOD_OUT_LOW, 235 + "watchdog-ping"); 236 + if (IS_ERR(priv->gpiod_ping)) 237 + return dev_err_probe(dev, PTR_ERR(priv->gpiod_ping), 238 + "getting watchdog-ping GPIO failed\n"); 239 + 240 + ret = of_property_read_variable_u32_array(np, "rohm,hw-timeout-ms", 241 + &hw_margin[0], 1, 2); 242 + if (ret < 0 && ret != -EINVAL) 243 + return ret; 244 + 245 + if (ret == 1) 246 + hw_margin_max = hw_margin[0]; 247 + 248 + if (ret == 2) { 249 + hw_margin_max = hw_margin[1]; 250 + hw_margin_min = hw_margin[0]; 251 + } 252 + 253 + ret = bd957x_set_wdt_mode(priv, hw_margin_max, hw_margin_min); 254 + if (ret) 255 + return ret; 256 + 257 + priv->always_running = of_property_read_bool(np, "always-running"); 258 + 259 + watchdog_set_drvdata(&priv->wdd, priv); 260 + 261 + priv->wdd.info = &bd957x_wdt_ident; 262 + priv->wdd.ops = &bd957x_wdt_ops; 263 + priv->wdd.min_hw_heartbeat_ms = hw_margin_min; 264 + priv->wdd.max_hw_heartbeat_ms = hw_margin_max; 265 + priv->wdd.parent = dev; 266 + priv->wdd.timeout = WATCHDOG_TIMEOUT; 267 + 268 + watchdog_init_timeout(&priv->wdd, 0, dev); 269 + watchdog_set_nowayout(&priv->wdd, nowayout); 270 + 271 + watchdog_stop_on_reboot(&priv->wdd); 272 + 273 + if (priv->always_running) 274 + bd9576_wdt_start(&priv->wdd); 275 + 276 + return devm_watchdog_register_device(dev, &priv->wdd); 277 + } 278 + 279 + static struct platform_driver bd9576_wdt_driver = { 280 + .driver = { 281 + .name = "bd9576-wdt", 282 + }, 283 + .probe = bd9576_wdt_probe, 284 + }; 285 + 286 + module_platform_driver(bd9576_wdt_driver); 287 + 288 + MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 289 + MODULE_DESCRIPTION("ROHM BD9576/BD9573 Watchdog driver"); 290 + MODULE_LICENSE("GPL"); 291 + MODULE_ALIAS("platform:bd9576-wdt");
+140
include/linux/mfd/rohm-bd957x.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* Copyright (C) 2021 ROHM Semiconductors */ 3 + 4 + #ifndef __LINUX_MFD_BD957X_H__ 5 + #define __LINUX_MFD_BD957X_H__ 6 + 7 + enum { 8 + BD957X_VD50, 9 + BD957X_VD18, 10 + BD957X_VDDDR, 11 + BD957X_VD10, 12 + BD957X_VOUTL1, 13 + BD957X_VOUTS1, 14 + }; 15 + 16 + /* 17 + * The BD9576 has own IRQ 'blocks' for: 18 + * - I2C/thermal, 19 + * - Over voltage protection 20 + * - Short-circuit protection 21 + * - Over current protection 22 + * - Over voltage detection 23 + * - Under voltage detection 24 + * - Under voltage protection 25 + * - 'system interrupt'. 26 + * 27 + * Each of the blocks have a status register giving more accurate IRQ source 28 + * information - for example which of the regulators have over-voltage. 29 + * 30 + * On top of this, there is "main IRQ" status register where each bit indicates 31 + * which of sub-blocks have active IRQs. Fine. That would fit regmap-irq main 32 + * status handling. Except that: 33 + * - Only some sub-IRQs can be masked. 34 + * - The IRQ informs us about fault-condition, not when fault state changes. 35 + * The IRQ line it is kept asserted until the detected condition is acked 36 + * AND cleared in HW. This is annoying for IRQs like the one informing high 37 + * temperature because if IRQ is not disabled it keeps the CPU in IRQ 38 + * handling loop. 39 + * 40 + * For now we do just use the main-IRQ register as source for our IRQ 41 + * information and bind the regmap-irq to this. We leave fine-grained sub-IRQ 42 + * register handling to handlers in sub-devices. The regulator driver shall 43 + * read which regulators are source for problem - or if the detected error is 44 + * regulator temperature error. The sub-drivers do also handle masking of "sub- 45 + * IRQs" if this is supported/needed. 46 + * 47 + * To overcome the problem with HW keeping IRQ asserted we do call 48 + * disable_irq_nosync() from sub-device handler and add a delayed work to 49 + * re-enable IRQ roughly 1 second later. This should keep our CPU out of 50 + * busy-loop. 51 + */ 52 + #define IRQS_SILENT_MS 1000 53 + 54 + enum { 55 + BD9576_INT_THERM, 56 + BD9576_INT_OVP, 57 + BD9576_INT_SCP, 58 + BD9576_INT_OCP, 59 + BD9576_INT_OVD, 60 + BD9576_INT_UVD, 61 + BD9576_INT_UVP, 62 + BD9576_INT_SYS, 63 + }; 64 + 65 + #define BD957X_REG_SMRB_ASSERT 0x15 66 + #define BD957X_REG_PMIC_INTERNAL_STAT 0x20 67 + #define BD957X_REG_INT_THERM_STAT 0x23 68 + #define BD957X_REG_INT_THERM_MASK 0x24 69 + #define BD957X_REG_INT_OVP_STAT 0x25 70 + #define BD957X_REG_INT_SCP_STAT 0x26 71 + #define BD957X_REG_INT_OCP_STAT 0x27 72 + #define BD957X_REG_INT_OVD_STAT 0x28 73 + #define BD957X_REG_INT_UVD_STAT 0x29 74 + #define BD957X_REG_INT_UVP_STAT 0x2a 75 + #define BD957X_REG_INT_SYS_STAT 0x2b 76 + #define BD957X_REG_INT_SYS_MASK 0x2c 77 + #define BD957X_REG_INT_MAIN_STAT 0x30 78 + #define BD957X_REG_INT_MAIN_MASK 0x31 79 + 80 + #define UVD_IRQ_VALID_MASK 0x6F 81 + #define OVD_IRQ_VALID_MASK 0x2F 82 + 83 + #define BD957X_MASK_INT_MAIN_THERM BIT(0) 84 + #define BD957X_MASK_INT_MAIN_OVP BIT(1) 85 + #define BD957X_MASK_INT_MAIN_SCP BIT(2) 86 + #define BD957X_MASK_INT_MAIN_OCP BIT(3) 87 + #define BD957X_MASK_INT_MAIN_OVD BIT(4) 88 + #define BD957X_MASK_INT_MAIN_UVD BIT(5) 89 + #define BD957X_MASK_INT_MAIN_UVP BIT(6) 90 + #define BD957X_MASK_INT_MAIN_SYS BIT(7) 91 + #define BD957X_MASK_INT_ALL 0xff 92 + 93 + #define BD957X_REG_WDT_CONF 0x16 94 + 95 + #define BD957X_REG_POW_TRIGGER1 0x41 96 + #define BD957X_REG_POW_TRIGGER2 0x42 97 + #define BD957X_REG_POW_TRIGGER3 0x43 98 + #define BD957X_REG_POW_TRIGGER4 0x44 99 + #define BD957X_REG_POW_TRIGGERL1 0x45 100 + #define BD957X_REG_POW_TRIGGERS1 0x46 101 + 102 + #define BD957X_REGULATOR_EN_MASK 0xff 103 + #define BD957X_REGULATOR_DIS_VAL 0xff 104 + 105 + #define BD957X_VSEL_REG_MASK 0xff 106 + 107 + #define BD957X_MASK_VOUT1_TUNE 0x87 108 + #define BD957X_MASK_VOUT2_TUNE 0x87 109 + #define BD957X_MASK_VOUT3_TUNE 0x1f 110 + #define BD957X_MASK_VOUT4_TUNE 0x1f 111 + #define BD957X_MASK_VOUTL1_TUNE 0x87 112 + 113 + #define BD957X_REG_VOUT1_TUNE 0x50 114 + #define BD957X_REG_VOUT2_TUNE 0x53 115 + #define BD957X_REG_VOUT3_TUNE 0x56 116 + #define BD957X_REG_VOUT4_TUNE 0x59 117 + #define BD957X_REG_VOUTL1_TUNE 0x5c 118 + 119 + #define BD9576_REG_VOUT1_OVD 0x51 120 + #define BD9576_REG_VOUT1_UVD 0x52 121 + #define BD9576_REG_VOUT2_OVD 0x54 122 + #define BD9576_REG_VOUT2_UVD 0x55 123 + #define BD9576_REG_VOUT3_OVD 0x57 124 + #define BD9576_REG_VOUT3_UVD 0x58 125 + #define BD9576_REG_VOUT4_OVD 0x5a 126 + #define BD9576_REG_VOUT4_UVD 0x5b 127 + #define BD9576_REG_VOUTL1_OVD 0x5d 128 + #define BD9576_REG_VOUTL1_UVD 0x5e 129 + 130 + #define BD9576_MASK_XVD 0x7f 131 + 132 + #define BD9576_REG_VOUT1S_OCW 0x5f 133 + #define BD9576_REG_VOUT1S_OCP 0x60 134 + 135 + #define BD9576_MASK_VOUT1S_OCW 0x3f 136 + #define BD9576_MASK_VOUT1S_OCP 0x3f 137 + 138 + #define BD957X_MAX_REGISTER 0x61 139 + 140 + #endif
+2
include/linux/mfd/rohm-generic.h
··· 9 9 10 10 enum rohm_chip_type { 11 11 ROHM_CHIP_TYPE_BD9571, 12 + ROHM_CHIP_TYPE_BD9573, 12 13 ROHM_CHIP_TYPE_BD9574, 14 + ROHM_CHIP_TYPE_BD9576, 13 15 ROHM_CHIP_TYPE_BD70528, 14 16 ROHM_CHIP_TYPE_BD71815, 15 17 ROHM_CHIP_TYPE_BD71828,