summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Kconfig4
-rw-r--r--drivers/clk/clk-bd718x7.c10
-rw-r--r--drivers/gpio/Kconfig9
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-bd72720.c281
-rw-r--r--drivers/mfd/Kconfig18
-rw-r--r--drivers/mfd/rohm-bd71828.c555
-rw-r--r--drivers/power/supply/bd71828-power.c160
-rw-r--r--drivers/regulator/Kconfig8
-rw-r--r--drivers/regulator/bd71828-regulator.c1025
-rw-r--r--drivers/rtc/Kconfig3
-rw-r--r--drivers/rtc/rtc-bd70528.c21
12 files changed, 1967 insertions, 128 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3a1611008e48..619bd63a3c77 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -475,8 +475,8 @@ config COMMON_CLK_BD718XX
tristate "Clock driver for 32K clk gates on ROHM PMICs"
depends on MFD_ROHM_BD718XX || MFD_ROHM_BD71828
help
- This driver supports ROHM BD71837, BD71847, BD71850, BD71815
- and BD71828 PMICs clock gates.
+ This driver supports ROHM BD71837, BD71847, BD71850, BD71815,
+ BD71828, and BD72720 PMICs clock gates.
config COMMON_CLK_FIXED_MMIO
bool "Clock driver for Memory Mapped Fixed values"
diff --git a/drivers/clk/clk-bd718x7.c b/drivers/clk/clk-bd718x7.c
index ac40b669d60b..1cae974e6d1d 100644
--- a/drivers/clk/clk-bd718x7.c
+++ b/drivers/clk/clk-bd718x7.c
@@ -19,7 +19,8 @@
#define BD71828_REG_OUT32K 0x4B
/* BD71837 and BD71847 */
#define BD718XX_REG_OUT32K 0x2E
-
+/* BD72720 */
+#define BD72720_REG_OUT32K 0x9a
/*
* BD71837, BD71847, and BD71828 all use bit [0] to clk output control
*/
@@ -118,6 +119,10 @@ static int bd71837_clk_probe(struct platform_device *pdev)
c->reg = BD71815_REG_OUT32K;
c->mask = CLK_OUT_EN_MASK;
break;
+ case ROHM_CHIP_TYPE_BD72720:
+ c->reg = BD72720_REG_OUT32K;
+ c->mask = CLK_OUT_EN_MASK;
+ break;
default:
dev_err(&pdev->dev, "Unknown clk chip\n");
return -EINVAL;
@@ -146,6 +151,7 @@ static const struct platform_device_id bd718x7_clk_id[] = {
{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
{ "bd71815-clk", ROHM_CHIP_TYPE_BD71815 },
+ { "bd72720-clk", ROHM_CHIP_TYPE_BD72720 },
{ },
};
MODULE_DEVICE_TABLE(platform, bd718x7_clk_id);
@@ -161,6 +167,6 @@ static struct platform_driver bd71837_clk = {
module_platform_driver(bd71837_clk);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and chip clk driver");
+MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD72720 chip clk driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bd718xx-clk");
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index bd185482a7fd..6b4df4db2f04 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1317,6 +1317,15 @@ config GPIO_BD71828
This driver can also be built as a module. If so, the module
will be called gpio-bd71828.
+config GPIO_BD72720
+ tristate "ROHM BD72720 and BD73900 PMIC GPIO support"
+ depends on MFD_ROHM_BD71828
+ help
+ Support for GPIO on ROHM BD72720 and BD73900 PMICs. There are two
+ pins which can be configured to GPI or GPO, and three pins which can
+ be configured to GPO on the ROHM PMIC. The pin configuration is done
+ on OTP at manufacturing.
+
config GPIO_BD9571MWV
tristate "ROHM BD9571 GPIO support"
depends on MFD_BD9571MWV
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 2421a8fd3733..e1d4c1ddd4d8 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o
obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o
obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o
+obj-$(CONFIG_GPIO_BD72720) += gpio-bd72720.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BLZP1600) += gpio-blzp1600.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
diff --git a/drivers/gpio/gpio-bd72720.c b/drivers/gpio/gpio-bd72720.c
new file mode 100644
index 000000000000..6549dbf4c7ad
--- /dev/null
+++ b/drivers/gpio/gpio-bd72720.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support to GPIOs on ROHM BD72720 and BD79300
+ * Copyright 2025 ROHM Semiconductors.
+ * Author: Matti Vaittinen <mazziesaccount@gmail.com>
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/rohm-bd72720.h>
+
+#define BD72720_GPIO_OPEN_DRAIN 0
+#define BD72720_GPIO_CMOS BIT(1)
+#define BD72720_INT_GPIO1_IN_SRC 4
+/*
+ * The BD72720 has several "one time programmable" (OTP) configurations which
+ * can be set at manufacturing phase. A set of these options allow using pins
+ * as GPIO. The OTP configuration can't be read at run-time, so drivers rely on
+ * device-tree to advertise the correct options.
+ *
+ * Both DVS[0,1] pins can be configured to be used for:
+ * - OTP0: regulator RUN state control
+ * - OTP1: GPI
+ * - OTP2: GPO
+ * - OTP3: Power sequencer output
+ * Data-sheet also states that these PINs can always be used for IRQ but the
+ * driver limits this by allowing them to be used for IRQs with OTP1 only.
+ *
+ * Pins GPIO_EXTEN0 (GPIO3), GPIO_EXTEN1 (GPIO4), GPIO_FAULT_B (GPIO5) have OTP
+ * options for a specific (non GPIO) purposes, but also an option to configure
+ * them to be used as a GPO.
+ *
+ * OTP settings can be separately configured for each pin.
+ *
+ * DT properties:
+ * "rohm,pin-dvs0" and "rohm,pin-dvs1" can be set to one of the values:
+ * "dvs-input", "gpi", "gpo".
+ *
+ * "rohm,pin-exten0", "rohm,pin-exten1" and "rohm,pin-fault_b" can be set to:
+ * "gpo"
+ */
+
+enum bd72720_gpio_state {
+ BD72720_PIN_UNKNOWN,
+ BD72720_PIN_GPI,
+ BD72720_PIN_GPO,
+};
+
+enum {
+ BD72720_GPIO1,
+ BD72720_GPIO2,
+ BD72720_GPIO3,
+ BD72720_GPIO4,
+ BD72720_GPIO5,
+ BD72720_GPIO_EPDEN,
+ BD72720_NUM_GPIOS
+};
+
+struct bd72720_gpio {
+ /* chip.parent points the MFD which provides DT node and regmap */
+ struct gpio_chip chip;
+ /* dev points to the platform device for devm and prints */
+ struct device *dev;
+ struct regmap *regmap;
+ int gpio_is_input;
+};
+
+static int bd72720gpi_get(struct bd72720_gpio *bdgpio, unsigned int reg_offset)
+{
+ int ret, val, shift;
+
+ ret = regmap_read(bdgpio->regmap, BD72720_REG_INT_ETC1_SRC, &val);
+ if (ret)
+ return ret;
+
+ shift = BD72720_INT_GPIO1_IN_SRC + reg_offset;
+
+ return (val >> shift) & 1;
+}
+
+static int bd72720gpo_get(struct bd72720_gpio *bdgpio,
+ unsigned int offset)
+{
+ const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
+ BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
+ BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
+ int ret, val;
+
+ ret = regmap_read(bdgpio->regmap, regs[offset], &val);
+ if (ret)
+ return ret;
+
+ return val & BD72720_GPIO_HIGH;
+}
+
+static int bd72720gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+
+ if (BIT(offset) & bdgpio->gpio_is_input)
+ return bd72720gpi_get(bdgpio, offset);
+
+ return bd72720gpo_get(bdgpio, offset);
+}
+
+static int bd72720gpo_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+ const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
+ BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
+ BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
+
+ if (BIT(offset) & bdgpio->gpio_is_input) {
+ dev_dbg(bdgpio->dev, "pin %d not output.\n", offset);
+ return -EINVAL;
+ }
+
+ if (value)
+ return regmap_set_bits(bdgpio->regmap, regs[offset],
+ BD72720_GPIO_HIGH);
+
+ return regmap_clear_bits(bdgpio->regmap, regs[offset],
+ BD72720_GPIO_HIGH);
+}
+
+static int bd72720_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+{
+ struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+ const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
+ BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
+ BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
+
+ /*
+ * We can only set the output mode, which makes sense only when output
+ * OTP configuration is used.
+ */
+ if (BIT(offset) & bdgpio->gpio_is_input)
+ return -ENOTSUPP;
+
+ switch (pinconf_to_config_param(config)) {
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ return regmap_update_bits(bdgpio->regmap,
+ regs[offset],
+ BD72720_GPIO_DRIVE_MASK,
+ BD72720_GPIO_OPEN_DRAIN);
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ return regmap_update_bits(bdgpio->regmap,
+ regs[offset],
+ BD72720_GPIO_DRIVE_MASK,
+ BD72720_GPIO_CMOS);
+ default:
+ break;
+ }
+
+ return -ENOTSUPP;
+}
+
+static int bd72720gpo_direction_get(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
+
+ if (BIT(offset) & bdgpio->gpio_is_input)
+ return GPIO_LINE_DIRECTION_IN;
+
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int bd72720_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ static const char * const properties[] = {
+ "rohm,pin-dvs0", "rohm,pin-dvs1", "rohm,pin-exten0",
+ "rohm,pin-exten1", "rohm,pin-fault_b"
+ };
+ struct bd72720_gpio *g = gpiochip_get_data(gc);
+ const char *val;
+ int i, ret;
+
+ *valid_mask = BIT(BD72720_GPIO_EPDEN);
+
+ if (!gc->parent)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(properties); i++) {
+ ret = fwnode_property_read_string(dev_fwnode(gc->parent),
+ properties[i], &val);
+
+ if (ret) {
+ if (ret == -EINVAL)
+ continue;
+
+ dev_err(g->dev, "pin %d (%s), bad configuration\n", i,
+ properties[i]);
+
+ return ret;
+ }
+
+ if (strcmp(val, "gpi") == 0) {
+ if (i != BD72720_GPIO1 && i != BD72720_GPIO2) {
+ dev_warn(g->dev,
+ "pin %d (%s) does not support INPUT mode",
+ i, properties[i]);
+ continue;
+ }
+
+ *valid_mask |= BIT(i);
+ g->gpio_is_input |= BIT(i);
+ } else if (strcmp(val, "gpo") == 0) {
+ *valid_mask |= BIT(i);
+ }
+ }
+
+ return 0;
+}
+
+/* Template for GPIO chip */
+static const struct gpio_chip bd72720gpo_chip = {
+ .label = "bd72720",
+ .owner = THIS_MODULE,
+ .get = bd72720gpio_get,
+ .get_direction = bd72720gpo_direction_get,
+ .set = bd72720gpo_set,
+ .set_config = bd72720_gpio_set_config,
+ .init_valid_mask = bd72720_valid_mask,
+ .can_sleep = true,
+ .ngpio = BD72720_NUM_GPIOS,
+ .base = -1,
+};
+
+static int gpo_bd72720_probe(struct platform_device *pdev)
+{
+ struct bd72720_gpio *g;
+ struct device *parent, *dev;
+
+ /*
+ * Bind devm lifetime to this platform device => use dev for devm.
+ * also the prints should originate from this device.
+ */
+ dev = &pdev->dev;
+ /* The device-tree and regmap come from MFD => use parent for that */
+ parent = dev->parent;
+
+ g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
+ if (!g)
+ return -ENOMEM;
+
+ g->chip = bd72720gpo_chip;
+ g->dev = dev;
+ g->chip.parent = parent;
+ g->regmap = dev_get_regmap(parent, NULL);
+
+ return devm_gpiochip_add_data(dev, &g->chip, g);
+}
+
+static const struct platform_device_id bd72720_gpio_id[] = {
+ { "bd72720-gpio" },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
+
+static struct platform_driver gpo_bd72720_driver = {
+ .driver = {
+ .name = "bd72720-gpio",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .probe = gpo_bd72720_probe,
+ .id_table = bd72720_gpio_id,
+};
+module_platform_driver(gpo_bd72720_driver);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("GPIO interface for BD72720 and BD73900");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index aace5766b38a..699f095f831e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2217,20 +2217,22 @@ config MFD_ROHM_BD718XX
and emergency shut down as well as 32,768KHz clock output.
config MFD_ROHM_BD71828
- tristate "ROHM BD71828 and BD71815 Power Management IC"
+ tristate "ROHM BD718[15/28/79], BD72720 and BD73900 PMICs"
depends on I2C=y
depends on OF
select REGMAP_I2C
select REGMAP_IRQ
select MFD_CORE
help
- Select this option to get support for the ROHM BD71828 and BD71815
- Power Management ICs. BD71828GW and BD71815AGW are single-chip power
- management ICs mainly for battery-powered portable devices.
- The BD71828 integrates 7 buck converters and 7 LDOs. The BD71815
- has 5 bucks, 7 LDOs, and a boost for driving LEDs. Both ICs provide
- also a single-cell linear charger, a Coulomb counter, a real-time
- clock (RTC), GPIOs and a 32.768 kHz clock gate.
+ Select this option to get support for the ROHM BD71815, BD71828,
+ BD71879, BD72720 and BD73900 Power Management ICs (PMICs). These are
+ single-chip Power Management ICs (PMIC), mainly for battery-powered
+ portable devices.
+ The BD71815 has 5 bucks, 7 LDOs, and a boost for driving LEDs.
+ The BD718[28/79] have 7 buck converters and 7 LDOs.
+ The BD72720 and the BD73900 have 10 bucks and 11 LDOs.
+ All ICs provide a single-cell linear charger, a Coulomb counter,
+ a Real-Time Clock (RTC), GPIOs and a 32.768 kHz clock gate.
config MFD_ROHM_BD957XMUF
tristate "ROHM BD9576MUF and BD9573MUF Power Management ICs"
diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c
index 84a64c3b9c9f..e54152a03510 100644
--- a/drivers/mfd/rohm-bd71828.c
+++ b/drivers/mfd/rohm-bd71828.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
-//
-// Copyright (C) 2019 ROHM Semiconductors
-//
-// ROHM BD71828/BD71815 PMIC driver
+/*
+ * Copyright (C) 2019 ROHM Semiconductors
+ *
+ * ROHM BD718[15/28/79] and BD72720 PMIC driver
+ */
#include <linux/gpio_keys.h>
#include <linux/i2c.h>
@@ -13,12 +14,29 @@
#include <linux/mfd/core.h>
#include <linux/mfd/rohm-bd71815.h>
#include <linux/mfd/rohm-bd71828.h>
+#include <linux/mfd/rohm-bd72720.h>
#include <linux/mfd/rohm-generic.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/types.h>
+#define BD72720_TYPED_IRQ_REG(_irq, _stat_offset, _mask, _type_offset) \
+ [_irq] = { \
+ .reg_offset = (_stat_offset), \
+ .mask = (_mask), \
+ { \
+ .type_reg_offset = (_type_offset), \
+ .type_reg_mask = BD72720_GPIO_IRQ_TYPE_MASK, \
+ .type_rising_val = BD72720_GPIO_IRQ_TYPE_RISING, \
+ .type_falling_val = BD72720_GPIO_IRQ_TYPE_FALLING, \
+ .type_level_low_val = BD72720_GPIO_IRQ_TYPE_LOW, \
+ .type_level_high_val = BD72720_GPIO_IRQ_TYPE_HIGH, \
+ .types_supported = IRQ_TYPE_EDGE_BOTH | \
+ IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW, \
+ }, \
+ }
+
static struct gpio_keys_button button = {
.code = KEY_POWER,
.gpio = -1,
@@ -43,6 +61,12 @@ static const struct resource bd71828_rtc_irqs[] = {
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd70528-rtc-alm-2"),
};
+static const struct resource bd72720_rtc_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_RTC0, "bd70528-rtc-alm-0"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_RTC1, "bd70528-rtc-alm-1"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_RTC2, "bd70528-rtc-alm-2"),
+};
+
static const struct resource bd71815_power_irqs[] = {
DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"),
DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-dcin-clps-out"),
@@ -156,56 +180,181 @@ static struct mfd_cell bd71828_mfd_cells[] = {
},
};
-static const struct regmap_range bd71815_volatile_ranges[] = {
+static const struct resource bd72720_power_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBUS_RMV, "bd72720_int_vbus_rmv"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBUS_DET, "bd72720_int_vbus_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBUS_MON_RES, "bd72720_int_vbus_mon_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBUS_MON_DET, "bd72720_int_vbus_mon_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_MON_RES, "bd72720_int_vsys_mon_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_MON_DET, "bd72720_int_vsys_mon_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_UV_RES, "bd72720_int_vsys_uv_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_UV_DET, "bd72720_int_vsys_uv_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_LO_RES, "bd72720_int_vsys_lo_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_LO_DET, "bd72720_int_vsys_lo_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_OV_RES, "bd72720_int_vsys_ov_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_OV_DET, "bd72720_int_vsys_ov_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_ILIM, "bd72720_int_bat_ilim"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_CHG_DONE, "bd72720_int_chg_done"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_EXTEMP_TOUT, "bd72720_int_extemp_tout"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_CHG_WDT_EXP, "bd72720_int_chg_wdt_exp"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_MNT_OUT, "bd72720_int_bat_mnt_out"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_MNT_IN, "bd72720_int_bat_mnt_in"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_CHG_TRNS, "bd72720_int_chg_trns"),
+
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_MON_RES, "bd72720_int_vbat_mon_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_MON_DET, "bd72720_int_vbat_mon_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_SHT_RES, "bd72720_int_vbat_sht_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_SHT_DET, "bd72720_int_vbat_sht_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_LO_RES, "bd72720_int_vbat_lo_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_LO_DET, "bd72720_int_vbat_lo_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_OV_RES, "bd72720_int_vbat_ov_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_OV_DET, "bd72720_int_vbat_ov_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_RMV, "bd72720_int_bat_rmv"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_DET, "bd72720_int_bat_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_DBAT_DET, "bd72720_int_dbat_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_TEMP_TRNS, "bd72720_int_bat_temp_trns"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_LOBTMP_RES, "bd72720_int_lobtmp_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_LOBTMP_DET, "bd72720_int_lobtmp_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_OVBTMP_RES, "bd72720_int_ovbtmp_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_OVBTMP_DET, "bd72720_int_ovbtmp_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR1_RES, "bd72720_int_ocur1_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR1_DET, "bd72720_int_ocur1_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR2_RES, "bd72720_int_ocur2_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR2_DET, "bd72720_int_ocur2_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR3_RES, "bd72720_int_ocur3_res"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR3_DET, "bd72720_int_ocur3_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_CC_MON1_DET, "bd72720_int_cc_mon1_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_CC_MON2_DET, "bd72720_int_cc_mon2_det"),
+ DEFINE_RES_IRQ_NAMED(BD72720_INT_CC_MON3_DET, "bd72720_int_cc_mon3_det"),
+};
+
+static const struct mfd_cell bd72720_mfd_cells[] = {
+ { .name = "bd72720-pmic", },
+ { .name = "bd72720-gpio", },
+ { .name = "bd72720-led", },
+ { .name = "bd72720-clk", },
{
- .range_min = BD71815_REG_SEC,
- .range_max = BD71815_REG_YEAR,
- }, {
- .range_min = BD71815_REG_CONF,
- .range_max = BD71815_REG_BAT_TEMP,
- }, {
- .range_min = BD71815_REG_VM_IBAT_U,
- .range_max = BD71815_REG_CC_CTRL,
- }, {
- .range_min = BD71815_REG_CC_STAT,
- .range_max = BD71815_REG_CC_CURCD_L,
+ .name = "bd72720-power",
+ .resources = bd72720_power_irqs,
+ .num_resources = ARRAY_SIZE(bd72720_power_irqs),
}, {
- .range_min = BD71815_REG_VM_BTMP_MON,
- .range_max = BD71815_REG_VM_BTMP_MON,
+ .name = "bd72720-rtc",
+ .resources = bd72720_rtc_irqs,
+ .num_resources = ARRAY_SIZE(bd72720_rtc_irqs),
}, {
- .range_min = BD71815_REG_INT_STAT,
- .range_max = BD71815_REG_INT_UPDATE,
- }, {
- .range_min = BD71815_REG_VM_VSYS_U,
- .range_max = BD71815_REG_REX_CTRL_1,
- }, {
- .range_min = BD71815_REG_FULL_CCNTD_3,
- .range_max = BD71815_REG_CCNTD_CHG_2,
+ .name = "gpio-keys",
+ .platform_data = &bd71828_powerkey_data,
+ .pdata_size = sizeof(bd71828_powerkey_data),
},
};
+static const struct regmap_range bd71815_volatile_ranges[] = {
+ regmap_reg_range(BD71815_REG_SEC, BD71815_REG_YEAR),
+ regmap_reg_range(BD71815_REG_CONF, BD71815_REG_BAT_TEMP),
+ regmap_reg_range(BD71815_REG_VM_IBAT_U, BD71815_REG_CC_CTRL),
+ regmap_reg_range(BD71815_REG_CC_STAT, BD71815_REG_CC_CURCD_L),
+ regmap_reg_range(BD71815_REG_VM_BTMP_MON, BD71815_REG_VM_BTMP_MON),
+ regmap_reg_range(BD71815_REG_INT_STAT, BD71815_REG_INT_UPDATE),
+ regmap_reg_range(BD71815_REG_VM_VSYS_U, BD71815_REG_REX_CTRL_1),
+ regmap_reg_range(BD71815_REG_FULL_CCNTD_3, BD71815_REG_CCNTD_CHG_2),
+};
+
static const struct regmap_range bd71828_volatile_ranges[] = {
- {
- .range_min = BD71828_REG_PS_CTRL_1,
- .range_max = BD71828_REG_PS_CTRL_1,
- }, {
- .range_min = BD71828_REG_PS_CTRL_3,
- .range_max = BD71828_REG_PS_CTRL_3,
- }, {
- .range_min = BD71828_REG_RTC_SEC,
- .range_max = BD71828_REG_RTC_YEAR,
- }, {
- /*
- * For now make all charger registers volatile because many
- * needs to be and because the charger block is not that
- * performance critical.
- */
- .range_min = BD71828_REG_CHG_STATE,
- .range_max = BD71828_REG_CHG_FULL,
- }, {
- .range_min = BD71828_REG_INT_MAIN,
- .range_max = BD71828_REG_IO_STAT,
- },
+ regmap_reg_range(BD71828_REG_PS_CTRL_1, BD71828_REG_PS_CTRL_1),
+ regmap_reg_range(BD71828_REG_PS_CTRL_3, BD71828_REG_PS_CTRL_3),
+ regmap_reg_range(BD71828_REG_RTC_SEC, BD71828_REG_RTC_YEAR),
+ /*
+ * For now make all charger registers volatile because many
+ * needs to be and because the charger block is not that
+ * performance critical.
+ */
+ regmap_reg_range(BD71828_REG_CHG_STATE, BD71828_REG_CHG_FULL),
+ regmap_reg_range(BD71828_REG_INT_MAIN, BD71828_REG_IO_STAT),
+};
+
+static const struct regmap_range bd72720_volatile_ranges_4b[] = {
+ regmap_reg_range(BD72720_REG_RESETSRC_1, BD72720_REG_RESETSRC_2),
+ regmap_reg_range(BD72720_REG_POWER_STATE, BD72720_REG_POWER_STATE),
+ /* The state indicator bit changes when new state is reached */
+ regmap_reg_range(BD72720_REG_PS_CTRL_1, BD72720_REG_PS_CTRL_1),
+ regmap_reg_range(BD72720_REG_RCVNUM, BD72720_REG_RCVNUM),
+ regmap_reg_range(BD72720_REG_CONF, BD72720_REG_HALL_STAT),
+ regmap_reg_range(BD72720_REG_RTC_SEC, BD72720_REG_RTC_YEAR),
+ regmap_reg_range(BD72720_REG_INT_LVL1_STAT, BD72720_REG_INT_ETC2_SRC),
+};
+
+static const struct regmap_range bd72720_precious_ranges_4b[] = {
+ regmap_reg_range(BD72720_REG_INT_LVL1_STAT, BD72720_REG_INT_ETC2_STAT),
+};
+
+/*
+ * The BD72720 is an odd beast in that it contains two separate sets of
+ * registers, both starting from address 0x0. The twist is that these "pages"
+ * are behind different I2C slave addresses. Most of the registers are behind
+ * a slave address 0x4b, which will be used as the "main" address for this
+ * device.
+ *
+ * Most of the charger related registers are located behind slave address 0x4c.
+ * It is tempting to push the dealing with the charger registers and the extra
+ * 0x4c device in power-supply driver - but perhaps it's better for the sake of
+ * the cleaner re-use to deal with setting up all of the regmaps here.
+ * Furthermore, the LED stuff may need access to both of these devices.
+ *
+ * Instead of providing one of the regmaps to sub-devices in MFD platform data,
+ * we create one more 'wrapper regmap' with custom read/write operations. These
+ * custom accessors will select which of the 'real' regmaps to use, based on
+ * the register address.
+ *
+ * The register addresses are 8-bit, so we add offset 0x100 to the addresses
+ * behind the secondary slave 0x4c. The 'wrapper' regmap can then detect the
+ * correct slave address based on the register address and call regmap_write()
+ * and regmap_read() using correct 'real' regmap. This way the registers of
+ * both of the slaves can be accessed using one 'wrapper' regmap.
+ *
+ * NOTE: The added offsets mean that the defined addresses for slave 0x4c must
+ * be used through the 'wrapper' regmap because the offset must be stripped
+ * from the register addresses. The 0x4b can be accessed both indirectly using
+ * the 'wrapper' regmap, and directly using the 'real' regmap.
+ */
+#define BD72720_SECONDARY_I2C_SLAVE 0x4c
+#define BD72720_SECONDARY_I2C_REG_OFFSET 0x100
+
+struct bd72720_regmaps {
+ struct regmap *map1_4b;
+ struct regmap *map2_4c;
+};
+
+/* Translate the slave 0x4c wrapper register address to a real one */
+#define BD72720_REG_UNWRAP(reg) ((reg) - BD72720_SECONDARY_I2C_REG_OFFSET)
+
+/* Ranges given to 'real' 0x4c regmap must use unwrapped addresses. */
+#define BD72720_UNWRAP_REG_RANGE(startreg, endreg) \
+ regmap_reg_range(BD72720_REG_UNWRAP(startreg), BD72720_REG_UNWRAP(endreg))
+
+static const struct regmap_range bd72720_volatile_ranges_4c[] = {
+ /* Status information */
+ BD72720_UNWRAP_REG_RANGE(BD72720_REG_CHG_STATE, BD72720_REG_CHG_EN),
+ /*
+ * Under certain circumstances, write to some bits may be
+ * ignored
+ */
+ BD72720_UNWRAP_REG_RANGE(BD72720_REG_CHG_CTRL, BD72720_REG_CHG_CTRL),
+ /*
+ * TODO: Ensure this is used to advertise state, not (only?) to
+ * control it.
+ */
+ BD72720_UNWRAP_REG_RANGE(BD72720_REG_VSYS_STATE_STAT, BD72720_REG_VSYS_STATE_STAT),
+ /* Measured data */
+ BD72720_UNWRAP_REG_RANGE(BD72720_REG_VM_VBAT_U, BD72720_REG_VM_VF_L),
+ /* Self clearing bits */
+ BD72720_UNWRAP_REG_RANGE(BD72720_REG_VM_VSYS_SA_MINMAX_CTRL,
+ BD72720_REG_VM_VSYS_SA_MINMAX_CTRL),
+ /* Counters, self clearing bits */
+ BD72720_UNWRAP_REG_RANGE(BD72720_REG_CC_CURCD_U, BD72720_REG_CC_CTRL),
+ /* Self clearing bits */
+ BD72720_UNWRAP_REG_RANGE(BD72720_REG_CC_CCNTD_CTRL, BD72720_REG_CC_CCNTD_CTRL),
+ /* Self clearing bits */
+ BD72720_UNWRAP_REG_RANGE(BD72720_REG_IMPCHK_CTRL, BD72720_REG_IMPCHK_CTRL),
};
static const struct regmap_access_table bd71815_volatile_regs = {
@@ -218,6 +367,21 @@ static const struct regmap_access_table bd71828_volatile_regs = {
.n_yes_ranges = ARRAY_SIZE(bd71828_volatile_ranges),
};
+static const struct regmap_access_table bd72720_volatile_regs_4b = {
+ .yes_ranges = &bd72720_volatile_ranges_4b[0],
+ .n_yes_ranges = ARRAY_SIZE(bd72720_volatile_ranges_4b),
+};
+
+static const struct regmap_access_table bd72720_precious_regs_4b = {
+ .yes_ranges = &bd72720_precious_ranges_4b[0],
+ .n_yes_ranges = ARRAY_SIZE(bd72720_precious_ranges_4b),
+};
+
+static const struct regmap_access_table bd72720_volatile_regs_4c = {
+ .yes_ranges = &bd72720_volatile_ranges_4c[0],
+ .n_yes_ranges = ARRAY_SIZE(bd72720_volatile_ranges_4c),
+};
+
static const struct regmap_config bd71815_regmap = {
.reg_bits = 8,
.val_bits = 8,
@@ -234,10 +398,79 @@ static const struct regmap_config bd71828_regmap = {
.cache_type = REGCACHE_MAPLE,
};
+static int regmap_write_wrapper(void *context, unsigned int reg, unsigned int val)
+{
+ struct bd72720_regmaps *maps = context;
+
+ if (reg < BD72720_SECONDARY_I2C_REG_OFFSET)
+ return regmap_write(maps->map1_4b, reg, val);
+
+ reg = BD72720_REG_UNWRAP(reg);
+
+ return regmap_write(maps->map2_4c, reg, val);
+}
+
+static int regmap_read_wrapper(void *context, unsigned int reg, unsigned int *val)
+{
+ struct bd72720_regmaps *maps = context;
+
+ if (reg < BD72720_SECONDARY_I2C_REG_OFFSET)
+ return regmap_read(maps->map1_4b, reg, val);
+
+ reg = BD72720_REG_UNWRAP(reg);
+
+ return regmap_read(maps->map2_4c, reg, val);
+}
+
+static const struct regmap_config bd72720_wrapper_map_config = {
+ .name = "wrap-map",
+ .reg_bits = 9,
+ .val_bits = 8,
+ .max_register = BD72720_REG_IMPCHK_CTRL,
+ /*
+ * We don't want to duplicate caches. It would be a bit faster to
+ * have the cache in this 'wrapper regmap', and not in the 'real
+ * regmaps' bd72720_regmap_4b and bd72720_regmap_4c below. This would
+ * require all the subdevices to use the wrapper-map in order to be
+ * able to benefit from the cache.
+ * Currently most of the sub-devices use only the same slave-address
+ * as this MFD driver. Now, because we don't add the offset to the
+ * registers belonging to this slave, those devices can use either the
+ * wrapper map, or the bd72720_regmap_4b directly. This means majority
+ * of our sub devices don't need to care which regmap they get using
+ * the dev_get_regmap(). This unifies the code between the BD72720 and
+ * those variants which don't have this 'multiple slave addresses'
+ * -hassle.
+ * So, for a small performance penalty, we simplify the code for the
+ * sub-devices by having the caches in the wrapped regmaps and not here.
+ */
+ .cache_type = REGCACHE_NONE,
+ .reg_write = regmap_write_wrapper,
+ .reg_read = regmap_read_wrapper,
+};
+
+static const struct regmap_config bd72720_regmap_4b = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &bd72720_volatile_regs_4b,
+ .precious_table = &bd72720_precious_regs_4b,
+ .max_register = BD72720_REG_INT_ETC2_SRC,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static const struct regmap_config bd72720_regmap_4c = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &bd72720_volatile_regs_4c,
+ .max_register = BD72720_REG_UNWRAP(BD72720_REG_IMPCHK_CTRL),
+ .cache_type = REGCACHE_MAPLE,
+};
+
/*
* Mapping of main IRQ register bits to sub-IRQ register offsets so that we can
* access corect sub-IRQ registers based on bits that are set in main IRQ
- * register. BD71815 and BD71828 have same sub-register-block offests.
+ * register. BD71815 and BD71828 have same sub-register-block offests, the
+ * BD72720 has a different one.
*/
static unsigned int bit0_offsets[] = {11}; /* RTC IRQ */
@@ -249,6 +482,15 @@ static unsigned int bit5_offsets[] = {3}; /* VSYS IRQ */
static unsigned int bit6_offsets[] = {1, 2}; /* DCIN IRQ */
static unsigned int bit7_offsets[] = {0}; /* BUCK IRQ */
+static unsigned int bd72720_bit0_offsets[] = {0, 1}; /* PS1 and PS2 */
+static unsigned int bd72720_bit1_offsets[] = {2, 3}; /* DVS1 and DVS2 */
+static unsigned int bd72720_bit2_offsets[] = {4}; /* VBUS */
+static unsigned int bd72720_bit3_offsets[] = {5}; /* VSYS */
+static unsigned int bd72720_bit4_offsets[] = {6}; /* CHG */
+static unsigned int bd72720_bit5_offsets[] = {7, 8}; /* BAT1 and BAT2 */
+static unsigned int bd72720_bit6_offsets[] = {9}; /* IBAT */
+static unsigned int bd72720_bit7_offsets[] = {10, 11}; /* ETC1 and ETC2 */
+
static const struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = {
REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
@@ -260,6 +502,17 @@ static const struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = {
REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets),
};
+static const struct regmap_irq_sub_irq_map bd72720_sub_irq_offsets[] = {
+ REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit0_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit1_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit2_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit3_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit4_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit5_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit6_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit7_offsets),
+};
+
static const struct regmap_irq bd71815_irqs[] = {
REGMAP_IRQ_REG(BD71815_INT_BUCK1_OCP, 0, BD71815_INT_BUCK1_OCP_MASK),
REGMAP_IRQ_REG(BD71815_INT_BUCK2_OCP, 0, BD71815_INT_BUCK2_OCP_MASK),
@@ -433,6 +686,117 @@ static const struct regmap_irq bd71828_irqs[] = {
REGMAP_IRQ_REG(BD71828_INT_RTC2, 11, BD71828_INT_RTC2_MASK),
};
+static const struct regmap_irq bd72720_irqs[] = {
+ REGMAP_IRQ_REG(BD72720_INT_LONGPUSH, 0, BD72720_INT_LONGPUSH_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_MIDPUSH, 0, BD72720_INT_MIDPUSH_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_SHORTPUSH, 0, BD72720_INT_SHORTPUSH_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_PUSH, 0, BD72720_INT_PUSH_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_HALL_DET, 0, BD72720_INT_HALL_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_HALL_TGL, 0, BD72720_INT_HALL_TGL_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_WDOG, 0, BD72720_INT_WDOG_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_SWRESET, 0, BD72720_INT_SWRESET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_SEQ_DONE, 1, BD72720_INT_SEQ_DONE_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_PGFAULT, 1, BD72720_INT_PGFAULT_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK1_DVS, 2, BD72720_INT_BUCK1_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK2_DVS, 2, BD72720_INT_BUCK2_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK3_DVS, 2, BD72720_INT_BUCK3_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK4_DVS, 2, BD72720_INT_BUCK4_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK5_DVS, 2, BD72720_INT_BUCK5_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK6_DVS, 2, BD72720_INT_BUCK6_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK7_DVS, 2, BD72720_INT_BUCK7_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK8_DVS, 2, BD72720_INT_BUCK8_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK9_DVS, 3, BD72720_INT_BUCK9_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BUCK10_DVS, 3, BD72720_INT_BUCK10_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_LDO1_DVS, 3, BD72720_INT_LDO1_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_LDO2_DVS, 3, BD72720_INT_LDO2_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_LDO3_DVS, 3, BD72720_INT_LDO3_DVS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_LDO4_DVS, 3, BD72720_INT_LDO4_DVS_MASK),
+
+ REGMAP_IRQ_REG(BD72720_INT_VBUS_RMV, 4, BD72720_INT_VBUS_RMV_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBUS_DET, 4, BD72720_INT_VBUS_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBUS_MON_RES, 4, BD72720_INT_VBUS_MON_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBUS_MON_DET, 4, BD72720_INT_VBUS_MON_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VSYS_MON_RES, 5, BD72720_INT_VSYS_MON_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VSYS_MON_DET, 5, BD72720_INT_VSYS_MON_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VSYS_UV_RES, 5, BD72720_INT_VSYS_UV_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VSYS_UV_DET, 5, BD72720_INT_VSYS_UV_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VSYS_LO_RES, 5, BD72720_INT_VSYS_LO_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VSYS_LO_DET, 5, BD72720_INT_VSYS_LO_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VSYS_OV_RES, 5, BD72720_INT_VSYS_OV_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VSYS_OV_DET, 5, BD72720_INT_VSYS_OV_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BAT_ILIM, 6, BD72720_INT_BAT_ILIM_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_CHG_DONE, 6, BD72720_INT_CHG_DONE_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_EXTEMP_TOUT, 6, BD72720_INT_EXTEMP_TOUT_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_CHG_WDT_EXP, 6, BD72720_INT_CHG_WDT_EXP_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BAT_MNT_OUT, 6, BD72720_INT_BAT_MNT_OUT_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BAT_MNT_IN, 6, BD72720_INT_BAT_MNT_IN_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_CHG_TRNS, 6, BD72720_INT_CHG_TRNS_MASK),
+
+ REGMAP_IRQ_REG(BD72720_INT_VBAT_MON_RES, 7, BD72720_INT_VBAT_MON_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBAT_MON_DET, 7, BD72720_INT_VBAT_MON_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBAT_SHT_RES, 7, BD72720_INT_VBAT_SHT_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBAT_SHT_DET, 7, BD72720_INT_VBAT_SHT_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBAT_LO_RES, 7, BD72720_INT_VBAT_LO_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBAT_LO_DET, 7, BD72720_INT_VBAT_LO_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBAT_OV_RES, 7, BD72720_INT_VBAT_OV_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VBAT_OV_DET, 7, BD72720_INT_VBAT_OV_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BAT_RMV, 8, BD72720_INT_BAT_RMV_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BAT_DET, 8, BD72720_INT_BAT_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_DBAT_DET, 8, BD72720_INT_DBAT_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_BAT_TEMP_TRNS, 8, BD72720_INT_BAT_TEMP_TRNS_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_LOBTMP_RES, 8, BD72720_INT_LOBTMP_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_LOBTMP_DET, 8, BD72720_INT_LOBTMP_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_OVBTMP_RES, 8, BD72720_INT_OVBTMP_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_OVBTMP_DET, 8, BD72720_INT_OVBTMP_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_OCUR1_RES, 9, BD72720_INT_OCUR1_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_OCUR1_DET, 9, BD72720_INT_OCUR1_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_OCUR2_RES, 9, BD72720_INT_OCUR2_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_OCUR2_DET, 9, BD72720_INT_OCUR2_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_OCUR3_RES, 9, BD72720_INT_OCUR3_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_OCUR3_DET, 9, BD72720_INT_OCUR3_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_CC_MON1_DET, 10, BD72720_INT_CC_MON1_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_CC_MON2_DET, 10, BD72720_INT_CC_MON2_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_CC_MON3_DET, 10, BD72720_INT_CC_MON3_DET_MASK),
+/*
+ * The GPIO1_IN and GPIO2_IN IRQs are generated from the PMIC's GPIO1 and GPIO2
+ * pins. Eg, they may be wired to other devices which can then use the PMIC as
+ * an interrupt controller. The GPIO1 and GPIO2 can have the IRQ type
+ * specified. All of the types (falling, rising, and both edges as well as low
+ * and high levels) are supported.
+ */
+ BD72720_TYPED_IRQ_REG(BD72720_INT_GPIO1_IN, 10, BD72720_INT_GPIO1_IN_MASK, 0),
+ BD72720_TYPED_IRQ_REG(BD72720_INT_GPIO2_IN, 10, BD72720_INT_GPIO2_IN_MASK, 1),
+ REGMAP_IRQ_REG(BD72720_INT_VF125_RES, 11, BD72720_INT_VF125_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VF125_DET, 11, BD72720_INT_VF125_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VF_RES, 11, BD72720_INT_VF_RES_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_VF_DET, 11, BD72720_INT_VF_DET_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_RTC0, 11, BD72720_INT_RTC0_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_RTC1, 11, BD72720_INT_RTC1_MASK),
+ REGMAP_IRQ_REG(BD72720_INT_RTC2, 11, BD72720_INT_RTC2_MASK),
+};
+
+static int bd72720_set_type_config(unsigned int **buf, unsigned int type,
+ const struct regmap_irq *irq_data,
+ int idx, void *irq_drv_data)
+{
+ const struct regmap_irq_type *t = &irq_data->type;
+
+ /*
+ * The regmap IRQ ecpects IRQ_TYPE_EDGE_BOTH to be written to register
+ * as logical OR of the type_falling_val and type_rising_val. This is
+ * not how the BD72720 implements this configuration, hence we need
+ * to handle this specific case separately.
+ */
+ if (type == IRQ_TYPE_EDGE_BOTH) {
+ buf[0][idx] &= ~t->type_reg_mask;
+ buf[0][idx] |= BD72720_GPIO_IRQ_TYPE_BOTH;
+
+ return 0;
+ }
+
+ return regmap_irq_set_type_config_simple(buf, type, irq_data, idx, irq_drv_data);
+}
+
static const struct regmap_irq_chip bd71828_irq_chip = {
.name = "bd71828_irq",
.main_status = BD71828_REG_INT_MAIN,
@@ -465,6 +829,28 @@ static const struct regmap_irq_chip bd71815_irq_chip = {
.irq_reg_stride = 1,
};
+static const unsigned int bd72720_irq_type_base[] = { BD72720_REG_GPIO1_CTRL };
+
+static const struct regmap_irq_chip bd72720_irq_chip = {
+ .name = "bd72720_irq",
+ .main_status = BD72720_REG_INT_LVL1_STAT,
+ .irqs = &bd72720_irqs[0],
+ .num_irqs = ARRAY_SIZE(bd72720_irqs),
+ .status_base = BD72720_REG_INT_PS1_STAT,
+ .unmask_base = BD72720_REG_INT_PS1_EN,
+ .config_base = &bd72720_irq_type_base[0],
+ .num_config_bases = 1,
+ .num_config_regs = 2,
+ .set_type_config = bd72720_set_type_config,
+ .ack_base = BD72720_REG_INT_PS1_STAT,
+ .init_ack_masked = true,
+ .num_regs = 12,
+ .num_main_regs = 1,
+ .sub_reg_offsets = &bd72720_sub_irq_offsets[0],
+ .num_main_status_bits = 8,
+ .irq_reg_stride = 1,
+};
+
static int set_clk_mode(struct device *dev, struct regmap *regmap,
int clkmode_reg)
{
@@ -511,11 +897,39 @@ static void bd71828_remove_poweroff(void *data)
pm_power_off = NULL;
}
+static struct regmap *bd72720_do_regmaps(struct i2c_client *i2c)
+{
+ struct bd72720_regmaps *maps;
+ struct i2c_client *secondary_i2c;
+
+ secondary_i2c = devm_i2c_new_dummy_device(&i2c->dev, i2c->adapter,
+ BD72720_SECONDARY_I2C_SLAVE);
+ if (IS_ERR(secondary_i2c)) {
+ dev_err_probe(&i2c->dev, PTR_ERR(secondary_i2c), "Failed to get secondary I2C\n");
+
+ return ERR_CAST(secondary_i2c);
+ }
+
+ maps = devm_kzalloc(&i2c->dev, sizeof(*maps), GFP_KERNEL);
+ if (!maps)
+ return ERR_PTR(-ENOMEM);
+
+ maps->map1_4b = devm_regmap_init_i2c(i2c, &bd72720_regmap_4b);
+ if (IS_ERR(maps->map1_4b))
+ return maps->map1_4b;
+
+ maps->map2_4c = devm_regmap_init_i2c(secondary_i2c, &bd72720_regmap_4c);
+ if (IS_ERR(maps->map2_4c))
+ return maps->map2_4c;
+
+ return devm_regmap_init(&i2c->dev, NULL, maps, &bd72720_wrapper_map_config);
+}
+
static int bd71828_i2c_probe(struct i2c_client *i2c)
{
struct regmap_irq_chip_data *irq_data;
int ret;
- struct regmap *regmap;
+ struct regmap *regmap = NULL;
const struct regmap_config *regmap_config;
const struct regmap_irq_chip *irqchip;
unsigned int chip_type;
@@ -523,6 +937,7 @@ static int bd71828_i2c_probe(struct i2c_client *i2c)
int cells;
int button_irq;
int clkmode_reg;
+ int main_lvl_mask_reg = 0, main_lvl_val = 0;
if (!i2c->irq) {
dev_err(&i2c->dev, "No IRQ configured\n");
@@ -554,15 +969,34 @@ static int bd71828_i2c_probe(struct i2c_client *i2c)
*/
button_irq = 0;
break;
+ case ROHM_CHIP_TYPE_BD72720:
+ {
+ mfd = bd72720_mfd_cells;
+ cells = ARRAY_SIZE(bd72720_mfd_cells);
+
+ regmap = bd72720_do_regmaps(i2c);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
+ "Failed to initialize Regmap\n");
+
+ irqchip = &bd72720_irq_chip;
+ clkmode_reg = BD72720_REG_OUT32K;
+ button_irq = BD72720_INT_SHORTPUSH;
+ main_lvl_mask_reg = BD72720_REG_INT_LVL1_EN;
+ main_lvl_val = BD72720_MASK_LVL1_EN_ALL;
+ break;
+ }
default:
dev_err(&i2c->dev, "Unknown device type");
return -EINVAL;
}
- regmap = devm_regmap_init_i2c(i2c, regmap_config);
- if (IS_ERR(regmap))
- return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
+ if (!regmap) {
+ regmap = devm_regmap_init_i2c(i2c, regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
"Failed to initialize Regmap\n");
+ }
ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
IRQF_ONESHOT, 0, irqchip, &irq_data);
@@ -573,6 +1007,20 @@ static int bd71828_i2c_probe(struct i2c_client *i2c)
dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n",
irqchip->num_irqs);
+ /*
+ * On some ICs the main IRQ register has corresponding mask register.
+ * This is not handled by the regmap IRQ. Let's enable all the main
+ * level IRQs here. Further writes to the main level MASK is not
+ * needed because masking is handled by the per IRQ 2.nd level MASK
+ * registers. 2.nd level masks are handled by the regmap IRQ.
+ */
+ if (main_lvl_mask_reg) {
+ ret = regmap_write(regmap, main_lvl_mask_reg, main_lvl_val);
+ if (ret) {
+ return dev_err_probe(&i2c->dev, ret,
+ "Failed to enable main level IRQs\n");
+ }
+ }
if (button_irq) {
ret = regmap_irq_get_virq(irq_data, button_irq);
if (ret < 0)
@@ -614,6 +1062,9 @@ static const struct of_device_id bd71828_of_match[] = {
}, {
.compatible = "rohm,bd71815",
.data = (void *)ROHM_CHIP_TYPE_BD71815,
+ }, {
+ .compatible = "rohm,bd72720",
+ .data = (void *)ROHM_CHIP_TYPE_BD72720,
},
{ },
};
diff --git a/drivers/power/supply/bd71828-power.c b/drivers/power/supply/bd71828-power.c
index f667baedeb77..438e220a9cb7 100644
--- a/drivers/power/supply/bd71828-power.c
+++ b/drivers/power/supply/bd71828-power.c
@@ -5,6 +5,7 @@
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd71815.h>
#include <linux/mfd/rohm-bd71828.h>
+#include <linux/mfd/rohm-bd72720.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
@@ -44,19 +45,21 @@
#define VBAT_LOW_TH 0x00D4
struct pwr_regs {
- u8 vbat_avg;
- u8 ibat;
- u8 ibat_avg;
- u8 btemp_vth;
- u8 chg_state;
- u8 bat_temp;
- u8 dcin_stat;
- u8 dcin_collapse_limit;
- u8 chg_set1;
- u8 chg_en;
- u8 vbat_alm_limit_u;
- u8 conf;
- u8 vdcin;
+ unsigned int vbat_avg;
+ unsigned int ibat;
+ unsigned int ibat_avg;
+ unsigned int btemp_vth;
+ unsigned int chg_state;
+ unsigned int bat_temp;
+ unsigned int dcin_stat;
+ unsigned int dcin_online_mask;
+ unsigned int dcin_collapse_limit;
+ unsigned int chg_set1;
+ unsigned int chg_en;
+ unsigned int vbat_alm_limit_u;
+ unsigned int conf;
+ unsigned int vdcin;
+ unsigned int vdcin_himask;
};
static const struct pwr_regs pwr_regs_bd71828 = {
@@ -67,12 +70,14 @@ static const struct pwr_regs pwr_regs_bd71828 = {
.chg_state = BD71828_REG_CHG_STATE,
.bat_temp = BD71828_REG_BAT_TEMP,
.dcin_stat = BD71828_REG_DCIN_STAT,
+ .dcin_online_mask = BD7182x_MASK_DCIN_DET,
.dcin_collapse_limit = BD71828_REG_DCIN_CLPS,
.chg_set1 = BD71828_REG_CHG_SET1,
.chg_en = BD71828_REG_CHG_EN,
.vbat_alm_limit_u = BD71828_REG_ALM_VBAT_LIMIT_U,
.conf = BD71828_REG_CONF,
.vdcin = BD71828_REG_VDCIN_U,
+ .vdcin_himask = BD7182x_MASK_VDCIN_U,
};
static const struct pwr_regs pwr_regs_bd71815 = {
@@ -85,6 +90,7 @@ static const struct pwr_regs pwr_regs_bd71815 = {
.chg_state = BD71815_REG_CHG_STATE,
.bat_temp = BD71815_REG_BAT_TEMP,
.dcin_stat = BD71815_REG_DCIN_STAT,
+ .dcin_online_mask = BD7182x_MASK_DCIN_DET,
.dcin_collapse_limit = BD71815_REG_DCIN_CLPS,
.chg_set1 = BD71815_REG_CHG_SET1,
.chg_en = BD71815_REG_CHG_SET1,
@@ -92,6 +98,31 @@ static const struct pwr_regs pwr_regs_bd71815 = {
.conf = BD71815_REG_CONF,
.vdcin = BD71815_REG_VM_DCIN_U,
+ .vdcin_himask = BD7182x_MASK_VDCIN_U,
+};
+
+static struct pwr_regs pwr_regs_bd72720 = {
+ .vbat_avg = BD72720_REG_VM_SA_VBAT_U,
+ .ibat = BD72720_REG_CC_CURCD_U,
+ .ibat_avg = BD72720_REG_CC_SA_CURCD_U,
+ .btemp_vth = BD72720_REG_VM_BTMP_U,
+ /*
+ * Note, state 0x40 IMP_CHK. not documented
+ * on other variants but was still handled in
+ * existing code. No memory traces as to why.
+ */
+ .chg_state = BD72720_REG_CHG_STATE,
+ .bat_temp = BD72720_REG_CHG_BAT_TEMP_STAT,
+ .dcin_stat = BD72720_REG_INT_VBUS_SRC,
+ .dcin_online_mask = BD72720_MASK_DCIN_DET,
+ .dcin_collapse_limit = -1, /* Automatic. Setting not supported */
+ .chg_set1 = BD72720_REG_CHG_SET_1,
+ .chg_en = BD72720_REG_CHG_EN,
+ /* 15mV note in data-sheet */
+ .vbat_alm_limit_u = BD72720_REG_ALM_VBAT_TH_U,
+ .conf = BD72720_REG_CONF, /* o XSTB, only PON. Seprate slave addr */
+ .vdcin = BD72720_REG_VM_VBUS_U, /* 10 bits not 11 as with other ICs */
+ .vdcin_himask = BD72720_MASK_VDCIN_U,
};
struct bd71828_power {
@@ -298,7 +329,7 @@ static int get_chg_online(struct bd71828_power *pwr, int *chg_online)
dev_err(pwr->dev, "Failed to read DCIN status\n");
return ret;
}
- *chg_online = ((r & BD7182x_MASK_DCIN_DET) != 0);
+ *chg_online = ((r & pwr->regs->dcin_online_mask) != 0);
return 0;
}
@@ -329,8 +360,8 @@ static int bd71828_bat_inserted(struct bd71828_power *pwr)
ret = val & BD7182x_MASK_CONF_PON;
if (ret)
- regmap_update_bits(pwr->regmap, pwr->regs->conf,
- BD7182x_MASK_CONF_PON, 0);
+ if (regmap_update_bits(pwr->regmap, pwr->regs->conf, BD7182x_MASK_CONF_PON, 0))
+ dev_err(pwr->dev, "Failed to write CONF register\n");
return ret;
}
@@ -358,11 +389,13 @@ static int bd71828_init_hardware(struct bd71828_power *pwr)
int ret;
/* TODO: Collapse limit should come from device-tree ? */
- ret = regmap_write(pwr->regmap, pwr->regs->dcin_collapse_limit,
- BD7182x_DCIN_COLLAPSE_DEFAULT);
- if (ret) {
- dev_err(pwr->dev, "Failed to write DCIN collapse limit\n");
- return ret;
+ if (pwr->regs->dcin_collapse_limit != (unsigned int)-1) {
+ ret = regmap_write(pwr->regmap, pwr->regs->dcin_collapse_limit,
+ BD7182x_DCIN_COLLAPSE_DEFAULT);
+ if (ret) {
+ dev_err(pwr->dev, "Failed to write DCIN collapse limit\n");
+ return ret;
+ }
}
ret = pwr->bat_inserted(pwr);
@@ -419,7 +452,7 @@ static int bd71828_charger_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = bd7182x_read16_himask(pwr, pwr->regs->vdcin,
- BD7182x_MASK_VDCIN_U, &tmp);
+ pwr->regs->vdcin_himask, &tmp);
if (ret)
return ret;
@@ -630,6 +663,9 @@ BD_ISR_AC(dcin_ovp_det, "DCIN OVER VOLTAGE", true)
BD_ISR_DUMMY(dcin_mon_det, "DCIN voltage below threshold")
BD_ISR_DUMMY(dcin_mon_res, "DCIN voltage above threshold")
+BD_ISR_DUMMY(vbus_curr_limit, "VBUS current limited")
+BD_ISR_DUMMY(vsys_ov_res, "VSYS over-voltage cleared")
+BD_ISR_DUMMY(vsys_ov_det, "VSYS over-voltage")
BD_ISR_DUMMY(vsys_uv_res, "VSYS under-voltage cleared")
BD_ISR_DUMMY(vsys_uv_det, "VSYS under-voltage")
BD_ISR_DUMMY(vsys_low_res, "'VSYS low' cleared")
@@ -878,6 +914,51 @@ static int bd7182x_get_irqs(struct platform_device *pdev,
BDIRQ("bd71828-temp-125-over", bd71828_temp_vf125_det),
BDIRQ("bd71828-temp-125-under", bd71828_temp_vf125_res),
};
+ static const struct bd7182x_irq_res bd72720_irqs[] = {
+ BDIRQ("bd72720_int_vbus_rmv", BD_ISR_NAME(dcin_removed)),
+ BDIRQ("bd72720_int_vbus_det", bd7182x_dcin_detected),
+ BDIRQ("bd72720_int_vbus_mon_res", BD_ISR_NAME(dcin_mon_res)),
+ BDIRQ("bd72720_int_vbus_mon_det", BD_ISR_NAME(dcin_mon_det)),
+ BDIRQ("bd72720_int_vsys_mon_res", BD_ISR_NAME(vsys_mon_res)),
+ BDIRQ("bd72720_int_vsys_mon_det", BD_ISR_NAME(vsys_mon_det)),
+ BDIRQ("bd72720_int_vsys_uv_res", BD_ISR_NAME(vsys_uv_res)),
+ BDIRQ("bd72720_int_vsys_uv_det", BD_ISR_NAME(vsys_uv_det)),
+ BDIRQ("bd72720_int_vsys_lo_res", BD_ISR_NAME(vsys_low_res)),
+ BDIRQ("bd72720_int_vsys_lo_det", BD_ISR_NAME(vsys_low_det)),
+ BDIRQ("bd72720_int_vsys_ov_res", BD_ISR_NAME(vsys_ov_res)),
+ BDIRQ("bd72720_int_vsys_ov_det", BD_ISR_NAME(vsys_ov_det)),
+ BDIRQ("bd72720_int_bat_ilim", BD_ISR_NAME(vbus_curr_limit)),
+ BDIRQ("bd72720_int_chg_done", bd718x7_chg_done),
+ BDIRQ("bd72720_int_extemp_tout", BD_ISR_NAME(chg_wdg_temp)),
+ BDIRQ("bd72720_int_chg_wdt_exp", BD_ISR_NAME(chg_wdg)),
+ BDIRQ("bd72720_int_bat_mnt_out", BD_ISR_NAME(rechg_res)),
+ BDIRQ("bd72720_int_bat_mnt_in", BD_ISR_NAME(rechg_det)),
+ BDIRQ("bd72720_int_chg_trns", BD_ISR_NAME(chg_state_changed)),
+
+ BDIRQ("bd72720_int_vbat_mon_res", BD_ISR_NAME(bat_mon_res)),
+ BDIRQ("bd72720_int_vbat_mon_det", BD_ISR_NAME(bat_mon)),
+ BDIRQ("bd72720_int_vbat_sht_res", BD_ISR_NAME(bat_short_res)),
+ BDIRQ("bd72720_int_vbat_sht_det", BD_ISR_NAME(bat_short)),
+ BDIRQ("bd72720_int_vbat_lo_res", BD_ISR_NAME(bat_low_res)),
+ BDIRQ("bd72720_int_vbat_lo_det", BD_ISR_NAME(bat_low)),
+ BDIRQ("bd72720_int_vbat_ov_res", BD_ISR_NAME(bat_ov_res)),
+ BDIRQ("bd72720_int_vbat_ov_det", BD_ISR_NAME(bat_ov)),
+ BDIRQ("bd72720_int_bat_rmv", BD_ISR_NAME(bat_removed)),
+ BDIRQ("bd72720_int_bat_det", BD_ISR_NAME(bat_det)),
+ BDIRQ("bd72720_int_dbat_det", BD_ISR_NAME(bat_dead)),
+ BDIRQ("bd72720_int_bat_temp_trns", BD_ISR_NAME(temp_transit)),
+ BDIRQ("bd72720_int_lobtmp_res", BD_ISR_NAME(temp_bat_low_res)),
+ BDIRQ("bd72720_int_lobtmp_det", BD_ISR_NAME(temp_bat_low)),
+ BDIRQ("bd72720_int_ovbtmp_res", BD_ISR_NAME(temp_bat_hi_res)),
+ BDIRQ("bd72720_int_ovbtmp_det", BD_ISR_NAME(temp_bat_hi)),
+ BDIRQ("bd72720_int_ocur1_res", BD_ISR_NAME(bat_oc1_res)),
+ BDIRQ("bd72720_int_ocur1_det", BD_ISR_NAME(bat_oc1)),
+ BDIRQ("bd72720_int_ocur2_res", BD_ISR_NAME(bat_oc2_res)),
+ BDIRQ("bd72720_int_ocur2_det", BD_ISR_NAME(bat_oc2)),
+ BDIRQ("bd72720_int_ocur3_res", BD_ISR_NAME(bat_oc3_res)),
+ BDIRQ("bd72720_int_ocur3_det", BD_ISR_NAME(bat_oc3)),
+ BDIRQ("bd72720_int_cc_mon2_det", BD_ISR_NAME(bat_cc_mon)),
+ };
int num_irqs;
const struct bd7182x_irq_res *irqs;
@@ -890,6 +971,10 @@ static int bd7182x_get_irqs(struct platform_device *pdev,
irqs = &bd71815_irqs[0];
num_irqs = ARRAY_SIZE(bd71815_irqs);
break;
+ case ROHM_CHIP_TYPE_BD72720:
+ irqs = &bd72720_irqs[0];
+ num_irqs = ARRAY_SIZE(bd72720_irqs);
+ break;
default:
return -EINVAL;
}
@@ -958,21 +1043,27 @@ static int bd71828_power_probe(struct platform_device *pdev)
struct power_supply_config ac_cfg = {};
struct power_supply_config bat_cfg = {};
int ret;
- struct regmap *regmap;
-
- regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!regmap) {
- dev_err(&pdev->dev, "No parent regmap\n");
- return -EINVAL;
- }
pwr = devm_kzalloc(&pdev->dev, sizeof(*pwr), GFP_KERNEL);
if (!pwr)
return -ENOMEM;
- pwr->regmap = regmap;
- pwr->dev = &pdev->dev;
+ /*
+ * The BD72720 MFD device registers two regmaps. Power-supply driver
+ * uses the "wrap-map", which provides access to both of the I2C slave
+ * addresses used by the BD72720
+ */
pwr->chip_type = platform_get_device_id(pdev)->driver_data;
+ if (pwr->chip_type != ROHM_CHIP_TYPE_BD72720)
+ pwr->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ else
+ pwr->regmap = dev_get_regmap(pdev->dev.parent, "wrap-map");
+ if (!pwr->regmap) {
+ dev_err(&pdev->dev, "No parent regmap\n");
+ return -EINVAL;
+ }
+
+ pwr->dev = &pdev->dev;
switch (pwr->chip_type) {
case ROHM_CHIP_TYPE_BD71828:
@@ -985,6 +1076,12 @@ static int bd71828_power_probe(struct platform_device *pdev)
pwr->get_temp = bd71815_get_temp;
pwr->regs = &pwr_regs_bd71815;
break;
+ case ROHM_CHIP_TYPE_BD72720:
+ pwr->bat_inserted = bd71828_bat_inserted;
+ pwr->regs = &pwr_regs_bd72720;
+ pwr->get_temp = bd71828_get_temp;
+ dev_dbg(pwr->dev, "Found ROHM BD72720\n");
+ break;
default:
dev_err(pwr->dev, "Unknown PMIC\n");
return -EINVAL;
@@ -1030,6 +1127,7 @@ static int bd71828_power_probe(struct platform_device *pdev)
static const struct platform_device_id bd71828_charger_id[] = {
{ "bd71815-power", ROHM_CHIP_TYPE_BD71815 },
{ "bd71828-power", ROHM_CHIP_TYPE_BD71828 },
+ { "bd72720-power", ROHM_CHIP_TYPE_BD72720 },
{ },
};
MODULE_DEVICE_TABLE(platform, bd71828_charger_id);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index d2335276cce5..003bd938c84a 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -241,13 +241,13 @@ config REGULATOR_BD71815
will be called bd71815-regulator.
config REGULATOR_BD71828
- tristate "ROHM BD71828 Power Regulator"
+ tristate "ROHM BD71828, BD72720 and BD73900 Power Regulators"
depends on MFD_ROHM_BD71828
select REGULATOR_ROHM
help
- This driver supports voltage regulators on ROHM BD71828 PMIC.
- This will enable support for the software controllable buck
- and LDO regulators.
+ This driver supports voltage regulators on ROHM BD71828,
+ BD71879, BD72720 and BD73900 PMICs. This will enable
+ support for the software controllable buck and LDO regulators.
This driver can also be built as a module. If so, the module
will be called bd71828-regulator.
diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c
index 87de87793fa1..c8f3343cfe23 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -3,12 +3,15 @@
// bd71828-regulator.c ROHM BD71828GW-DS1 regulator driver
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd71828.h>
+#include <linux/mfd/rohm-bd72720.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -16,6 +19,7 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#define BD72720_MASK_LDON_HEAD GENMASK(2, 0)
struct reg_init {
unsigned int reg;
unsigned int mask;
@@ -28,7 +32,7 @@ struct bd71828_regulator_data {
int reg_init_amnt;
};
-static const struct reg_init buck1_inits[] = {
+static const struct reg_init bd71828_buck1_inits[] = {
/*
* DVS Buck voltages can be changed by register values or via GPIO.
* Use register accesses by default.
@@ -40,7 +44,7 @@ static const struct reg_init buck1_inits[] = {
},
};
-static const struct reg_init buck2_inits[] = {
+static const struct reg_init bd71828_buck2_inits[] = {
{
.reg = BD71828_REG_PS_CTRL_1,
.mask = BD71828_MASK_DVS_BUCK2_CTRL,
@@ -48,7 +52,7 @@ static const struct reg_init buck2_inits[] = {
},
};
-static const struct reg_init buck6_inits[] = {
+static const struct reg_init bd71828_buck6_inits[] = {
{
.reg = BD71828_REG_PS_CTRL_1,
.mask = BD71828_MASK_DVS_BUCK6_CTRL,
@@ -56,7 +60,7 @@ static const struct reg_init buck6_inits[] = {
},
};
-static const struct reg_init buck7_inits[] = {
+static const struct reg_init bd71828_buck7_inits[] = {
{
.reg = BD71828_REG_PS_CTRL_1,
.mask = BD71828_MASK_DVS_BUCK7_CTRL,
@@ -64,6 +68,26 @@ static const struct reg_init buck7_inits[] = {
},
};
+#define BD72720_MASK_DVS_BUCK1_CTRL BIT(4)
+#define BD72720_MASK_DVS_LDO1_CTRL BIT(5)
+
+static const struct reg_init bd72720_buck1_inits[] = {
+ {
+ .reg = BD72720_REG_PS_CTRL_2,
+ .mask = BD72720_MASK_DVS_BUCK1_CTRL,
+ .val = 0, /* Disable "run-level" control */
+ },
+};
+
+static const struct reg_init bd72720_ldo1_inits[] = {
+ {
+ .reg = BD72720_REG_PS_CTRL_2,
+ .mask = BD72720_MASK_DVS_LDO1_CTRL,
+ .val = 0, /* Disable "run-level" control */
+ },
+};
+
+/* BD71828 Buck voltages */
static const struct linear_range bd71828_buck1267_volts[] = {
REGULATOR_LINEAR_RANGE(500000, 0x00, 0xef, 6250),
REGULATOR_LINEAR_RANGE(2000000, 0xf0, 0xff, 0),
@@ -84,13 +108,79 @@ static const struct linear_range bd71828_buck5_volts[] = {
REGULATOR_LINEAR_RANGE(3300000, 0x10, 0x1f, 0),
};
+/* BD71828 LDO voltages */
static const struct linear_range bd71828_ldo_volts[] = {
REGULATOR_LINEAR_RANGE(800000, 0x00, 0x31, 50000),
REGULATOR_LINEAR_RANGE(3300000, 0x32, 0x3f, 0),
};
+/* BD72720 Buck voltages */
+static const struct linear_range bd72720_buck1234_volts[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x00, 0xc0, 6250),
+ REGULATOR_LINEAR_RANGE(1700000, 0xc1, 0xff, 0),
+};
+
+static const struct linear_range bd72720_buck589_volts[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x00, 0x78, 10000),
+ REGULATOR_LINEAR_RANGE(1700000, 0x79, 0xff, 0),
+};
+
+static const struct linear_range bd72720_buck67_volts[] = {
+ REGULATOR_LINEAR_RANGE(1500000, 0x00, 0xb4, 10000),
+ REGULATOR_LINEAR_RANGE(3300000, 0xb5, 0xff, 0),
+};
+
+/*
+ * The BUCK10 on BD72720 has two modes of operation, depending on a LDON_HEAD
+ * setting. When LDON_HEAD is 0x0, the behaviour is as with other bucks, eg.
+ * voltage can be set to a values indicated below using the VSEL register.
+ *
+ * However, when LDON_HEAD is set to 0x1 ... 0x7, BUCK 10 voltage is, according
+ * to the data-sheet, "automatically adjusted following LDON_HEAD setting and
+ * clamped to BUCK10_VID setting".
+ *
+ * Again, reading the data-sheet shows a "typical connection" where the BUCK10
+ * is used to supply the LDOs 1-4. My assumption is that in practice, this
+ * means that the BUCK10 voltage will be adjusted based on the maximum output
+ * of the LDO 1-4 (to minimize power loss). This makes sense.
+ *
+ * Auto-adjusting regulators aren't something I really like to model in the
+ * driver though - and, if the auto-adjustment works as intended, then there
+ * should really be no need to software to care about the buck10 voltages.
+ * If enable/disable control is still needed, we can implement buck10 as a
+ * regulator with only the enable/disable ops - and device-tree can be used
+ * to model the supply-relations. I believe this could allow the regulator
+ * framework to automagically disable the BUCK10 if all LDOs that are being
+ * supplied by it are disabled.
+ */
+static const struct linear_range bd72720_buck10_volts[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x00, 0xc0, 6250),
+ REGULATOR_LINEAR_RANGE(1700000, 0xc1, 0xff, 0),
+};
+
+/* BD72720 LDO voltages */
+static const struct linear_range bd72720_ldo1234_volts[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x00, 0x50, 6250),
+ REGULATOR_LINEAR_RANGE(1000000, 0x51, 0x7f, 0),
+};
+
+static const struct linear_range bd72720_ldo57891011_volts[] = {
+ REGULATOR_LINEAR_RANGE(750000, 0x00, 0xff, 10000),
+};
+
+static const struct linear_range bd72720_ldo6_volts[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0x00, 0x78, 10000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x79, 0x7f, 0),
+};
+
static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 10000, 20000 };
+/*
+ * BD72720 supports setting both the ramp-up and ramp-down values
+ * separately. Do we need to support ramp-down setting?
+ */
+static const unsigned int bd72720_ramp_delay[] = { 5000, 7500, 10000, 12500 };
+
static int buck_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
@@ -102,9 +192,9 @@ static int buck_set_hw_dvs_levels(struct device_node *np,
return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap);
}
-static int ldo6_parse_dt(struct device_node *np,
- const struct regulator_desc *desc,
- struct regulator_config *cfg)
+static int bd71828_ldo6_parse_dt(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *cfg)
{
int ret, i;
uint32_t uv = 0;
@@ -171,6 +261,24 @@ static const struct regulator_ops bd71828_ldo6_ops = {
.is_enabled = regulator_is_enabled_regmap,
};
+static const struct regulator_ops bd72720_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
+};
+
+static const struct regulator_ops bd72720_buck10_ldon_head_op = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_ramp_delay = regulator_set_ramp_delay_regmap,
+};
+
static const struct bd71828_regulator_data bd71828_rdata[] = {
{
.desc = {
@@ -212,8 +320,8 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
*/
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
- .reg_inits = buck1_inits,
- .reg_init_amnt = ARRAY_SIZE(buck1_inits),
+ .reg_inits = bd71828_buck1_inits,
+ .reg_init_amnt = ARRAY_SIZE(bd71828_buck1_inits),
},
{
.desc = {
@@ -253,8 +361,8 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
.lpsr_reg = BD71828_REG_BUCK2_SUSP_VOLT,
.lpsr_mask = BD71828_MASK_BUCK1267_VOLT,
},
- .reg_inits = buck2_inits,
- .reg_init_amnt = ARRAY_SIZE(buck2_inits),
+ .reg_inits = bd71828_buck2_inits,
+ .reg_init_amnt = ARRAY_SIZE(bd71828_buck2_inits),
},
{
.desc = {
@@ -399,8 +507,8 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
.lpsr_reg = BD71828_REG_BUCK6_SUSP_VOLT,
.lpsr_mask = BD71828_MASK_BUCK1267_VOLT,
},
- .reg_inits = buck6_inits,
- .reg_init_amnt = ARRAY_SIZE(buck6_inits),
+ .reg_inits = bd71828_buck6_inits,
+ .reg_init_amnt = ARRAY_SIZE(bd71828_buck6_inits),
},
{
.desc = {
@@ -440,8 +548,8 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
.lpsr_reg = BD71828_REG_BUCK7_SUSP_VOLT,
.lpsr_mask = BD71828_MASK_BUCK1267_VOLT,
},
- .reg_inits = buck7_inits,
- .reg_init_amnt = ARRAY_SIZE(buck7_inits),
+ .reg_inits = bd71828_buck7_inits,
+ .reg_init_amnt = ARRAY_SIZE(bd71828_buck7_inits),
},
{
.desc = {
@@ -633,7 +741,7 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
* LDO6 only supports enable/disable for all states.
* Voltage for LDO6 is fixed.
*/
- .of_parse_cb = ldo6_parse_dt,
+ .of_parse_cb = bd71828_ldo6_parse_dt,
},
}, {
.desc = {
@@ -677,22 +785,890 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
},
};
+#define BD72720_BUCK10_DESC_INDEX 10
+#define BD72720_NUM_BUCK_VOLTS 0x100
+#define BD72720_NUM_LDO_VOLTS 0x100
+#define BD72720_NUM_LDO12346_VOLTS 0x80
+
+static const struct bd71828_regulator_data bd72720_rdata[] = {
+ {
+ .desc = {
+ .name = "buck1",
+ .of_match = of_match_ptr("buck1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK1,
+ .type = REGULATOR_VOLTAGE,
+
+ /*
+ * The BD72720 BUCK1 and LDO1 support GPIO toggled
+ * sub-RUN states called RUN0, RUN1, RUN2 and RUN3.
+ * The "operating mode" (sub-RUN states or normal)
+ * can be changed by a register.
+ *
+ * When the sub-RUN states are used, the voltage and
+ * enable state depend on a state specific
+ * configuration. The voltage and enable configuration
+ * for BUCK1 and LDO1 can be defined for each sub-RUN
+ * state using BD72720_REG_[BUCK,LDO]1_VSEL_R[0,1,2,3]
+ * voltage selection registers and the bits
+ * BD72720_MASK_RUN_[0,1,2,3]_EN in the enable registers.
+ * The PMIC will change both the BUCK1 and LDO1 voltages
+ * to the states defined in these registers when
+ * "DVS GPIOs" are toggled.
+ *
+ * If RUN 0 .. RUN 4 states are to be used, the normal
+ * voltage configuration mechanisms do not apply
+ * and we should overwrite the ops and ignore the
+ * voltage setting/getting registers which are setup
+ * here. This is not supported for now. If you need
+ * this functionality, you may try merging functionality
+ * from a downstream driver:
+ * https://rohmsemiconductor.github.io/Linux-Kernel-PMIC-Drivers/BD72720/
+ */
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck1234_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck1234_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK1_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK1_VSEL_RB,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK1_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR, /* Deep idle in data-sheet */
+ .run_reg = BD72720_REG_BUCK1_VSEL_RB,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_reg = BD72720_REG_BUCK1_VSEL_I,
+ .idle_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_reg = BD72720_REG_BUCK1_VSEL_S,
+ .suspend_mask = BD72720_MASK_BUCK_VSEL,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_reg = BD72720_REG_BUCK1_VSEL_DI,
+ .lpsr_mask = BD72720_MASK_BUCK_VSEL,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ .reg_inits = bd72720_buck1_inits,
+ .reg_init_amnt = ARRAY_SIZE(bd72720_buck1_inits),
+ }, {
+ .desc = {
+ .name = "buck2",
+ .of_match = of_match_ptr("buck2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK2,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck1234_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck1234_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK2_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK2_VSEL_R,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK2_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_BUCK2_VSEL_R,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_reg = BD72720_REG_BUCK2_VSEL_I,
+ .idle_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_reg = BD72720_REG_BUCK2_VSEL_S,
+ .suspend_mask = BD72720_MASK_BUCK_VSEL,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_reg = BD72720_REG_BUCK2_VSEL_DI,
+ .lpsr_mask = BD72720_MASK_BUCK_VSEL,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "buck3",
+ .of_match = of_match_ptr("buck3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK3,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck1234_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck1234_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK3_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK3_VSEL_R,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK3_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_BUCK3_VSEL_R,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_reg = BD72720_REG_BUCK3_VSEL_I,
+ .idle_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_reg = BD72720_REG_BUCK3_VSEL_S,
+ .suspend_mask = BD72720_MASK_BUCK_VSEL,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_reg = BD72720_REG_BUCK3_VSEL_DI,
+ .lpsr_mask = BD72720_MASK_BUCK_VSEL,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "buck4",
+ .of_match = of_match_ptr("buck4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK4,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck1234_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck1234_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK4_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK4_VSEL_R,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK4_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_BUCK4_VSEL_R,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_reg = BD72720_REG_BUCK4_VSEL_I,
+ .idle_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_reg = BD72720_REG_BUCK4_VSEL_S,
+ .suspend_mask = BD72720_MASK_BUCK_VSEL,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_reg = BD72720_REG_BUCK4_VSEL_DI,
+ .lpsr_mask = BD72720_MASK_BUCK_VSEL,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "buck5",
+ .of_match = of_match_ptr("buck5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK5,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck589_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck589_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK5_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK5_VSEL,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK5_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_BUCK5_VSEL,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "buck6",
+ .of_match = of_match_ptr("buck6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK6,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck67_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck67_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK6_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK6_VSEL,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK6_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_BUCK6_VSEL,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "buck7",
+ .of_match = of_match_ptr("buck7"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK7,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck67_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck67_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK7_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK7_VSEL,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK7_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_BUCK7_VSEL,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "buck8",
+ .of_match = of_match_ptr("buck8"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK8,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck589_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck589_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK8_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK8_VSEL,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK8_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_BUCK8_VSEL,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "buck9",
+ .of_match = of_match_ptr("buck9"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK9,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck589_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck589_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK9_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK9_VSEL,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK9_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_BUCK9_VSEL,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "buck10",
+ .of_match = of_match_ptr("buck10"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_BUCK10,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_buck10_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_buck10_volts),
+ .n_voltages = BD72720_NUM_BUCK_VOLTS,
+ .enable_reg = BD72720_REG_BUCK10_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_BUCK10_VSEL,
+ .vsel_mask = BD72720_MASK_BUCK_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_BUCK10_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_BUCK10_VSEL,
+ .run_mask = BD72720_MASK_BUCK_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo1",
+ .of_match = of_match_ptr("ldo1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO1,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo1234_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo1234_volts),
+ .n_voltages = BD72720_NUM_LDO12346_VOLTS,
+ .enable_reg = BD72720_REG_LDO1_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO1_VSEL_RB,
+ .vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO1_MODE1,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO1_VSEL_RB,
+ .run_mask = BD72720_MASK_LDO12346_VSEL,
+ .idle_reg = BD72720_REG_LDO1_VSEL_I,
+ .idle_mask = BD72720_MASK_LDO12346_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_reg = BD72720_REG_LDO1_VSEL_S,
+ .suspend_mask = BD72720_MASK_LDO12346_VSEL,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_reg = BD72720_REG_LDO1_VSEL_DI,
+ .lpsr_mask = BD72720_MASK_LDO12346_VSEL,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ .reg_inits = bd72720_ldo1_inits,
+ .reg_init_amnt = ARRAY_SIZE(bd72720_ldo1_inits),
+ }, {
+ .desc = {
+ .name = "ldo2",
+ .of_match = of_match_ptr("ldo2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO2,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo1234_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo1234_volts),
+ .n_voltages = BD72720_NUM_LDO12346_VOLTS,
+ .enable_reg = BD72720_REG_LDO2_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO2_VSEL_R,
+ .vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO2_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO2_VSEL_R,
+ .run_mask = BD72720_MASK_LDO12346_VSEL,
+ .idle_reg = BD72720_REG_LDO2_VSEL_I,
+ .idle_mask = BD72720_MASK_LDO12346_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_reg = BD72720_REG_LDO2_VSEL_S,
+ .suspend_mask = BD72720_MASK_LDO12346_VSEL,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_reg = BD72720_REG_LDO2_VSEL_DI,
+ .lpsr_mask = BD72720_MASK_LDO12346_VSEL,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo3",
+ .of_match = of_match_ptr("ldo3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO3,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo1234_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo1234_volts),
+ .n_voltages = BD72720_NUM_LDO12346_VOLTS,
+ .enable_reg = BD72720_REG_LDO3_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO3_VSEL_R,
+ .vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO3_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO3_VSEL_R,
+ .run_mask = BD72720_MASK_LDO12346_VSEL,
+ .idle_reg = BD72720_REG_LDO3_VSEL_I,
+ .idle_mask = BD72720_MASK_LDO12346_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_reg = BD72720_REG_LDO3_VSEL_S,
+ .suspend_mask = BD72720_MASK_LDO12346_VSEL,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_reg = BD72720_REG_LDO3_VSEL_DI,
+ .lpsr_mask = BD72720_MASK_LDO12346_VSEL,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo4",
+ .of_match = of_match_ptr("ldo4"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO4,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo1234_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo1234_volts),
+ .n_voltages = BD72720_NUM_LDO12346_VOLTS,
+ .enable_reg = BD72720_REG_LDO4_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO4_VSEL_R,
+ .vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO4_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO4_VSEL_R,
+ .run_mask = BD72720_MASK_LDO12346_VSEL,
+ .idle_reg = BD72720_REG_LDO4_VSEL_I,
+ .idle_mask = BD72720_MASK_LDO12346_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_reg = BD72720_REG_LDO4_VSEL_S,
+ .suspend_mask = BD72720_MASK_LDO12346_VSEL,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_reg = BD72720_REG_LDO4_VSEL_DI,
+ .lpsr_mask = BD72720_MASK_LDO12346_VSEL,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo5",
+ .of_match = of_match_ptr("ldo5"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO5,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo57891011_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+ .n_voltages = BD72720_NUM_LDO_VOLTS,
+ .enable_reg = BD72720_REG_LDO5_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO5_VSEL,
+ .vsel_mask = BD72720_MASK_LDO_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO5_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO5_VSEL,
+ .run_mask = BD72720_MASK_LDO_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo6",
+ .of_match = of_match_ptr("ldo6"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO6,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo6_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo6_volts),
+ .n_voltages = BD72720_NUM_LDO12346_VOLTS,
+ .enable_reg = BD72720_REG_LDO6_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO6_VSEL,
+ .vsel_mask = BD72720_MASK_LDO12346_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO6_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO6_VSEL,
+ .run_mask = BD72720_MASK_LDO12346_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo7",
+ .of_match = of_match_ptr("ldo7"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO7,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo57891011_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+ .n_voltages = BD72720_NUM_LDO_VOLTS,
+ .enable_reg = BD72720_REG_LDO7_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO7_VSEL,
+ .vsel_mask = BD72720_MASK_LDO_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO7_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO7_VSEL,
+ .run_mask = BD72720_MASK_LDO_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo8",
+ .of_match = of_match_ptr("ldo8"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO8,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo57891011_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+ .n_voltages = BD72720_NUM_LDO_VOLTS,
+ .enable_reg = BD72720_REG_LDO8_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO8_VSEL,
+ .vsel_mask = BD72720_MASK_LDO_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO8_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO8_VSEL,
+ .run_mask = BD72720_MASK_LDO_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo9",
+ .of_match = of_match_ptr("ldo9"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO9,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo57891011_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+ .n_voltages = BD72720_NUM_LDO_VOLTS,
+ .enable_reg = BD72720_REG_LDO9_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO9_VSEL,
+ .vsel_mask = BD72720_MASK_LDO_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO9_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO9_VSEL,
+ .run_mask = BD72720_MASK_LDO_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo10",
+ .of_match = of_match_ptr("ldo10"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO10,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo57891011_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+ .n_voltages = BD72720_NUM_LDO_VOLTS,
+ .enable_reg = BD72720_REG_LDO10_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO10_VSEL,
+ .vsel_mask = BD72720_MASK_LDO_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO10_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO10_VSEL,
+ .run_mask = BD72720_MASK_LDO_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ }, {
+ .desc = {
+ .name = "ldo11",
+ .of_match = of_match_ptr("ldo11"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = BD72720_LDO11,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &bd72720_regulator_ops,
+ .linear_ranges = bd72720_ldo57891011_volts,
+ .n_linear_ranges = ARRAY_SIZE(bd72720_ldo57891011_volts),
+ .n_voltages = BD72720_NUM_LDO_VOLTS,
+ .enable_reg = BD72720_REG_LDO11_ON,
+ .enable_mask = BD72720_MASK_RUN_B_EN,
+ .vsel_reg = BD72720_REG_LDO11_VSEL,
+ .vsel_mask = BD72720_MASK_LDO_VSEL,
+
+ .ramp_delay_table = bd72720_ramp_delay,
+ .n_ramp_values = ARRAY_SIZE(bd72720_ramp_delay),
+ .ramp_reg = BD72720_REG_LDO11_MODE,
+ .ramp_mask = BD72720_MASK_RAMP_UP_DELAY,
+ .owner = THIS_MODULE,
+ .of_parse_cb = buck_set_hw_dvs_levels,
+ },
+ .dvs = {
+ .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
+ ROHM_DVS_LEVEL_SUSPEND |
+ ROHM_DVS_LEVEL_LPSR,
+ .run_reg = BD72720_REG_LDO11_VSEL,
+ .run_mask = BD72720_MASK_LDO_VSEL,
+ .idle_on_mask = BD72720_MASK_IDLE_EN,
+ .suspend_on_mask = BD72720_MASK_SUSPEND_EN,
+ .lpsr_on_mask = BD72720_MASK_DEEP_IDLE_EN,
+ },
+ },
+};
+
+static int bd72720_buck10_ldon_head_mode(struct device *dev,
+ struct device_node *npreg,
+ struct regmap *regmap,
+ struct regulator_desc *buck10_desc)
+{
+ struct device_node *np __free(device_node) =
+ of_get_child_by_name(npreg, "buck10");
+ uint32_t ldon_head;
+ int ldon_val;
+ int ret;
+
+ if (!np) {
+ dev_err(dev, "failed to find buck10 regulator node\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(np, "rohm,ldon-head-microvolt", &ldon_head);
+ if (ret == -EINVAL)
+ return 0;
+ if (ret)
+ return ret;
+
+ /*
+ * LDON_HEAD mode means the BUCK10 is used to supply LDOs 1-4 and
+ * the BUCK 10 voltage is automatically set to follow LDO 1-4
+ * settings. Thus the BUCK10 should not allow voltage [g/s]etting.
+ */
+ buck10_desc->ops = &bd72720_buck10_ldon_head_op;
+
+ ldon_val = ldon_head / 50000 + 1;
+ if (ldon_head > 300000) {
+ dev_warn(dev, "Unsupported LDON_HEAD, clamping to 300 mV\n");
+ ldon_val = 7;
+ }
+
+ return regmap_update_bits(regmap, BD72720_REG_LDO1_MODE2,
+ BD72720_MASK_LDON_HEAD, ldon_val);
+}
+
+static int bd72720_dt_parse(struct device *dev,
+ struct regulator_desc *buck10_desc,
+ struct regmap *regmap)
+{
+ struct device_node *nproot __free(device_node) =
+ of_get_child_by_name(dev->parent->of_node, "regulators");
+
+ if (!nproot) {
+ dev_err(dev, "failed to find regulators node\n");
+ return -ENODEV;
+ }
+
+ return bd72720_buck10_ldon_head_mode(dev, nproot, regmap, buck10_desc);
+}
+
static int bd71828_probe(struct platform_device *pdev)
{
- int i, j, ret;
+ int i, j, ret, num_regulators;
struct regulator_config config = {
.dev = pdev->dev.parent,
};
+ enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
+ struct bd71828_regulator_data *rdata;
config.regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!config.regmap)
return -ENODEV;
- for (i = 0; i < ARRAY_SIZE(bd71828_rdata); i++) {
+ switch (chip) {
+ case ROHM_CHIP_TYPE_BD72720:
+ rdata = devm_kmemdup(&pdev->dev, bd72720_rdata,
+ sizeof(bd72720_rdata), GFP_KERNEL);
+ if (!rdata)
+ return -ENOMEM;
+
+ ret = bd72720_dt_parse(&pdev->dev, &rdata[BD72720_BUCK10_DESC_INDEX].desc,
+ config.regmap);
+ if (ret)
+ return ret;
+
+ num_regulators = ARRAY_SIZE(bd72720_rdata);
+ break;
+
+ case ROHM_CHIP_TYPE_BD71828:
+ rdata = devm_kmemdup(&pdev->dev, bd71828_rdata,
+ sizeof(bd71828_rdata), GFP_KERNEL);
+ if (!rdata)
+ return -ENOMEM;
+
+ num_regulators = ARRAY_SIZE(bd71828_rdata);
+
+ break;
+ default:
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Unsupported device\n");
+ }
+
+ for (i = 0; i < num_regulators; i++) {
struct regulator_dev *rdev;
- const struct bd71828_regulator_data *rd;
+ struct bd71828_regulator_data *rd;
+
+ rd = &rdata[i];
- rd = &bd71828_rdata[i];
+ config.driver_data = rd;
rdev = devm_regulator_register(&pdev->dev,
&rd->desc, &config);
if (IS_ERR(rdev))
@@ -714,12 +1690,20 @@ static int bd71828_probe(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id bd71828_pmic_id[] = {
+ { "bd71828-pmic", ROHM_CHIP_TYPE_BD71828 },
+ { "bd72720-pmic", ROHM_CHIP_TYPE_BD72720 },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, bd71828_pmic_id);
+
static struct platform_driver bd71828_regulator = {
.driver = {
.name = "bd71828-pmic",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = bd71828_probe,
+ .id_table = bd71828_pmic_id,
};
module_platform_driver(bd71828_regulator);
@@ -727,4 +1711,3 @@ module_platform_driver(bd71828_regulator);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("BD71828 voltage regulator driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:bd71828-pmic");
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 50dc779f7f98..7ac18985e438 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -570,7 +570,8 @@ config RTC_DRV_BD70528
depends on MFD_ROHM_BD71828
help
If you say Y here you will get support for the RTC
- block on ROHM BD71815 and BD71828 Power Management IC.
+ block on ROHM BD71815, BD71828 and BD72720 Power
+ Management ICs.
This driver can also be built as a module. If so, the module
will be called rtc-bd70528.
diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index 954ac4ef53e8..4c8599761b2e 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -7,6 +7,7 @@
#include <linux/bcd.h>
#include <linux/mfd/rohm-bd71815.h>
#include <linux/mfd/rohm-bd71828.h>
+#include <linux/mfd/rohm-bd72720.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -262,13 +263,13 @@ static int bd70528_probe(struct platform_device *pdev)
/*
* See also BD718XX_ALM_EN_OFFSET:
- * This works for BD71828 and BD71815 as they have same offset
- * between ALM0 start and ALM0_MASK. If new ICs are to be
- * added this requires proper check as ALM0_MASK is not located
- * at the end of ALM0 block - but after all ALM blocks so if
- * amount of ALMs differ the offset to enable/disable is likely
- * to be incorrect and enable/disable must be given as own
- * reg address here.
+ * This works for BD71828, BD71815, and BD72720 as they all
+ * have same offset between the ALM0 start and the ALM0_MASK.
+ * If new ICs are to be added this requires proper check as
+ * the ALM0_MASK is not located at the end of ALM0 block -
+ * but after all ALM blocks. If amount of ALMs differ, the
+ * offset to enable/disable is likely to be incorrect and
+ * enable/disable must be given as own reg address here.
*/
bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START;
hour_reg = BD71815_REG_HOUR;
@@ -278,6 +279,11 @@ static int bd70528_probe(struct platform_device *pdev)
bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START;
hour_reg = BD71828_REG_RTC_HOUR;
break;
+ case ROHM_CHIP_TYPE_BD72720:
+ bd_rtc->reg_time_start = BD72720_REG_RTC_START;
+ bd_rtc->bd718xx_alm_block_start = BD72720_REG_RTC_ALM_START;
+ hour_reg = BD72720_REG_RTC_HOUR;
+ break;
default:
dev_err(&pdev->dev, "Unknown chip\n");
return -ENOENT;
@@ -337,6 +343,7 @@ static int bd70528_probe(struct platform_device *pdev)
static const struct platform_device_id bd718x7_rtc_id[] = {
{ "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },
{ "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 },
+ { "bd72720-rtc", ROHM_CHIP_TYPE_BD72720 },
{ },
};
MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id);