···11+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause22+%YAML 1.233+---44+$id: http://devicetree.org/schemas/mfd/rohm,bd9576-pmic.yaml#55+$schema: http://devicetree.org/meta-schemas/core.yaml#66+77+title: ROHM BD9576MUF and BD9573MUF Power Management Integrated Circuit bindings88+99+maintainers:1010+ - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>1111+1212+description: |1313+ BD9576MUF and BD9573MUF are power management ICs primarily intended for1414+ powering the R-Car series processors.1515+ The IC provides 6 power outputs with configurable sequencing and safety1616+ monitoring. A watchdog logic with slow ping/windowed modes is also included.1717+1818+properties:1919+ compatible:2020+ enum:2121+ - rohm,bd95762222+ - rohm,bd95732323+2424+ reg:2525+ description:2626+ I2C slave address.2727+ maxItems: 12828+2929+ interrupts:3030+ maxItems: 13131+3232+ rohm,vout1-en-low:3333+ description:3434+ BD9576 and BD9573 VOUT1 regulator enable state can be individually3535+ controlled by a GPIO. This is dictated by state of vout1-en pin during3636+ the PMIC startup. If vout1-en is LOW during PMIC startup then the VOUT13737+ enable sate is controlled via this pin. Set this property if vout1-en3838+ is wired to be down at PMIC start-up.3939+ type: boolean4040+4141+ rohm,vout1-en-gpios:4242+ description:4343+ GPIO specifier to specify the GPIO connected to vout1-en for vout1 ON/OFF4444+ state control.4545+ maxItems: 14646+4747+ rohm,ddr-sel-low:4848+ description:4949+ The BD9576 and BD9573 output voltage for DDR can be selected by setting5050+ the ddr-sel pin low or high. Set this property if ddr-sel is grounded.5151+ type: boolean5252+5353+ rohm,watchdog-enable-gpios:5454+ description: The GPIO line used to enable the watchdog.5555+ maxItems: 15656+5757+ rohm,watchdog-ping-gpios:5858+ description: The GPIO line used to ping the watchdog.5959+ maxItems: 16060+6161+ rohm,hw-timeout-ms:6262+ maxItems: 26363+ description:6464+ Watchog timeout in milliseconds. If single value is given it is6565+ the maximum timeout. Eg. if pinging watchdog is not done within this time6666+ limit the watchdog will be triggered. If two values are given watchdog6767+ is configured in "window mode". Then first value is limit for short-ping6868+ Eg. if watchdog is pinged sooner than that the watchdog will trigger.6969+ When two values is given the second value is the maximum timeout.7070+ # (HW) minimum for short timeout is 2ms, maximum 220 ms.7171+ # (HW) minimum for max timeout is 4ms, maximum 4416 ms.7272+7373+ regulators:7474+ $ref: ../regulator/rohm,bd9576-regulator.yaml7575+ description:7676+ List of child nodes that specify the regulators.7777+7878+required:7979+ - compatible8080+ - reg8181+ - regulators8282+8383+additionalProperties: false8484+8585+examples:8686+ - |8787+ #include <dt-bindings/gpio/gpio.h>8888+ #include <dt-bindings/leds/common.h>8989+ i2c {9090+ #address-cells = <1>;9191+ #size-cells = <0>;9292+ pmic: pmic@30 {9393+ compatible = "rohm,bd9576";9494+ reg = <0x30>;9595+ rohm,vout1-en-low;9696+ rohm,vout1-en-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;9797+ rohm,ddr-sel-low;9898+ rohm,watchdog-enable-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;9999+ rohm,watchdog-ping-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;100100+ rohm,hw-timeout-ms = <150>, <2300>;101101+102102+ regulators {103103+ boost1: regulator-vd50 {104104+ regulator-name = "VD50";105105+ };106106+ buck1: regulator-vd18 {107107+ regulator-name = "VD18";108108+ };109109+ buck2: regulator-vdddr {110110+ regulator-name = "VDDDR";111111+ };112112+ buck3: regulator-vd10 {113113+ regulator-name = "VD10";114114+ };115115+ ldo: regulator-voutl1 {116116+ regulator-name = "VOUTL1";117117+ };118118+ sw: regulator-vouts1 {119119+ regulator-name = "VOUTS1";120120+ };121121+ };122122+ };123123+ };
···20012001 also a single-cell linear charger, a Coulomb counter, a real-time20022002 clock (RTC), GPIOs and a 32.768 kHz clock gate.2003200320042004+config MFD_ROHM_BD957XMUF20052005+ tristate "ROHM BD9576MUF and BD9573MUF Power Management ICs"20062006+ depends on I2C=y20072007+ depends on OF20082008+ select REGMAP_I2C20092009+ select MFD_CORE20102010+ help20112011+ Select this option to get support for the ROHM BD9576MUF and20122012+ BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily20132013+ designed to be used to power R-Car series processors.20142014+20042015config MFD_STM32_LPTIMER20052016 tristate "Support for STM32 Low-Power Timer"20062017 depends on (ARCH_STM32 && OF) || COMPILE_TEST
···11+// SPDX-License-Identifier: GPL-2.0-or-later22+/*33+ * Copyright (C) 2021 ROHM Semiconductors44+ *55+ * ROHM BD9576MUF and BD9573MUF PMIC driver66+ */77+88+#include <linux/i2c.h>99+#include <linux/interrupt.h>1010+#include <linux/ioport.h>1111+#include <linux/irq.h>1212+#include <linux/mfd/core.h>1313+#include <linux/mfd/rohm-bd957x.h>1414+#include <linux/mfd/rohm-generic.h>1515+#include <linux/module.h>1616+#include <linux/of_device.h>1717+#include <linux/regmap.h>1818+#include <linux/types.h>1919+2020+enum {2121+ BD957X_REGULATOR_CELL,2222+ BD957X_WDT_CELL,2323+};2424+2525+/*2626+ * Due to the BD9576MUF nasty IRQ behaiour we don't always populate IRQs.2727+ * These will be added to regulator resources only if IRQ information for the2828+ * PMIC is populated in device-tree.2929+ */3030+static const struct resource bd9576_regulator_irqs[] = {3131+ DEFINE_RES_IRQ_NAMED(BD9576_INT_THERM, "bd9576-temp"),3232+ DEFINE_RES_IRQ_NAMED(BD9576_INT_OVD, "bd9576-ovd"),3333+ DEFINE_RES_IRQ_NAMED(BD9576_INT_UVD, "bd9576-uvd"),3434+};3535+3636+static struct mfd_cell bd9573_mfd_cells[] = {3737+ [BD957X_REGULATOR_CELL] = { .name = "bd9573-regulator", },3838+ [BD957X_WDT_CELL] = { .name = "bd9576-wdt", },3939+};4040+4141+static struct mfd_cell bd9576_mfd_cells[] = {4242+ [BD957X_REGULATOR_CELL] = { .name = "bd9576-regulator", },4343+ [BD957X_WDT_CELL] = { .name = "bd9576-wdt", },4444+};4545+4646+static const struct regmap_range volatile_ranges[] = {4747+ regmap_reg_range(BD957X_REG_SMRB_ASSERT, BD957X_REG_SMRB_ASSERT),4848+ regmap_reg_range(BD957X_REG_PMIC_INTERNAL_STAT,4949+ BD957X_REG_PMIC_INTERNAL_STAT),5050+ regmap_reg_range(BD957X_REG_INT_THERM_STAT, BD957X_REG_INT_THERM_STAT),5151+ regmap_reg_range(BD957X_REG_INT_OVP_STAT, BD957X_REG_INT_SYS_STAT),5252+ regmap_reg_range(BD957X_REG_INT_MAIN_STAT, BD957X_REG_INT_MAIN_STAT),5353+};5454+5555+static const struct regmap_access_table volatile_regs = {5656+ .yes_ranges = &volatile_ranges[0],5757+ .n_yes_ranges = ARRAY_SIZE(volatile_ranges),5858+};5959+6060+static struct regmap_config bd957x_regmap = {6161+ .reg_bits = 8,6262+ .val_bits = 8,6363+ .volatile_table = &volatile_regs,6464+ .max_register = BD957X_MAX_REGISTER,6565+ .cache_type = REGCACHE_RBTREE,6666+};6767+6868+static struct regmap_irq bd9576_irqs[] = {6969+ REGMAP_IRQ_REG(BD9576_INT_THERM, 0, BD957X_MASK_INT_MAIN_THERM),7070+ REGMAP_IRQ_REG(BD9576_INT_OVP, 0, BD957X_MASK_INT_MAIN_OVP),7171+ REGMAP_IRQ_REG(BD9576_INT_SCP, 0, BD957X_MASK_INT_MAIN_SCP),7272+ REGMAP_IRQ_REG(BD9576_INT_OCP, 0, BD957X_MASK_INT_MAIN_OCP),7373+ REGMAP_IRQ_REG(BD9576_INT_OVD, 0, BD957X_MASK_INT_MAIN_OVD),7474+ REGMAP_IRQ_REG(BD9576_INT_UVD, 0, BD957X_MASK_INT_MAIN_UVD),7575+ REGMAP_IRQ_REG(BD9576_INT_UVP, 0, BD957X_MASK_INT_MAIN_UVP),7676+ REGMAP_IRQ_REG(BD9576_INT_SYS, 0, BD957X_MASK_INT_MAIN_SYS),7777+};7878+7979+static struct regmap_irq_chip bd9576_irq_chip = {8080+ .name = "bd9576_irq",8181+ .irqs = &bd9576_irqs[0],8282+ .num_irqs = ARRAY_SIZE(bd9576_irqs),8383+ .status_base = BD957X_REG_INT_MAIN_STAT,8484+ .mask_base = BD957X_REG_INT_MAIN_MASK,8585+ .ack_base = BD957X_REG_INT_MAIN_STAT,8686+ .init_ack_masked = true,8787+ .num_regs = 1,8888+ .irq_reg_stride = 1,8989+};9090+9191+static int bd957x_i2c_probe(struct i2c_client *i2c,9292+ const struct i2c_device_id *id)9393+{9494+ int ret;9595+ struct regmap *regmap;9696+ struct mfd_cell *cells;9797+ int num_cells;9898+ unsigned long chip_type;9999+ struct irq_domain *domain;100100+ bool usable_irqs;101101+102102+ chip_type = (unsigned long)of_device_get_match_data(&i2c->dev);103103+104104+ switch (chip_type) {105105+ case ROHM_CHIP_TYPE_BD9576:106106+ cells = bd9576_mfd_cells;107107+ num_cells = ARRAY_SIZE(bd9576_mfd_cells);108108+ usable_irqs = !!i2c->irq;109109+ break;110110+ case ROHM_CHIP_TYPE_BD9573:111111+ cells = bd9573_mfd_cells;112112+ num_cells = ARRAY_SIZE(bd9573_mfd_cells);113113+ /*114114+ * BD9573 only supports fatal IRQs which we can not handle115115+ * because SoC is going to lose the power.116116+ */117117+ usable_irqs = false;118118+ break;119119+ default:120120+ dev_err(&i2c->dev, "Unknown device type");121121+ return -EINVAL;122122+ }123123+124124+ regmap = devm_regmap_init_i2c(i2c, &bd957x_regmap);125125+ if (IS_ERR(regmap)) {126126+ dev_err(&i2c->dev, "Failed to initialize Regmap\n");127127+ return PTR_ERR(regmap);128128+ }129129+130130+ /*131131+ * BD9576 behaves badly. It kepts IRQ line asserted for the whole132132+ * duration of detected HW condition (like over temperature). So we133133+ * don't require IRQ to be populated.134134+ * If IRQ information is not given, then we mask all IRQs and do not135135+ * provide IRQ resources to regulator driver - which then just omits136136+ * the notifiers.137137+ */138138+ if (usable_irqs) {139139+ struct regmap_irq_chip_data *irq_data;140140+ struct mfd_cell *regulators;141141+142142+ regulators = &bd9576_mfd_cells[BD957X_REGULATOR_CELL];143143+ regulators->resources = bd9576_regulator_irqs;144144+ regulators->num_resources = ARRAY_SIZE(bd9576_regulator_irqs);145145+146146+ ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,147147+ IRQF_ONESHOT, 0,148148+ &bd9576_irq_chip, &irq_data);149149+ if (ret) {150150+ dev_err(&i2c->dev, "Failed to add IRQ chip\n");151151+ return ret;152152+ }153153+ domain = regmap_irq_get_domain(irq_data);154154+ } else {155155+ ret = regmap_update_bits(regmap, BD957X_REG_INT_MAIN_MASK,156156+ BD957X_MASK_INT_ALL,157157+ BD957X_MASK_INT_ALL);158158+ if (ret)159159+ return ret;160160+ domain = NULL;161161+ }162162+163163+ ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, cells,164164+ num_cells, NULL, 0, domain);165165+ if (ret)166166+ dev_err(&i2c->dev, "Failed to create subdevices\n");167167+168168+ return ret;169169+}170170+171171+static const struct of_device_id bd957x_of_match[] = {172172+ { .compatible = "rohm,bd9576", .data = (void *)ROHM_CHIP_TYPE_BD9576, },173173+ { .compatible = "rohm,bd9573", .data = (void *)ROHM_CHIP_TYPE_BD9573, },174174+ { },175175+};176176+MODULE_DEVICE_TABLE(of, bd957x_of_match);177177+178178+static struct i2c_driver bd957x_drv = {179179+ .driver = {180180+ .name = "rohm-bd957x",181181+ .of_match_table = bd957x_of_match,182182+ },183183+ .probe = &bd957x_i2c_probe,184184+};185185+module_i2c_driver(bd957x_drv);186186+187187+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");188188+MODULE_DESCRIPTION("ROHM BD9576MUF and BD9573MUF Power Management IC driver");189189+MODULE_LICENSE("GPL");
+13
drivers/watchdog/Kconfig
···172172 Alternatively say M to compile the driver as a module,173173 which will be called bd70528_wdt.174174175175+config BD957XMUF_WATCHDOG176176+ tristate "ROHM BD9576MUF and BD9573MUF PMIC Watchdog"177177+ depends on MFD_ROHM_BD957XMUF178178+ select WATCHDOG_CORE179179+ help180180+ Support for the watchdog in the ROHM BD9576 and BD9573 PMICs.181181+ These PMIC ICs contain watchdog block which can be configured182182+ to toggle reset line if SoC fails to ping watchdog via GPIO.183183+184184+ Say Y here to include support for the ROHM BD9576 or BD9573185185+ watchdog. Alternatively say M to compile the driver as a module,186186+ which will be called bd9576_wdt.187187+175188config DA9052_WATCHDOG176189 tristate "Dialog DA9052 Watchdog"177190 depends on PMIC_DA9052 || COMPILE_TEST
···11+// SPDX-License-Identifier: GPL-2.0-or-later22+/*33+ * Copyright (C) 2020 ROHM Semiconductors44+ *55+ * ROHM BD9576MUF and BD9573MUF Watchdog driver66+ */77+88+#include <linux/err.h>99+#include <linux/gpio/consumer.h>1010+#include <linux/mfd/rohm-bd957x.h>1111+#include <linux/module.h>1212+#include <linux/of.h>1313+#include <linux/platform_device.h>1414+#include <linux/regmap.h>1515+#include <linux/watchdog.h>1616+1717+static bool nowayout;1818+module_param(nowayout, bool, 0);1919+MODULE_PARM_DESC(nowayout,2020+ "Watchdog cannot be stopped once started (default=\"false\")");2121+2222+#define HW_MARGIN_MIN 22323+#define HW_MARGIN_MAX 44162424+#define BD957X_WDT_DEFAULT_MARGIN 44162525+#define WATCHDOG_TIMEOUT 302626+2727+struct bd9576_wdt_priv {2828+ struct gpio_desc *gpiod_ping;2929+ struct gpio_desc *gpiod_en;3030+ struct device *dev;3131+ struct regmap *regmap;3232+ bool always_running;3333+ struct watchdog_device wdd;3434+};3535+3636+static void bd9576_wdt_disable(struct bd9576_wdt_priv *priv)3737+{3838+ gpiod_set_value_cansleep(priv->gpiod_en, 0);3939+}4040+4141+static int bd9576_wdt_ping(struct watchdog_device *wdd)4242+{4343+ struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd);4444+4545+ /* Pulse */4646+ gpiod_set_value_cansleep(priv->gpiod_ping, 1);4747+ gpiod_set_value_cansleep(priv->gpiod_ping, 0);4848+4949+ return 0;5050+}5151+5252+static int bd9576_wdt_start(struct watchdog_device *wdd)5353+{5454+ struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd);5555+5656+ gpiod_set_value_cansleep(priv->gpiod_en, 1);5757+5858+ return bd9576_wdt_ping(wdd);5959+}6060+6161+static int bd9576_wdt_stop(struct watchdog_device *wdd)6262+{6363+ struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd);6464+6565+ if (!priv->always_running)6666+ bd9576_wdt_disable(priv);6767+ else6868+ set_bit(WDOG_HW_RUNNING, &wdd->status);6969+7070+ return 0;7171+}7272+7373+static const struct watchdog_info bd957x_wdt_ident = {7474+ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |7575+ WDIOF_SETTIMEOUT,7676+ .identity = "BD957x Watchdog",7777+};7878+7979+static const struct watchdog_ops bd957x_wdt_ops = {8080+ .owner = THIS_MODULE,8181+ .start = bd9576_wdt_start,8282+ .stop = bd9576_wdt_stop,8383+ .ping = bd9576_wdt_ping,8484+};8585+8686+/* Unit is hundreds of uS */8787+#define FASTNG_MIN 238888+8989+static int find_closest_fast(int target, int *sel, int *val)9090+{9191+ int i;9292+ int window = FASTNG_MIN;9393+9494+ for (i = 0; i < 8 && window < target; i++)9595+ window <<= 1;9696+9797+ *val = window;9898+ *sel = i;9999+100100+ if (i == 8)101101+ return -EINVAL;102102+103103+ return 0;104104+105105+}106106+107107+static int find_closest_slow_by_fast(int fast_val, int target, int *slowsel)108108+{109109+ int sel;110110+ static const int multipliers[] = {2, 3, 7, 15};111111+112112+ for (sel = 0; sel < ARRAY_SIZE(multipliers) &&113113+ multipliers[sel] * fast_val < target; sel++)114114+ ;115115+116116+ if (sel == ARRAY_SIZE(multipliers))117117+ return -EINVAL;118118+119119+ *slowsel = sel;120120+121121+ return 0;122122+}123123+124124+static int find_closest_slow(int target, int *slow_sel, int *fast_sel)125125+{126126+ static const int multipliers[] = {2, 3, 7, 15};127127+ int i, j;128128+ int val = 0;129129+ int window = FASTNG_MIN;130130+131131+ for (i = 0; i < 8; i++) {132132+ for (j = 0; j < ARRAY_SIZE(multipliers); j++) {133133+ int slow;134134+135135+ slow = window * multipliers[j];136136+ if (slow >= target && (!val || slow < val)) {137137+ val = slow;138138+ *fast_sel = i;139139+ *slow_sel = j;140140+ }141141+ }142142+ window <<= 1;143143+ }144144+ if (!val)145145+ return -EINVAL;146146+147147+ return 0;148148+}149149+150150+#define BD957X_WDG_TYPE_WINDOW BIT(5)151151+#define BD957X_WDG_TYPE_SLOW 0152152+#define BD957X_WDG_TYPE_MASK BIT(5)153153+#define BD957X_WDG_NG_RATIO_MASK 0x18154154+#define BD957X_WDG_FASTNG_MASK 0x7155155+156156+static int bd957x_set_wdt_mode(struct bd9576_wdt_priv *priv, int hw_margin,157157+ int hw_margin_min)158158+{159159+ int ret, fastng, slowng, type, reg, mask;160160+ struct device *dev = priv->dev;161161+162162+ /* convert to 100uS */163163+ hw_margin *= 10;164164+ hw_margin_min *= 10;165165+ if (hw_margin_min) {166166+ int min;167167+168168+ type = BD957X_WDG_TYPE_WINDOW;169169+ dev_dbg(dev, "Setting type WINDOW 0x%x\n", type);170170+ ret = find_closest_fast(hw_margin_min, &fastng, &min);171171+ if (ret) {172172+ dev_err(dev, "bad WDT window for fast timeout\n");173173+ return ret;174174+ }175175+176176+ ret = find_closest_slow_by_fast(min, hw_margin, &slowng);177177+ if (ret) {178178+ dev_err(dev, "bad WDT window\n");179179+ return ret;180180+ }181181+182182+ } else {183183+ type = BD957X_WDG_TYPE_SLOW;184184+ dev_dbg(dev, "Setting type SLOW 0x%x\n", type);185185+ ret = find_closest_slow(hw_margin, &slowng, &fastng);186186+ if (ret) {187187+ dev_err(dev, "bad WDT window\n");188188+ return ret;189189+ }190190+ }191191+192192+ slowng <<= ffs(BD957X_WDG_NG_RATIO_MASK) - 1;193193+ reg = type | slowng | fastng;194194+ mask = BD957X_WDG_TYPE_MASK | BD957X_WDG_NG_RATIO_MASK |195195+ BD957X_WDG_FASTNG_MASK;196196+ ret = regmap_update_bits(priv->regmap, BD957X_REG_WDT_CONF,197197+ mask, reg);198198+199199+ return ret;200200+}201201+202202+static int bd9576_wdt_probe(struct platform_device *pdev)203203+{204204+ struct device *dev = &pdev->dev;205205+ struct device_node *np = dev->parent->of_node;206206+ struct bd9576_wdt_priv *priv;207207+ u32 hw_margin[2];208208+ u32 hw_margin_max = BD957X_WDT_DEFAULT_MARGIN, hw_margin_min = 0;209209+ int ret;210210+211211+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);212212+ if (!priv)213213+ return -ENOMEM;214214+215215+ platform_set_drvdata(pdev, priv);216216+217217+ priv->dev = dev;218218+ priv->regmap = dev_get_regmap(dev->parent, NULL);219219+ if (!priv->regmap) {220220+ dev_err(dev, "No regmap found\n");221221+ return -ENODEV;222222+ }223223+224224+ priv->gpiod_en = devm_gpiod_get_from_of_node(dev, dev->parent->of_node,225225+ "rohm,watchdog-enable-gpios",226226+ 0, GPIOD_OUT_LOW,227227+ "watchdog-enable");228228+ if (IS_ERR(priv->gpiod_en))229229+ return dev_err_probe(dev, PTR_ERR(priv->gpiod_en),230230+ "getting watchdog-enable GPIO failed\n");231231+232232+ priv->gpiod_ping = devm_gpiod_get_from_of_node(dev, dev->parent->of_node,233233+ "rohm,watchdog-ping-gpios",234234+ 0, GPIOD_OUT_LOW,235235+ "watchdog-ping");236236+ if (IS_ERR(priv->gpiod_ping))237237+ return dev_err_probe(dev, PTR_ERR(priv->gpiod_ping),238238+ "getting watchdog-ping GPIO failed\n");239239+240240+ ret = of_property_read_variable_u32_array(np, "rohm,hw-timeout-ms",241241+ &hw_margin[0], 1, 2);242242+ if (ret < 0 && ret != -EINVAL)243243+ return ret;244244+245245+ if (ret == 1)246246+ hw_margin_max = hw_margin[0];247247+248248+ if (ret == 2) {249249+ hw_margin_max = hw_margin[1];250250+ hw_margin_min = hw_margin[0];251251+ }252252+253253+ ret = bd957x_set_wdt_mode(priv, hw_margin_max, hw_margin_min);254254+ if (ret)255255+ return ret;256256+257257+ priv->always_running = of_property_read_bool(np, "always-running");258258+259259+ watchdog_set_drvdata(&priv->wdd, priv);260260+261261+ priv->wdd.info = &bd957x_wdt_ident;262262+ priv->wdd.ops = &bd957x_wdt_ops;263263+ priv->wdd.min_hw_heartbeat_ms = hw_margin_min;264264+ priv->wdd.max_hw_heartbeat_ms = hw_margin_max;265265+ priv->wdd.parent = dev;266266+ priv->wdd.timeout = WATCHDOG_TIMEOUT;267267+268268+ watchdog_init_timeout(&priv->wdd, 0, dev);269269+ watchdog_set_nowayout(&priv->wdd, nowayout);270270+271271+ watchdog_stop_on_reboot(&priv->wdd);272272+273273+ if (priv->always_running)274274+ bd9576_wdt_start(&priv->wdd);275275+276276+ return devm_watchdog_register_device(dev, &priv->wdd);277277+}278278+279279+static struct platform_driver bd9576_wdt_driver = {280280+ .driver = {281281+ .name = "bd9576-wdt",282282+ },283283+ .probe = bd9576_wdt_probe,284284+};285285+286286+module_platform_driver(bd9576_wdt_driver);287287+288288+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");289289+MODULE_DESCRIPTION("ROHM BD9576/BD9573 Watchdog driver");290290+MODULE_LICENSE("GPL");291291+MODULE_ALIAS("platform:bd9576-wdt");
+140
include/linux/mfd/rohm-bd957x.h
···11+/* SPDX-License-Identifier: GPL-2.0-or-later */22+/* Copyright (C) 2021 ROHM Semiconductors */33+44+#ifndef __LINUX_MFD_BD957X_H__55+#define __LINUX_MFD_BD957X_H__66+77+enum {88+ BD957X_VD50,99+ BD957X_VD18,1010+ BD957X_VDDDR,1111+ BD957X_VD10,1212+ BD957X_VOUTL1,1313+ BD957X_VOUTS1,1414+};1515+1616+/*1717+ * The BD9576 has own IRQ 'blocks' for:1818+ * - I2C/thermal,1919+ * - Over voltage protection2020+ * - Short-circuit protection2121+ * - Over current protection2222+ * - Over voltage detection2323+ * - Under voltage detection2424+ * - Under voltage protection2525+ * - 'system interrupt'.2626+ *2727+ * Each of the blocks have a status register giving more accurate IRQ source2828+ * information - for example which of the regulators have over-voltage.2929+ *3030+ * On top of this, there is "main IRQ" status register where each bit indicates3131+ * which of sub-blocks have active IRQs. Fine. That would fit regmap-irq main3232+ * status handling. Except that:3333+ * - Only some sub-IRQs can be masked.3434+ * - The IRQ informs us about fault-condition, not when fault state changes.3535+ * The IRQ line it is kept asserted until the detected condition is acked3636+ * AND cleared in HW. This is annoying for IRQs like the one informing high3737+ * temperature because if IRQ is not disabled it keeps the CPU in IRQ3838+ * handling loop.3939+ *4040+ * For now we do just use the main-IRQ register as source for our IRQ4141+ * information and bind the regmap-irq to this. We leave fine-grained sub-IRQ4242+ * register handling to handlers in sub-devices. The regulator driver shall4343+ * read which regulators are source for problem - or if the detected error is4444+ * regulator temperature error. The sub-drivers do also handle masking of "sub-4545+ * IRQs" if this is supported/needed.4646+ *4747+ * To overcome the problem with HW keeping IRQ asserted we do call4848+ * disable_irq_nosync() from sub-device handler and add a delayed work to4949+ * re-enable IRQ roughly 1 second later. This should keep our CPU out of5050+ * busy-loop.5151+ */5252+#define IRQS_SILENT_MS 10005353+5454+enum {5555+ BD9576_INT_THERM,5656+ BD9576_INT_OVP,5757+ BD9576_INT_SCP,5858+ BD9576_INT_OCP,5959+ BD9576_INT_OVD,6060+ BD9576_INT_UVD,6161+ BD9576_INT_UVP,6262+ BD9576_INT_SYS,6363+};6464+6565+#define BD957X_REG_SMRB_ASSERT 0x156666+#define BD957X_REG_PMIC_INTERNAL_STAT 0x206767+#define BD957X_REG_INT_THERM_STAT 0x236868+#define BD957X_REG_INT_THERM_MASK 0x246969+#define BD957X_REG_INT_OVP_STAT 0x257070+#define BD957X_REG_INT_SCP_STAT 0x267171+#define BD957X_REG_INT_OCP_STAT 0x277272+#define BD957X_REG_INT_OVD_STAT 0x287373+#define BD957X_REG_INT_UVD_STAT 0x297474+#define BD957X_REG_INT_UVP_STAT 0x2a7575+#define BD957X_REG_INT_SYS_STAT 0x2b7676+#define BD957X_REG_INT_SYS_MASK 0x2c7777+#define BD957X_REG_INT_MAIN_STAT 0x307878+#define BD957X_REG_INT_MAIN_MASK 0x317979+8080+#define UVD_IRQ_VALID_MASK 0x6F8181+#define OVD_IRQ_VALID_MASK 0x2F8282+8383+#define BD957X_MASK_INT_MAIN_THERM BIT(0)8484+#define BD957X_MASK_INT_MAIN_OVP BIT(1)8585+#define BD957X_MASK_INT_MAIN_SCP BIT(2)8686+#define BD957X_MASK_INT_MAIN_OCP BIT(3)8787+#define BD957X_MASK_INT_MAIN_OVD BIT(4)8888+#define BD957X_MASK_INT_MAIN_UVD BIT(5)8989+#define BD957X_MASK_INT_MAIN_UVP BIT(6)9090+#define BD957X_MASK_INT_MAIN_SYS BIT(7)9191+#define BD957X_MASK_INT_ALL 0xff9292+9393+#define BD957X_REG_WDT_CONF 0x169494+9595+#define BD957X_REG_POW_TRIGGER1 0x419696+#define BD957X_REG_POW_TRIGGER2 0x429797+#define BD957X_REG_POW_TRIGGER3 0x439898+#define BD957X_REG_POW_TRIGGER4 0x449999+#define BD957X_REG_POW_TRIGGERL1 0x45100100+#define BD957X_REG_POW_TRIGGERS1 0x46101101+102102+#define BD957X_REGULATOR_EN_MASK 0xff103103+#define BD957X_REGULATOR_DIS_VAL 0xff104104+105105+#define BD957X_VSEL_REG_MASK 0xff106106+107107+#define BD957X_MASK_VOUT1_TUNE 0x87108108+#define BD957X_MASK_VOUT2_TUNE 0x87109109+#define BD957X_MASK_VOUT3_TUNE 0x1f110110+#define BD957X_MASK_VOUT4_TUNE 0x1f111111+#define BD957X_MASK_VOUTL1_TUNE 0x87112112+113113+#define BD957X_REG_VOUT1_TUNE 0x50114114+#define BD957X_REG_VOUT2_TUNE 0x53115115+#define BD957X_REG_VOUT3_TUNE 0x56116116+#define BD957X_REG_VOUT4_TUNE 0x59117117+#define BD957X_REG_VOUTL1_TUNE 0x5c118118+119119+#define BD9576_REG_VOUT1_OVD 0x51120120+#define BD9576_REG_VOUT1_UVD 0x52121121+#define BD9576_REG_VOUT2_OVD 0x54122122+#define BD9576_REG_VOUT2_UVD 0x55123123+#define BD9576_REG_VOUT3_OVD 0x57124124+#define BD9576_REG_VOUT3_UVD 0x58125125+#define BD9576_REG_VOUT4_OVD 0x5a126126+#define BD9576_REG_VOUT4_UVD 0x5b127127+#define BD9576_REG_VOUTL1_OVD 0x5d128128+#define BD9576_REG_VOUTL1_UVD 0x5e129129+130130+#define BD9576_MASK_XVD 0x7f131131+132132+#define BD9576_REG_VOUT1S_OCW 0x5f133133+#define BD9576_REG_VOUT1S_OCP 0x60134134+135135+#define BD9576_MASK_VOUT1S_OCW 0x3f136136+#define BD9576_MASK_VOUT1S_OCP 0x3f137137+138138+#define BD957X_MAX_REGISTER 0x61139139+140140+#endif