···11+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause22+%YAML 1.233+---44+$id: http://devicetree.org/schemas/regulator/rohm,bd96801-regulator.yaml#55+$schema: http://devicetree.org/meta-schemas/core.yaml#66+77+title: ROHM BD96801 Power Management Integrated Circuit regulators88+99+maintainers:1010+ - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>1111+1212+description:1313+ This module is part of the ROHM BD96801 MFD device. For more details1414+ see Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml.1515+1616+ The regulator controller is represented as a sub-node of the PMIC node1717+ on the device tree.1818+1919+ Regulator nodes should be named to buck_<number> and ldo_<number>.2020+ The valid names for BD96801 regulator nodes are2121+ buck1, buck2, buck3, buck4, ldo5, ldo6, ldo72222+2323+patternProperties:2424+ "^ldo[5-7]$":2525+ type: object2626+ description:2727+ Properties for single LDO regulator.2828+ $ref: regulator.yaml#2929+3030+ properties:3131+ rohm,initial-voltage-microvolt:3232+ description:3333+ Initial voltage for regulator. Voltage can be tuned +/-150 mV from3434+ this value. NOTE, This can be modified via I2C only when PMIC is in3535+ STBY state.3636+ minimum: 3000003737+ maximum: 33000003838+3939+ unevaluatedProperties: false4040+4141+ "^buck[1-4]$":4242+ type: object4343+ description:4444+ Properties for single BUCK regulator.4545+ $ref: regulator.yaml#4646+4747+ properties:4848+ rohm,initial-voltage-microvolt:4949+ description:5050+ Initial voltage for regulator. Voltage can be tuned +/-150 mV from5151+ this value. NOTE, This can be modified via I2C only when PMIC is in5252+ STBY state.5353+ minimum: 5000005454+ maximum: 33000005555+5656+ rohm,keep-on-stby:5757+ description:5858+ Keep the regulator powered when PMIC transitions to STBY state.5959+ type: boolean6060+6161+ unevaluatedProperties: false6262+6363+additionalProperties: false
···21012101 BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily21022102 designed to be used to power R-Car series processors.2103210321042104+config MFD_ROHM_BD9680121052105+ tristate "ROHM BD96801 Power Management IC"21062106+ depends on I2C=y21072107+ depends on OF21082108+ select REGMAP_I2C21092109+ select REGMAP_IRQ21102110+ select MFD_CORE21112111+ help21122112+ Select this option to get support for the ROHM BD96801 Power21132113+ Management IC. The ROHM BD96801 is a highly scalable Power Management21142114+ IC for industrial and automotive use. The BD96801 can be used as a21152115+ master PMIC in a chained PMIC solution with suitable companion PMICs.21162116+21042117config MFD_STM32_LPTIMER21052118 tristate "Support for STM32 Low-Power Timer"21062119 depends on (ARCH_STM32 && OF) || COMPILE_TEST
···11+// SPDX-License-Identifier: GPL-2.0-or-later22+/*33+ * Copyright (C) 2024 ROHM Semiconductors44+ *55+ * ROHM BD96801 PMIC driver66+ *77+ * This version of the "BD86801 scalable PMIC"'s driver supports only very88+ * basic set of the PMIC features. Most notably, there is no support for99+ * the ERRB interrupt and the configurations which should be done when the1010+ * PMIC is in STBY mode.1111+ *1212+ * Supporting the ERRB interrupt would require dropping the regmap-IRQ1313+ * usage or working around (or accepting a presense of) a naming conflict1414+ * in debugFS IRQs.1515+ *1616+ * Being able to reliably do the configurations like changing the1717+ * regulator safety limits (like limits for the over/under -voltages, over1818+ * current, thermal protection) would require the configuring driver to be1919+ * synchronized with entity causing the PMIC state transitions. Eg, one2020+ * should be able to ensure the PMIC is in STBY state when the2121+ * configurations are applied to the hardware. How and when the PMIC state2222+ * transitions are to be done is likely to be very system specific, as will2323+ * be the need to configure these safety limits. Hence it's not simple to2424+ * come up with a generic solution.2525+ *2626+ * Users who require the ERRB handling and STBY state configurations can2727+ * have a look at the original RFC:2828+ * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/2929+ * which implements a workaround to debugFS naming conflict and some of3030+ * the safety limit configurations - but leaves the state change handling3131+ * and synchronization to be implemented.3232+ *3333+ * It would be great to hear (and receive a patch!) if you implement the3434+ * STBY configuration support or a proper fix to the debugFS naming3535+ * conflict in your downstream driver ;)3636+ */3737+3838+#include <linux/i2c.h>3939+#include <linux/interrupt.h>4040+#include <linux/mfd/core.h>4141+#include <linux/module.h>4242+#include <linux/property.h>4343+#include <linux/regmap.h>4444+#include <linux/types.h>4545+4646+#include <linux/mfd/rohm-bd96801.h>4747+#include <linux/mfd/rohm-generic.h>4848+4949+static const struct resource regulator_intb_irqs[] = {5050+ DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"),5151+5252+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "bd96801-buck1-overcurr-h"),5353+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPL_STAT, "bd96801-buck1-overcurr-l"),5454+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPN_STAT, "bd96801-buck1-overcurr-n"),5555+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVD_STAT, "bd96801-buck1-overvolt"),5656+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVD_STAT, "bd96801-buck1-undervolt"),5757+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_TW_CH_STAT, "bd96801-buck1-thermal"),5858+5959+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPH_STAT, "bd96801-buck2-overcurr-h"),6060+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPL_STAT, "bd96801-buck2-overcurr-l"),6161+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPN_STAT, "bd96801-buck2-overcurr-n"),6262+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVD_STAT, "bd96801-buck2-overvolt"),6363+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVD_STAT, "bd96801-buck2-undervolt"),6464+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_TW_CH_STAT, "bd96801-buck2-thermal"),6565+6666+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPH_STAT, "bd96801-buck3-overcurr-h"),6767+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPL_STAT, "bd96801-buck3-overcurr-l"),6868+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPN_STAT, "bd96801-buck3-overcurr-n"),6969+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVD_STAT, "bd96801-buck3-overvolt"),7070+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVD_STAT, "bd96801-buck3-undervolt"),7171+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_TW_CH_STAT, "bd96801-buck3-thermal"),7272+7373+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPH_STAT, "bd96801-buck4-overcurr-h"),7474+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPL_STAT, "bd96801-buck4-overcurr-l"),7575+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPN_STAT, "bd96801-buck4-overcurr-n"),7676+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVD_STAT, "bd96801-buck4-overvolt"),7777+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVD_STAT, "bd96801-buck4-undervolt"),7878+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_TW_CH_STAT, "bd96801-buck4-thermal"),7979+8080+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OCPH_STAT, "bd96801-ldo5-overcurr"),8181+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVD_STAT, "bd96801-ldo5-overvolt"),8282+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVD_STAT, "bd96801-ldo5-undervolt"),8383+8484+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OCPH_STAT, "bd96801-ldo6-overcurr"),8585+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVD_STAT, "bd96801-ldo6-overvolt"),8686+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVD_STAT, "bd96801-ldo6-undervolt"),8787+8888+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OCPH_STAT, "bd96801-ldo7-overcurr"),8989+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVD_STAT, "bd96801-ldo7-overvolt"),9090+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "bd96801-ldo7-undervolt"),9191+};9292+9393+static const struct resource wdg_intb_irqs[] = {9494+ DEFINE_RES_IRQ_NAMED(BD96801_WDT_ERR_STAT, "bd96801-wdg"),9595+};9696+9797+static struct mfd_cell bd96801_cells[] = {9898+ {9999+ .name = "bd96801-wdt",100100+ .resources = wdg_intb_irqs,101101+ .num_resources = ARRAY_SIZE(wdg_intb_irqs),102102+ }, {103103+ .name = "bd96801-regulator",104104+ .resources = regulator_intb_irqs,105105+ .num_resources = ARRAY_SIZE(regulator_intb_irqs),106106+ },107107+};108108+109109+static const struct regmap_range bd96801_volatile_ranges[] = {110110+ /* Status registers */111111+ regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT),112112+ regmap_reg_range(BD96801_REG_WD_ASK, BD96801_REG_WD_ASK),113113+ regmap_reg_range(BD96801_REG_WD_STATUS, BD96801_REG_WD_STATUS),114114+ regmap_reg_range(BD96801_REG_PMIC_STATE, BD96801_REG_INT_LDO7_INTB),115115+ /* Registers which do not update value unless PMIC is in STBY */116116+ regmap_reg_range(BD96801_REG_SSCG_CTRL, BD96801_REG_SHD_INTB),117117+ regmap_reg_range(BD96801_REG_BUCK_OVP, BD96801_REG_BOOT_OVERTIME),118118+ /*119119+ * LDO control registers have single bit (LDO MODE) which does not120120+ * change when we write it unless PMIC is in STBY. It's safer to not121121+ * cache it.122122+ */123123+ regmap_reg_range(BD96801_LDO5_VOL_LVL_REG, BD96801_LDO7_VOL_LVL_REG),124124+};125125+126126+static const struct regmap_access_table volatile_regs = {127127+ .yes_ranges = bd96801_volatile_ranges,128128+ .n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges),129129+};130130+131131+static const struct regmap_irq bd96801_intb_irqs[] = {132132+ /* STATUS SYSTEM INTB */133133+ REGMAP_IRQ_REG(BD96801_TW_STAT, 0, BD96801_TW_STAT_MASK),134134+ REGMAP_IRQ_REG(BD96801_WDT_ERR_STAT, 0, BD96801_WDT_ERR_STAT_MASK),135135+ REGMAP_IRQ_REG(BD96801_I2C_ERR_STAT, 0, BD96801_I2C_ERR_STAT_MASK),136136+ REGMAP_IRQ_REG(BD96801_CHIP_IF_ERR_STAT, 0, BD96801_CHIP_IF_ERR_STAT_MASK),137137+ /* STATUS BUCK1 INTB */138138+ REGMAP_IRQ_REG(BD96801_BUCK1_OCPH_STAT, 1, BD96801_BUCK_OCPH_STAT_MASK),139139+ REGMAP_IRQ_REG(BD96801_BUCK1_OCPL_STAT, 1, BD96801_BUCK_OCPL_STAT_MASK),140140+ REGMAP_IRQ_REG(BD96801_BUCK1_OCPN_STAT, 1, BD96801_BUCK_OCPN_STAT_MASK),141141+ REGMAP_IRQ_REG(BD96801_BUCK1_OVD_STAT, 1, BD96801_BUCK_OVD_STAT_MASK),142142+ REGMAP_IRQ_REG(BD96801_BUCK1_UVD_STAT, 1, BD96801_BUCK_UVD_STAT_MASK),143143+ REGMAP_IRQ_REG(BD96801_BUCK1_TW_CH_STAT, 1, BD96801_BUCK_TW_CH_STAT_MASK),144144+ /* BUCK 2 INTB */145145+ REGMAP_IRQ_REG(BD96801_BUCK2_OCPH_STAT, 2, BD96801_BUCK_OCPH_STAT_MASK),146146+ REGMAP_IRQ_REG(BD96801_BUCK2_OCPL_STAT, 2, BD96801_BUCK_OCPL_STAT_MASK),147147+ REGMAP_IRQ_REG(BD96801_BUCK2_OCPN_STAT, 2, BD96801_BUCK_OCPN_STAT_MASK),148148+ REGMAP_IRQ_REG(BD96801_BUCK2_OVD_STAT, 2, BD96801_BUCK_OVD_STAT_MASK),149149+ REGMAP_IRQ_REG(BD96801_BUCK2_UVD_STAT, 2, BD96801_BUCK_UVD_STAT_MASK),150150+ REGMAP_IRQ_REG(BD96801_BUCK2_TW_CH_STAT, 2, BD96801_BUCK_TW_CH_STAT_MASK),151151+ /* BUCK 3 INTB */152152+ REGMAP_IRQ_REG(BD96801_BUCK3_OCPH_STAT, 3, BD96801_BUCK_OCPH_STAT_MASK),153153+ REGMAP_IRQ_REG(BD96801_BUCK3_OCPL_STAT, 3, BD96801_BUCK_OCPL_STAT_MASK),154154+ REGMAP_IRQ_REG(BD96801_BUCK3_OCPN_STAT, 3, BD96801_BUCK_OCPN_STAT_MASK),155155+ REGMAP_IRQ_REG(BD96801_BUCK3_OVD_STAT, 3, BD96801_BUCK_OVD_STAT_MASK),156156+ REGMAP_IRQ_REG(BD96801_BUCK3_UVD_STAT, 3, BD96801_BUCK_UVD_STAT_MASK),157157+ REGMAP_IRQ_REG(BD96801_BUCK3_TW_CH_STAT, 3, BD96801_BUCK_TW_CH_STAT_MASK),158158+ /* BUCK 4 INTB */159159+ REGMAP_IRQ_REG(BD96801_BUCK4_OCPH_STAT, 4, BD96801_BUCK_OCPH_STAT_MASK),160160+ REGMAP_IRQ_REG(BD96801_BUCK4_OCPL_STAT, 4, BD96801_BUCK_OCPL_STAT_MASK),161161+ REGMAP_IRQ_REG(BD96801_BUCK4_OCPN_STAT, 4, BD96801_BUCK_OCPN_STAT_MASK),162162+ REGMAP_IRQ_REG(BD96801_BUCK4_OVD_STAT, 4, BD96801_BUCK_OVD_STAT_MASK),163163+ REGMAP_IRQ_REG(BD96801_BUCK4_UVD_STAT, 4, BD96801_BUCK_UVD_STAT_MASK),164164+ REGMAP_IRQ_REG(BD96801_BUCK4_TW_CH_STAT, 4, BD96801_BUCK_TW_CH_STAT_MASK),165165+ /* LDO5 INTB */166166+ REGMAP_IRQ_REG(BD96801_LDO5_OCPH_STAT, 5, BD96801_LDO_OCPH_STAT_MASK),167167+ REGMAP_IRQ_REG(BD96801_LDO5_OVD_STAT, 5, BD96801_LDO_OVD_STAT_MASK),168168+ REGMAP_IRQ_REG(BD96801_LDO5_UVD_STAT, 5, BD96801_LDO_UVD_STAT_MASK),169169+ /* LDO6 INTB */170170+ REGMAP_IRQ_REG(BD96801_LDO6_OCPH_STAT, 6, BD96801_LDO_OCPH_STAT_MASK),171171+ REGMAP_IRQ_REG(BD96801_LDO6_OVD_STAT, 6, BD96801_LDO_OVD_STAT_MASK),172172+ REGMAP_IRQ_REG(BD96801_LDO6_UVD_STAT, 6, BD96801_LDO_UVD_STAT_MASK),173173+ /* LDO7 INTB */174174+ REGMAP_IRQ_REG(BD96801_LDO7_OCPH_STAT, 7, BD96801_LDO_OCPH_STAT_MASK),175175+ REGMAP_IRQ_REG(BD96801_LDO7_OVD_STAT, 7, BD96801_LDO_OVD_STAT_MASK),176176+ REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK),177177+};178178+179179+static struct regmap_irq_chip bd96801_irq_chip_intb = {180180+ .name = "bd96801-irq-intb",181181+ .main_status = BD96801_REG_INT_MAIN,182182+ .num_main_regs = 1,183183+ .irqs = &bd96801_intb_irqs[0],184184+ .num_irqs = ARRAY_SIZE(bd96801_intb_irqs),185185+ .status_base = BD96801_REG_INT_SYS_INTB,186186+ .mask_base = BD96801_REG_MASK_SYS_INTB,187187+ .ack_base = BD96801_REG_INT_SYS_INTB,188188+ .init_ack_masked = true,189189+ .num_regs = 8,190190+ .irq_reg_stride = 1,191191+};192192+193193+static const struct regmap_config bd96801_regmap_config = {194194+ .reg_bits = 8,195195+ .val_bits = 8,196196+ .volatile_table = &volatile_regs,197197+ .cache_type = REGCACHE_RBTREE,198198+};199199+200200+static int bd96801_i2c_probe(struct i2c_client *i2c)201201+{202202+ struct regmap_irq_chip_data *intb_irq_data;203203+ const struct fwnode_handle *fwnode;204204+ struct irq_domain *intb_domain;205205+ struct regmap *regmap;206206+ int ret, intb_irq;207207+208208+ fwnode = dev_fwnode(&i2c->dev);209209+ if (!fwnode)210210+ return dev_err_probe(&i2c->dev, -EINVAL, "Failed to find fwnode\n");211211+212212+ intb_irq = fwnode_irq_get_byname(fwnode, "intb");213213+ if (intb_irq < 0)214214+ return dev_err_probe(&i2c->dev, intb_irq, "INTB IRQ not configured\n");215215+216216+ regmap = devm_regmap_init_i2c(i2c, &bd96801_regmap_config);217217+ if (IS_ERR(regmap))218218+ return dev_err_probe(&i2c->dev, PTR_ERR(regmap),219219+ "Regmap initialization failed\n");220220+221221+ ret = regmap_write(regmap, BD96801_LOCK_REG, BD96801_UNLOCK);222222+ if (ret)223223+ return dev_err_probe(&i2c->dev, ret, "Failed to unlock PMIC\n");224224+225225+ ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, intb_irq,226226+ IRQF_ONESHOT, 0, &bd96801_irq_chip_intb,227227+ &intb_irq_data);228228+ if (ret)229229+ return dev_err_probe(&i2c->dev, ret, "Failed to add INTB IRQ chip\n");230230+231231+ intb_domain = regmap_irq_get_domain(intb_irq_data);232232+233233+ ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,234234+ bd96801_cells,235235+ ARRAY_SIZE(bd96801_cells), NULL, 0,236236+ intb_domain);237237+ if (ret)238238+ dev_err(&i2c->dev, "Failed to create subdevices\n");239239+240240+ return ret;241241+}242242+243243+static const struct of_device_id bd96801_of_match[] = {244244+ { .compatible = "rohm,bd96801", },245245+ { }246246+};247247+MODULE_DEVICE_TABLE(of, bd96801_of_match);248248+249249+static struct i2c_driver bd96801_i2c_driver = {250250+ .driver = {251251+ .name = "rohm-bd96801",252252+ .of_match_table = bd96801_of_match,253253+ },254254+ .probe = bd96801_i2c_probe,255255+};256256+257257+static int __init bd96801_i2c_init(void)258258+{259259+ return i2c_add_driver(&bd96801_i2c_driver);260260+}261261+262262+/* Initialise early so consumer devices can complete system boot */263263+subsys_initcall(bd96801_i2c_init);264264+265265+static void __exit bd96801_i2c_exit(void)266266+{267267+ i2c_del_driver(&bd96801_i2c_driver);268268+}269269+module_exit(bd96801_i2c_exit);270270+271271+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");272272+MODULE_DESCRIPTION("ROHM BD96801 Power Management IC driver");273273+MODULE_LICENSE("GPL");
+12
drivers/regulator/Kconfig
···274274 This driver can also be built as a module. If so, the module275275 will be called bd9576-regulator.276276277277+config REGULATOR_BD96801278278+ tristate "ROHM BD96801 Power Regulator"279279+ depends on MFD_ROHM_BD96801280280+ select REGULATOR_ROHM281281+ help282282+ This driver supports voltage regulators on ROHM BD96801 PMIC.283283+ This will enable support for the software controllable buck284284+ and LDO regulators.285285+286286+ This driver can also be built as a module. If so, the module287287+ will be called bd96801-regulator.288288+277289config REGULATOR_CPCAP278290 tristate "Motorola CPCAP regulator"279291 depends on MFD_CPCAP
···11+// SPDX-License-Identifier: GPL-2.022+// Copyright (C) 2024 ROHM Semiconductors33+// bd96801-regulator.c ROHM BD96801 regulator driver44+55+/*66+ * This version of the "BD86801 scalable PMIC"'s driver supports only very77+ * basic set of the PMIC features. Most notably, there is no support for88+ * the ERRB interrupt and the configurations which should be done when the99+ * PMIC is in STBY mode.1010+ *1111+ * Supporting the ERRB interrupt would require dropping the regmap-IRQ1212+ * usage or working around (or accepting a presense of) a naming conflict1313+ * in debugFS IRQs.1414+ *1515+ * Being able to reliably do the configurations like changing the1616+ * regulator safety limits (like limits for the over/under -voltages, over1717+ * current, thermal protection) would require the configuring driver to be1818+ * synchronized with entity causing the PMIC state transitions. Eg, one1919+ * should be able to ensure the PMIC is in STBY state when the2020+ * configurations are applied to the hardware. How and when the PMIC state2121+ * transitions are to be done is likely to be very system specific, as will2222+ * be the need to configure these safety limits. Hence it's not simple to2323+ * come up with a generic solution.2424+ *2525+ * Users who require the ERRB handling and STBY state configurations can2626+ * have a look at the original RFC:2727+ * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/2828+ * which implements a workaround to debugFS naming conflict and some of2929+ * the safety limit configurations - but leaves the state change handling3030+ * and synchronization to be implemented.3131+ *3232+ * It would be great to hear (and receive a patch!) if you implement the3333+ * STBY configuration support or a proper fix to the debugFS naming3434+ * conflict in your downstream driver ;)3535+ */3636+3737+#include <linux/delay.h>3838+#include <linux/err.h>3939+#include <linux/interrupt.h>4040+#include <linux/kernel.h>4141+#include <linux/linear_range.h>4242+#include <linux/mfd/rohm-generic.h>4343+#include <linux/mfd/rohm-bd96801.h>4444+#include <linux/module.h>4545+#include <linux/of.h>4646+#include <linux/platform_device.h>4747+#include <linux/regmap.h>4848+#include <linux/regulator/coupler.h>4949+#include <linux/regulator/driver.h>5050+#include <linux/regulator/machine.h>5151+#include <linux/regulator/of_regulator.h>5252+#include <linux/slab.h>5353+#include <linux/timer.h>5454+5555+enum {5656+ BD96801_BUCK1,5757+ BD96801_BUCK2,5858+ BD96801_BUCK3,5959+ BD96801_BUCK4,6060+ BD96801_LDO5,6161+ BD96801_LDO6,6262+ BD96801_LDO7,6363+ BD96801_REGULATOR_AMOUNT,6464+};6565+6666+enum {6767+ BD96801_PROT_OVP,6868+ BD96801_PROT_UVP,6969+ BD96801_PROT_OCP,7070+ BD96801_PROT_TEMP,7171+ BD96801_NUM_PROT,7272+};7373+7474+#define BD96801_ALWAYS_ON_REG 0x3c7575+#define BD96801_REG_ENABLE 0x0b7676+#define BD96801_BUCK1_EN_MASK BIT(0)7777+#define BD96801_BUCK2_EN_MASK BIT(1)7878+#define BD96801_BUCK3_EN_MASK BIT(2)7979+#define BD96801_BUCK4_EN_MASK BIT(3)8080+#define BD96801_LDO5_EN_MASK BIT(4)8181+#define BD96801_LDO6_EN_MASK BIT(5)8282+#define BD96801_LDO7_EN_MASK BIT(6)8383+8484+#define BD96801_BUCK1_VSEL_REG 0x288585+#define BD96801_BUCK2_VSEL_REG 0x298686+#define BD96801_BUCK3_VSEL_REG 0x2a8787+#define BD96801_BUCK4_VSEL_REG 0x2b8888+#define BD96801_LDO5_VSEL_REG 0x258989+#define BD96801_LDO6_VSEL_REG 0x269090+#define BD96801_LDO7_VSEL_REG 0x279191+#define BD96801_BUCK_VSEL_MASK 0x1F9292+#define BD96801_LDO_VSEL_MASK 0xff9393+9494+#define BD96801_MASK_RAMP_DELAY 0xc09595+#define BD96801_INT_VOUT_BASE_REG 0x219696+#define BD96801_BUCK_INT_VOUT_MASK 0xff9797+9898+#define BD96801_BUCK_VOLTS 2569999+#define BD96801_LDO_VOLTS 256100100+101101+#define BD96801_OVP_MASK 0x03102102+#define BD96801_MASK_BUCK1_OVP_SHIFT 0x00103103+#define BD96801_MASK_BUCK2_OVP_SHIFT 0x02104104+#define BD96801_MASK_BUCK3_OVP_SHIFT 0x04105105+#define BD96801_MASK_BUCK4_OVP_SHIFT 0x06106106+#define BD96801_MASK_LDO5_OVP_SHIFT 0x00107107+#define BD96801_MASK_LDO6_OVP_SHIFT 0x02108108+#define BD96801_MASK_LDO7_OVP_SHIFT 0x04109109+110110+#define BD96801_PROT_LIMIT_OCP_MIN 0x00111111+#define BD96801_PROT_LIMIT_LOW 0x01112112+#define BD96801_PROT_LIMIT_MID 0x02113113+#define BD96801_PROT_LIMIT_HI 0x03114114+115115+#define BD96801_REG_BUCK1_OCP 0x32116116+#define BD96801_REG_BUCK2_OCP 0x32117117+#define BD96801_REG_BUCK3_OCP 0x33118118+#define BD96801_REG_BUCK4_OCP 0x33119119+120120+#define BD96801_MASK_BUCK1_OCP_SHIFT 0x00121121+#define BD96801_MASK_BUCK2_OCP_SHIFT 0x04122122+#define BD96801_MASK_BUCK3_OCP_SHIFT 0x00123123+#define BD96801_MASK_BUCK4_OCP_SHIFT 0x04124124+125125+#define BD96801_REG_LDO5_OCP 0x34126126+#define BD96801_REG_LDO6_OCP 0x34127127+#define BD96801_REG_LDO7_OCP 0x34128128+129129+#define BD96801_MASK_LDO5_OCP_SHIFT 0x00130130+#define BD96801_MASK_LDO6_OCP_SHIFT 0x02131131+#define BD96801_MASK_LDO7_OCP_SHIFT 0x04132132+133133+#define BD96801_MASK_SHD_INTB BIT(7)134134+#define BD96801_INTB_FATAL BIT(7)135135+136136+#define BD96801_NUM_REGULATORS 7137137+#define BD96801_NUM_LDOS 4138138+139139+/*140140+ * Ramp rates for bucks are controlled by bits [7:6] as follows:141141+ * 00 => 1 mV/uS142142+ * 01 => 5 mV/uS143143+ * 10 => 10 mV/uS144144+ * 11 => 20 mV/uS145145+ */146146+static const unsigned int buck_ramp_table[] = { 1000, 5000, 10000, 20000 };147147+148148+/*149149+ * This is a voltage range that get's appended to selected150150+ * bd96801_buck_init_volts value. The range from 0x0 to 0xF is actually151151+ * bd96801_buck_init_volts + 0 ... bd96801_buck_init_volts + 150mV152152+ * and the range from 0x10 to 0x1f is bd96801_buck_init_volts - 150mV ...153153+ * bd96801_buck_init_volts - 0. But as the members of linear_range154154+ * are all unsigned I will apply offset of -150 mV to value in155155+ * linear_range - which should increase these ranges with156156+ * 150 mV getting all the values to >= 0.157157+ */158158+static const struct linear_range bd96801_tune_volts[] = {159159+ REGULATOR_LINEAR_RANGE(150000, 0x00, 0xF, 10000),160160+ REGULATOR_LINEAR_RANGE(0, 0x10, 0x1F, 10000),161161+};162162+163163+static const struct linear_range bd96801_buck_init_volts[] = {164164+ REGULATOR_LINEAR_RANGE(500000 - 150000, 0x00, 0xc8, 5000),165165+ REGULATOR_LINEAR_RANGE(1550000 - 150000, 0xc9, 0xec, 50000),166166+ REGULATOR_LINEAR_RANGE(3300000 - 150000, 0xed, 0xff, 0),167167+};168168+169169+static const struct linear_range bd96801_ldo_int_volts[] = {170170+ REGULATOR_LINEAR_RANGE(300000, 0x00, 0x78, 25000),171171+ REGULATOR_LINEAR_RANGE(3300000, 0x79, 0xff, 0),172172+};173173+174174+#define BD96801_LDO_SD_VOLT_MASK 0x1175175+#define BD96801_LDO_MODE_MASK 0x6176176+#define BD96801_LDO_MODE_INT 0x0177177+#define BD96801_LDO_MODE_SD 0x2178178+#define BD96801_LDO_MODE_DDR 0x4179179+180180+static int ldo_ddr_volt_table[] = {500000, 300000};181181+static int ldo_sd_volt_table[] = {3300000, 1800000};182182+183183+/* Constant IRQ initialization data (templates) */184184+struct bd96801_irqinfo {185185+ int type;186186+ struct regulator_irq_desc irq_desc;187187+ int err_cfg;188188+ int wrn_cfg;189189+ const char *irq_name;190190+};191191+192192+#define BD96801_IRQINFO(_type, _name, _irqoff_ms, _irqname) \193193+{ \194194+ .type = (_type), \195195+ .err_cfg = -1, \196196+ .wrn_cfg = -1, \197197+ .irq_name = (_irqname), \198198+ .irq_desc = { \199199+ .name = (_name), \200200+ .irq_off_ms = (_irqoff_ms), \201201+ .map_event = regulator_irq_map_event_simple, \202202+ }, \203203+}204204+205205+static const struct bd96801_irqinfo buck1_irqinfo[] = {206206+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-h", 500,207207+ "bd96801-buck1-overcurr-h"),208208+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-l", 500,209209+ "bd96801-buck1-overcurr-l"),210210+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-n", 500,211211+ "bd96801-buck1-overcurr-n"),212212+ BD96801_IRQINFO(BD96801_PROT_OVP, "buck1-over-voltage", 500,213213+ "bd96801-buck1-overvolt"),214214+ BD96801_IRQINFO(BD96801_PROT_UVP, "buck1-under-voltage", 500,215215+ "bd96801-buck1-undervolt"),216216+ BD96801_IRQINFO(BD96801_PROT_TEMP, "buck1-over-temp", 500,217217+ "bd96801-buck1-thermal")218218+};219219+220220+static const struct bd96801_irqinfo buck2_irqinfo[] = {221221+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-h", 500,222222+ "bd96801-buck2-overcurr-h"),223223+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-l", 500,224224+ "bd96801-buck2-overcurr-l"),225225+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-n", 500,226226+ "bd96801-buck2-overcurr-n"),227227+ BD96801_IRQINFO(BD96801_PROT_OVP, "buck2-over-voltage", 500,228228+ "bd96801-buck2-overvolt"),229229+ BD96801_IRQINFO(BD96801_PROT_UVP, "buck2-under-voltage", 500,230230+ "bd96801-buck2-undervolt"),231231+ BD96801_IRQINFO(BD96801_PROT_TEMP, "buck2-over-temp", 500,232232+ "bd96801-buck2-thermal")233233+};234234+235235+static const struct bd96801_irqinfo buck3_irqinfo[] = {236236+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-h", 500,237237+ "bd96801-buck3-overcurr-h"),238238+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-l", 500,239239+ "bd96801-buck3-overcurr-l"),240240+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-n", 500,241241+ "bd96801-buck3-overcurr-n"),242242+ BD96801_IRQINFO(BD96801_PROT_OVP, "buck3-over-voltage", 500,243243+ "bd96801-buck3-overvolt"),244244+ BD96801_IRQINFO(BD96801_PROT_UVP, "buck3-under-voltage", 500,245245+ "bd96801-buck3-undervolt"),246246+ BD96801_IRQINFO(BD96801_PROT_TEMP, "buck3-over-temp", 500,247247+ "bd96801-buck3-thermal")248248+};249249+250250+static const struct bd96801_irqinfo buck4_irqinfo[] = {251251+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-h", 500,252252+ "bd96801-buck4-overcurr-h"),253253+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-l", 500,254254+ "bd96801-buck4-overcurr-l"),255255+ BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-n", 500,256256+ "bd96801-buck4-overcurr-n"),257257+ BD96801_IRQINFO(BD96801_PROT_OVP, "buck4-over-voltage", 500,258258+ "bd96801-buck4-overvolt"),259259+ BD96801_IRQINFO(BD96801_PROT_UVP, "buck4-under-voltage", 500,260260+ "bd96801-buck4-undervolt"),261261+ BD96801_IRQINFO(BD96801_PROT_TEMP, "buck4-over-temp", 500,262262+ "bd96801-buck4-thermal")263263+};264264+265265+static const struct bd96801_irqinfo ldo5_irqinfo[] = {266266+ BD96801_IRQINFO(BD96801_PROT_OCP, "ldo5-overcurr", 500,267267+ "bd96801-ldo5-overcurr"),268268+ BD96801_IRQINFO(BD96801_PROT_OVP, "ldo5-over-voltage", 500,269269+ "bd96801-ldo5-overvolt"),270270+ BD96801_IRQINFO(BD96801_PROT_UVP, "ldo5-under-voltage", 500,271271+ "bd96801-ldo5-undervolt"),272272+};273273+274274+static const struct bd96801_irqinfo ldo6_irqinfo[] = {275275+ BD96801_IRQINFO(BD96801_PROT_OCP, "ldo6-overcurr", 500,276276+ "bd96801-ldo6-overcurr"),277277+ BD96801_IRQINFO(BD96801_PROT_OVP, "ldo6-over-voltage", 500,278278+ "bd96801-ldo6-overvolt"),279279+ BD96801_IRQINFO(BD96801_PROT_UVP, "ldo6-under-voltage", 500,280280+ "bd96801-ldo6-undervolt"),281281+};282282+283283+static const struct bd96801_irqinfo ldo7_irqinfo[] = {284284+ BD96801_IRQINFO(BD96801_PROT_OCP, "ldo7-overcurr", 500,285285+ "bd96801-ldo7-overcurr"),286286+ BD96801_IRQINFO(BD96801_PROT_OVP, "ldo7-over-voltage", 500,287287+ "bd96801-ldo7-overvolt"),288288+ BD96801_IRQINFO(BD96801_PROT_UVP, "ldo7-under-voltage", 500,289289+ "bd96801-ldo7-undervolt"),290290+};291291+292292+struct bd96801_irq_desc {293293+ struct bd96801_irqinfo *irqinfo;294294+ int num_irqs;295295+};296296+297297+struct bd96801_regulator_data {298298+ struct regulator_desc desc;299299+ const struct linear_range *init_ranges;300300+ int num_ranges;301301+ struct bd96801_irq_desc irq_desc;302302+ int initial_voltage;303303+ int ldo_vol_lvl;304304+ int ldo_errs;305305+};306306+307307+struct bd96801_pmic_data {308308+ struct bd96801_regulator_data regulator_data[BD96801_NUM_REGULATORS];309309+ struct regmap *regmap;310310+ int fatal_ind;311311+};312312+313313+static int ldo_map_notif(int irq, struct regulator_irq_data *rid,314314+ unsigned long *dev_mask)315315+{316316+ int i;317317+318318+ for (i = 0; i < rid->num_states; i++) {319319+ struct bd96801_regulator_data *rdata;320320+ struct regulator_dev *rdev;321321+322322+ rdev = rid->states[i].rdev;323323+ rdata = container_of(rdev->desc, struct bd96801_regulator_data,324324+ desc);325325+ rid->states[i].notifs = regulator_err2notif(rdata->ldo_errs);326326+ rid->states[i].errors = rdata->ldo_errs;327327+ *dev_mask |= BIT(i);328328+ }329329+ return 0;330330+}331331+332332+static int bd96801_list_voltage_lr(struct regulator_dev *rdev,333333+ unsigned int selector)334334+{335335+ int voltage;336336+ struct bd96801_regulator_data *data;337337+338338+ data = container_of(rdev->desc, struct bd96801_regulator_data, desc);339339+340340+ /*341341+ * The BD096801 has voltage setting in two registers. One giving the342342+ * "initial voltage" (can be changed only when regulator is disabled.343343+ * This driver caches the value and sets it only at startup. The other344344+ * register is voltage tuning value which applies -150 mV ... +150 mV345345+ * offset to the voltage.346346+ *347347+ * Note that the cached initial voltage stored in regulator data is348348+ * 'scaled down' by the 150 mV so that all of our tuning values are349349+ * >= 0. This is done because the linear_ranges uses unsigned values.350350+ *351351+ * As a result, we increase the tuning voltage which we get based on352352+ * the selector by the stored initial_voltage.353353+ */354354+ voltage = regulator_list_voltage_linear_range(rdev, selector);355355+ if (voltage < 0)356356+ return voltage;357357+358358+ return voltage + data->initial_voltage;359359+}360360+361361+362362+static const struct regulator_ops bd96801_ldo_table_ops = {363363+ .is_enabled = regulator_is_enabled_regmap,364364+ .list_voltage = regulator_list_voltage_table,365365+ .get_voltage_sel = regulator_get_voltage_sel_regmap,366366+};367367+368368+static const struct regulator_ops bd96801_buck_ops = {369369+ .is_enabled = regulator_is_enabled_regmap,370370+ .list_voltage = bd96801_list_voltage_lr,371371+ .set_voltage_sel = regulator_set_voltage_sel_regmap,372372+ .get_voltage_sel = regulator_get_voltage_sel_regmap,373373+ .set_voltage_time_sel = regulator_set_voltage_time_sel,374374+ .set_ramp_delay = regulator_set_ramp_delay_regmap,375375+};376376+377377+static const struct regulator_ops bd96801_ldo_ops = {378378+ .is_enabled = regulator_is_enabled_regmap,379379+ .list_voltage = regulator_list_voltage_linear_range,380380+ .get_voltage_sel = regulator_get_voltage_sel_regmap,381381+};382382+383383+static int buck_get_initial_voltage(struct regmap *regmap, struct device *dev,384384+ struct bd96801_regulator_data *data)385385+{386386+ int ret = 0, sel, initial_uv;387387+ int reg = BD96801_INT_VOUT_BASE_REG + data->desc.id;388388+389389+ if (data->num_ranges) {390390+ ret = regmap_read(regmap, reg, &sel);391391+ sel &= BD96801_BUCK_INT_VOUT_MASK;392392+393393+ ret = linear_range_get_value_array(data->init_ranges,394394+ data->num_ranges, sel,395395+ &initial_uv);396396+ if (ret)397397+ return ret;398398+399399+ data->initial_voltage = initial_uv;400400+ dev_dbg(dev, "Tune-scaled initial voltage %u\n",401401+ data->initial_voltage);402402+ }403403+404404+ return 0;405405+}406406+407407+static int get_ldo_initial_voltage(struct regmap *regmap,408408+ struct device *dev,409409+ struct bd96801_regulator_data *data)410410+{411411+ int ret;412412+ int cfgreg;413413+414414+ ret = regmap_read(regmap, data->ldo_vol_lvl, &cfgreg);415415+ if (ret)416416+ return ret;417417+418418+ switch (cfgreg & BD96801_LDO_MODE_MASK) {419419+ case BD96801_LDO_MODE_DDR:420420+ data->desc.volt_table = ldo_ddr_volt_table;421421+ data->desc.n_voltages = ARRAY_SIZE(ldo_ddr_volt_table);422422+ break;423423+ case BD96801_LDO_MODE_SD:424424+ data->desc.volt_table = ldo_sd_volt_table;425425+ data->desc.n_voltages = ARRAY_SIZE(ldo_sd_volt_table);426426+ break;427427+ default:428428+ dev_info(dev, "Leaving LDO to normal mode");429429+ return 0;430430+ }431431+432432+ /* SD or DDR mode => override default ops */433433+ data->desc.ops = &bd96801_ldo_table_ops,434434+ data->desc.vsel_mask = 1;435435+ data->desc.vsel_reg = data->ldo_vol_lvl;436436+437437+ return 0;438438+}439439+440440+static int get_initial_voltage(struct device *dev, struct regmap *regmap,441441+ struct bd96801_regulator_data *data)442442+{443443+ /* BUCK */444444+ if (data->desc.id <= BD96801_BUCK4)445445+ return buck_get_initial_voltage(regmap, dev, data);446446+447447+ /* LDO */448448+ return get_ldo_initial_voltage(regmap, dev, data);449449+}450450+451451+static int bd96801_walk_regulator_dt(struct device *dev, struct regmap *regmap,452452+ struct bd96801_regulator_data *data,453453+ int num)454454+{455455+ int i, ret;456456+ struct device_node *np;457457+ struct device_node *nproot = dev->parent->of_node;458458+459459+ nproot = of_get_child_by_name(nproot, "regulators");460460+ if (!nproot) {461461+ dev_err(dev, "failed to find regulators node\n");462462+ return -ENODEV;463463+ }464464+ for_each_child_of_node(nproot, np)465465+ for (i = 0; i < num; i++) {466466+ if (!of_node_name_eq(np, data[i].desc.of_match))467467+ continue;468468+ /*469469+ * If STBY configs are supported, we must pass node470470+ * here to extract the initial voltages from the DT.471471+ * Thus we do the initial voltage getting in this472472+ * loop.473473+ */474474+ ret = get_initial_voltage(dev, regmap, &data[i]);475475+ if (ret) {476476+ dev_err(dev,477477+ "Initializing voltages for %s failed\n",478478+ data[i].desc.name);479479+ of_node_put(np);480480+ of_node_put(nproot);481481+482482+ return ret;483483+ }484484+ if (of_property_read_bool(np, "rohm,keep-on-stby")) {485485+ ret = regmap_set_bits(regmap,486486+ BD96801_ALWAYS_ON_REG,487487+ 1 << data[i].desc.id);488488+ if (ret) {489489+ dev_err(dev,490490+ "failed to set %s on-at-stby\n",491491+ data[i].desc.name);492492+ of_node_put(np);493493+ of_node_put(nproot);494494+495495+ return ret;496496+ }497497+ }498498+ }499499+ of_node_put(nproot);500500+501501+ return 0;502502+}503503+504504+/*505505+ * Template for regulator data. Probe will allocate dynamic / driver instance506506+ * struct so we should be on a safe side even if there were multiple PMICs to507507+ * control. Note that there is a plan to allow multiple PMICs to be used so508508+ * systems can scale better. I am however still slightly unsure how the509509+ * multi-PMIC case will be handled. I don't know if the processor will have I2C510510+ * acces to all of the PMICs or only the first one. I'd guess there will be511511+ * access provided to all PMICs for voltage scaling - but the errors will only512512+ * be informed via the master PMIC. Eg, we should prepare to support multiple513513+ * driver instances - either with or without the IRQs... Well, let's first514514+ * just support the simple and clear single-PMIC setup and ponder the multi PMIC515515+ * case later. What we can easly do for preparing is to not use static global516516+ * data for regulators though.517517+ */518518+static const struct bd96801_pmic_data bd96801_data = {519519+ .regulator_data = {520520+ {521521+ .desc = {522522+ .name = "buck1",523523+ .of_match = of_match_ptr("buck1"),524524+ .regulators_node = of_match_ptr("regulators"),525525+ .id = BD96801_BUCK1,526526+ .ops = &bd96801_buck_ops,527527+ .type = REGULATOR_VOLTAGE,528528+ .linear_ranges = bd96801_tune_volts,529529+ .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts),530530+ .n_voltages = BD96801_BUCK_VOLTS,531531+ .enable_reg = BD96801_REG_ENABLE,532532+ .enable_mask = BD96801_BUCK1_EN_MASK,533533+ .enable_is_inverted = true,534534+ .vsel_reg = BD96801_BUCK1_VSEL_REG,535535+ .vsel_mask = BD96801_BUCK_VSEL_MASK,536536+ .ramp_reg = BD96801_BUCK1_VSEL_REG,537537+ .ramp_mask = BD96801_MASK_RAMP_DELAY,538538+ .ramp_delay_table = &buck_ramp_table[0],539539+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),540540+ .owner = THIS_MODULE,541541+ },542542+ .init_ranges = bd96801_buck_init_volts,543543+ .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts),544544+ .irq_desc = {545545+ .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0],546546+ .num_irqs = ARRAY_SIZE(buck1_irqinfo),547547+ },548548+ }, {549549+ .desc = {550550+ .name = "buck2",551551+ .of_match = of_match_ptr("buck2"),552552+ .regulators_node = of_match_ptr("regulators"),553553+ .id = BD96801_BUCK2,554554+ .ops = &bd96801_buck_ops,555555+ .type = REGULATOR_VOLTAGE,556556+ .linear_ranges = bd96801_tune_volts,557557+ .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts),558558+ .n_voltages = BD96801_BUCK_VOLTS,559559+ .enable_reg = BD96801_REG_ENABLE,560560+ .enable_mask = BD96801_BUCK2_EN_MASK,561561+ .enable_is_inverted = true,562562+ .vsel_reg = BD96801_BUCK2_VSEL_REG,563563+ .vsel_mask = BD96801_BUCK_VSEL_MASK,564564+ .ramp_reg = BD96801_BUCK2_VSEL_REG,565565+ .ramp_mask = BD96801_MASK_RAMP_DELAY,566566+ .ramp_delay_table = &buck_ramp_table[0],567567+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),568568+ .owner = THIS_MODULE,569569+ },570570+ .irq_desc = {571571+ .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0],572572+ .num_irqs = ARRAY_SIZE(buck2_irqinfo),573573+ },574574+ .init_ranges = bd96801_buck_init_volts,575575+ .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts),576576+ }, {577577+ .desc = {578578+ .name = "buck3",579579+ .of_match = of_match_ptr("buck3"),580580+ .regulators_node = of_match_ptr("regulators"),581581+ .id = BD96801_BUCK3,582582+ .ops = &bd96801_buck_ops,583583+ .type = REGULATOR_VOLTAGE,584584+ .linear_ranges = bd96801_tune_volts,585585+ .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts),586586+ .n_voltages = BD96801_BUCK_VOLTS,587587+ .enable_reg = BD96801_REG_ENABLE,588588+ .enable_mask = BD96801_BUCK3_EN_MASK,589589+ .enable_is_inverted = true,590590+ .vsel_reg = BD96801_BUCK3_VSEL_REG,591591+ .vsel_mask = BD96801_BUCK_VSEL_MASK,592592+ .ramp_reg = BD96801_BUCK3_VSEL_REG,593593+ .ramp_mask = BD96801_MASK_RAMP_DELAY,594594+ .ramp_delay_table = &buck_ramp_table[0],595595+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),596596+ .owner = THIS_MODULE,597597+ },598598+ .irq_desc = {599599+ .irqinfo = (struct bd96801_irqinfo *)&buck3_irqinfo[0],600600+ .num_irqs = ARRAY_SIZE(buck3_irqinfo),601601+ },602602+ .init_ranges = bd96801_buck_init_volts,603603+ .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts),604604+ }, {605605+ .desc = {606606+ .name = "buck4",607607+ .of_match = of_match_ptr("buck4"),608608+ .regulators_node = of_match_ptr("regulators"),609609+ .id = BD96801_BUCK4,610610+ .ops = &bd96801_buck_ops,611611+ .type = REGULATOR_VOLTAGE,612612+ .linear_ranges = bd96801_tune_volts,613613+ .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts),614614+ .n_voltages = BD96801_BUCK_VOLTS,615615+ .enable_reg = BD96801_REG_ENABLE,616616+ .enable_mask = BD96801_BUCK4_EN_MASK,617617+ .enable_is_inverted = true,618618+ .vsel_reg = BD96801_BUCK4_VSEL_REG,619619+ .vsel_mask = BD96801_BUCK_VSEL_MASK,620620+ .ramp_reg = BD96801_BUCK4_VSEL_REG,621621+ .ramp_mask = BD96801_MASK_RAMP_DELAY,622622+ .ramp_delay_table = &buck_ramp_table[0],623623+ .n_ramp_values = ARRAY_SIZE(buck_ramp_table),624624+ .owner = THIS_MODULE,625625+ },626626+ .irq_desc = {627627+ .irqinfo = (struct bd96801_irqinfo *)&buck4_irqinfo[0],628628+ .num_irqs = ARRAY_SIZE(buck4_irqinfo),629629+ },630630+ .init_ranges = bd96801_buck_init_volts,631631+ .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts),632632+ }, {633633+ .desc = {634634+ .name = "ldo5",635635+ .of_match = of_match_ptr("ldo5"),636636+ .regulators_node = of_match_ptr("regulators"),637637+ .id = BD96801_LDO5,638638+ .ops = &bd96801_ldo_ops,639639+ .type = REGULATOR_VOLTAGE,640640+ .linear_ranges = bd96801_ldo_int_volts,641641+ .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts),642642+ .n_voltages = BD96801_LDO_VOLTS,643643+ .enable_reg = BD96801_REG_ENABLE,644644+ .enable_mask = BD96801_LDO5_EN_MASK,645645+ .enable_is_inverted = true,646646+ .vsel_reg = BD96801_LDO5_VSEL_REG,647647+ .vsel_mask = BD96801_LDO_VSEL_MASK,648648+ .owner = THIS_MODULE,649649+ },650650+ .irq_desc = {651651+ .irqinfo = (struct bd96801_irqinfo *)&ldo5_irqinfo[0],652652+ .num_irqs = ARRAY_SIZE(ldo5_irqinfo),653653+ },654654+ .ldo_vol_lvl = BD96801_LDO5_VOL_LVL_REG,655655+ }, {656656+ .desc = {657657+ .name = "ldo6",658658+ .of_match = of_match_ptr("ldo6"),659659+ .regulators_node = of_match_ptr("regulators"),660660+ .id = BD96801_LDO6,661661+ .ops = &bd96801_ldo_ops,662662+ .type = REGULATOR_VOLTAGE,663663+ .linear_ranges = bd96801_ldo_int_volts,664664+ .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts),665665+ .n_voltages = BD96801_LDO_VOLTS,666666+ .enable_reg = BD96801_REG_ENABLE,667667+ .enable_mask = BD96801_LDO6_EN_MASK,668668+ .enable_is_inverted = true,669669+ .vsel_reg = BD96801_LDO6_VSEL_REG,670670+ .vsel_mask = BD96801_LDO_VSEL_MASK,671671+ .owner = THIS_MODULE,672672+ },673673+ .irq_desc = {674674+ .irqinfo = (struct bd96801_irqinfo *)&ldo6_irqinfo[0],675675+ .num_irqs = ARRAY_SIZE(ldo6_irqinfo),676676+ },677677+ .ldo_vol_lvl = BD96801_LDO6_VOL_LVL_REG,678678+ }, {679679+ .desc = {680680+ .name = "ldo7",681681+ .of_match = of_match_ptr("ldo7"),682682+ .regulators_node = of_match_ptr("regulators"),683683+ .id = BD96801_LDO7,684684+ .ops = &bd96801_ldo_ops,685685+ .type = REGULATOR_VOLTAGE,686686+ .linear_ranges = bd96801_ldo_int_volts,687687+ .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts),688688+ .n_voltages = BD96801_LDO_VOLTS,689689+ .enable_reg = BD96801_REG_ENABLE,690690+ .enable_mask = BD96801_LDO7_EN_MASK,691691+ .enable_is_inverted = true,692692+ .vsel_reg = BD96801_LDO7_VSEL_REG,693693+ .vsel_mask = BD96801_LDO_VSEL_MASK,694694+ .owner = THIS_MODULE,695695+ },696696+ .irq_desc = {697697+ .irqinfo = (struct bd96801_irqinfo *)&ldo7_irqinfo[0],698698+ .num_irqs = ARRAY_SIZE(ldo7_irqinfo),699699+ },700700+ .ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG,701701+ },702702+ },703703+};704704+705705+static int initialize_pmic_data(struct device *dev,706706+ struct bd96801_pmic_data *pdata)707707+{708708+ int r, i;709709+710710+ /*711711+ * Allocate and initialize IRQ data for all of the regulators. We712712+ * wish to modify IRQ information independently for each driver713713+ * instance.714714+ */715715+ for (r = 0; r < BD96801_NUM_REGULATORS; r++) {716716+ const struct bd96801_irqinfo *template;717717+ struct bd96801_irqinfo *new;718718+ int num_infos;719719+720720+ template = pdata->regulator_data[r].irq_desc.irqinfo;721721+ num_infos = pdata->regulator_data[r].irq_desc.num_irqs;722722+723723+ new = devm_kcalloc(dev, num_infos, sizeof(*new), GFP_KERNEL);724724+ if (!new)725725+ return -ENOMEM;726726+727727+ pdata->regulator_data[r].irq_desc.irqinfo = new;728728+729729+ for (i = 0; i < num_infos; i++)730730+ new[i] = template[i];731731+ }732732+733733+ return 0;734734+}735735+736736+static int bd96801_rdev_intb_irqs(struct platform_device *pdev,737737+ struct bd96801_pmic_data *pdata,738738+ struct bd96801_irqinfo *iinfo,739739+ struct regulator_dev *rdev)740740+{741741+ struct regulator_dev *rdev_arr[1];742742+ void *retp;743743+ int err = 0;744744+ int irq;745745+ int err_flags[] = {746746+ [BD96801_PROT_OVP] = REGULATOR_ERROR_REGULATION_OUT,747747+ [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE,748748+ [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT,749749+ [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP,750750+751751+ };752752+ int wrn_flags[] = {753753+ [BD96801_PROT_OVP] = REGULATOR_ERROR_OVER_VOLTAGE_WARN,754754+ [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE_WARN,755755+ [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT_WARN,756756+ [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP_WARN,757757+ };758758+759759+ /*760760+ * Don't install IRQ handler if both error and warning761761+ * notifications are explicitly disabled762762+ */763763+ if (!iinfo->err_cfg && !iinfo->wrn_cfg)764764+ return 0;765765+766766+ if (WARN_ON(iinfo->type >= BD96801_NUM_PROT))767767+ return -EINVAL;768768+769769+ if (iinfo->err_cfg)770770+ err = err_flags[iinfo->type];771771+ else if (iinfo->wrn_cfg)772772+ err = wrn_flags[iinfo->type];773773+774774+ iinfo->irq_desc.data = pdata;775775+ irq = platform_get_irq_byname(pdev, iinfo->irq_name);776776+ if (irq < 0)777777+ return irq;778778+ /* Find notifications for this IRQ (WARN/ERR) */779779+780780+ rdev_arr[0] = rdev;781781+ retp = devm_regulator_irq_helper(&pdev->dev,782782+ &iinfo->irq_desc, irq,783783+ 0, err, NULL, rdev_arr,784784+ 1);785785+ if (IS_ERR(retp))786786+ return PTR_ERR(retp);787787+788788+ return 0;789789+}790790+791791+792792+793793+static int bd96801_probe(struct platform_device *pdev)794794+{795795+ struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS];796796+ struct bd96801_regulator_data *rdesc;797797+ struct regulator_config config = {};798798+ int ldo_errs_arr[BD96801_NUM_LDOS];799799+ struct bd96801_pmic_data *pdata;800800+ int temp_notif_ldos = 0;801801+ struct device *parent;802802+ int i, ret;803803+ void *retp;804804+805805+ parent = pdev->dev.parent;806806+807807+ pdata = devm_kmemdup(&pdev->dev, &bd96801_data, sizeof(bd96801_data),808808+ GFP_KERNEL);809809+ if (!pdata)810810+ return -ENOMEM;811811+812812+ if (initialize_pmic_data(&pdev->dev, pdata))813813+ return -ENOMEM;814814+815815+ pdata->regmap = dev_get_regmap(parent, NULL);816816+ if (!pdata->regmap) {817817+ dev_err(&pdev->dev, "No register map found\n");818818+ return -ENODEV;819819+ }820820+821821+ rdesc = &pdata->regulator_data[0];822822+823823+ config.driver_data = pdata;824824+ config.regmap = pdata->regmap;825825+ config.dev = parent;826826+827827+ ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc,828828+ BD96801_NUM_REGULATORS);829829+ if (ret)830830+ return ret;831831+832832+ for (i = 0; i < ARRAY_SIZE(pdata->regulator_data); i++) {833833+ struct regulator_dev *rdev;834834+ struct bd96801_irq_desc *idesc = &rdesc[i].irq_desc;835835+ int j;836836+837837+ rdev = devm_regulator_register(&pdev->dev,838838+ &rdesc[i].desc, &config);839839+ if (IS_ERR(rdev)) {840840+ dev_err(&pdev->dev,841841+ "failed to register %s regulator\n",842842+ rdesc[i].desc.name);843843+ return PTR_ERR(rdev);844844+ }845845+ /*846846+ * LDOs don't have own temperature monitoring. If temperature847847+ * notification was requested for this LDO from DT then we will848848+ * add the regulator to be notified if central IC temperature849849+ * exceeds threshold.850850+ */851851+ if (rdesc[i].ldo_errs) {852852+ ldo_errs_rdev_arr[temp_notif_ldos] = rdev;853853+ ldo_errs_arr[temp_notif_ldos] = rdesc[i].ldo_errs;854854+ temp_notif_ldos++;855855+ }856856+ if (!idesc)857857+ continue;858858+859859+ /* Register INTB handlers for configured protections */860860+ for (j = 0; j < idesc->num_irqs; j++) {861861+ ret = bd96801_rdev_intb_irqs(pdev, pdata,862862+ &idesc->irqinfo[j], rdev);863863+ if (ret)864864+ return ret;865865+ }866866+ }867867+ if (temp_notif_ldos) {868868+ int irq;869869+ struct regulator_irq_desc tw_desc = {870870+ .name = "bd96801-core-thermal",871871+ .irq_off_ms = 500,872872+ .map_event = ldo_map_notif,873873+ };874874+875875+ irq = platform_get_irq_byname(pdev, "bd96801-core-thermal");876876+ if (irq < 0)877877+ return irq;878878+879879+ retp = devm_regulator_irq_helper(&pdev->dev, &tw_desc, irq, 0,880880+ 0, &ldo_errs_arr[0],881881+ &ldo_errs_rdev_arr[0],882882+ temp_notif_ldos);883883+ if (IS_ERR(retp))884884+ return PTR_ERR(retp);885885+ }886886+887887+ return 0;888888+}889889+890890+static const struct platform_device_id bd96801_pmic_id[] = {891891+ { "bd96801-regulator", },892892+ { }893893+};894894+MODULE_DEVICE_TABLE(platform, bd96801_pmic_id);895895+896896+static struct platform_driver bd96801_regulator = {897897+ .driver = {898898+ .name = "bd96801-pmic"899899+ },900900+ .probe = bd96801_probe,901901+ .id_table = bd96801_pmic_id,902902+};903903+904904+module_platform_driver(bd96801_regulator);905905+906906+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");907907+MODULE_DESCRIPTION("BD96801 voltage regulator driver");908908+MODULE_LICENSE("GPL");
+13
drivers/watchdog/Kconfig
···181181 watchdog. Alternatively say M to compile the driver as a module,182182 which will be called bd9576_wdt.183183184184+config BD96801_WATCHDOG185185+ tristate "ROHM BD96801 PMIC Watchdog"186186+ depends on MFD_ROHM_BD96801187187+ select WATCHDOG_CORE188188+ help189189+ Support for the watchdog in the ROHM BD96801 PMIC. Watchdog can be190190+ configured to only generate IRQ or to trigger system reset via reset191191+ pin.192192+193193+ Say Y here to include support for the ROHM BD96801 watchdog.194194+ Alternatively say M to compile the driver as a module,195195+ which will be called bd96801_wdt.196196+184197config CROS_EC_WATCHDOG185198 tristate "ChromeOS EC-based watchdog"186199 select WATCHDOG_CORE