diff options
| author | Mark Brown <broonie@kernel.org> | 2026-02-05 03:07:58 +0300 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-02-05 03:07:58 +0300 |
| commit | 914809c666d6c96d130da4755daa5bb0a57f0e12 (patch) | |
| tree | 9412448ea5f713032d0c18f7664f073988d21a71 /drivers | |
| parent | 20c4701b75a3d6ce09d61e17125aefe77e7eb333 (diff) | |
| parent | fe8429a2717fc01082502b0adf680a50b230eff7 (diff) | |
| download | linux-914809c666d6c96d130da4755daa5bb0a57f0e12.tar.xz | |
Samsung S2MPG10 regulator and S2MPG11 PMIC drivers
Merge series from André Draszik <andre.draszik@linaro.org>:
This series extends the existing S2MPG10 PMIC driver to add support for
the regulators, and adds new S2MPG11 core and regulator drivers.
The patches are kept together in one series, due to S2MPG11 and its
regulators being very similar to S2MPG10.
The Samsung S2MPG11 PMIC is a Power Management IC for mobile
applications with buck converters, various LDOs, power meters, and
additional GPIO interfaces. It typically complements an S2MPG10 PMIC in
a main/sub configuration as the sub-PMIC and both are used on the
Google Pixel 6 and 6 Pro (oriole / raven).
A DT update for Oriole / Raven to enable these is required which I will
send out separately.
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/mfd/sec-acpm.c | 171 | ||||
| -rw-r--r-- | drivers/mfd/sec-common.c | 62 | ||||
| -rw-r--r-- | drivers/mfd/sec-core.h | 2 | ||||
| -rw-r--r-- | drivers/mfd/sec-irq.c | 150 | ||||
| -rw-r--r-- | drivers/regulator/s2mps11.c | 1186 | ||||
| -rw-r--r-- | drivers/rtc/rtc-s5m.c | 21 |
6 files changed, 1412 insertions, 180 deletions
diff --git a/drivers/mfd/sec-acpm.c b/drivers/mfd/sec-acpm.c index 36622069a788..537ea65685bf 100644 --- a/drivers/mfd/sec-acpm.c +++ b/drivers/mfd/sec-acpm.c @@ -13,6 +13,7 @@ #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/rtc.h> #include <linux/mfd/samsung/s2mpg10.h> +#include <linux/mfd/samsung/s2mpg11.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of.h> @@ -216,6 +217,155 @@ static const struct regmap_config s2mpg10_regmap_config_meter = { .cache_type = REGCACHE_FLAT, }; +static const struct regmap_range s2mpg11_common_registers[] = { + regmap_reg_range(0x00, 0x02), /* CHIP_ID_S, INT, INT_MASK */ + regmap_reg_range(0x0a, 0x0c), /* Speedy control */ + regmap_reg_range(0x1a, 0x27), /* Debug */ +}; + +static const struct regmap_range s2mpg11_common_ro_registers[] = { + regmap_reg_range(0x00, 0x01), /* CHIP_ID_S, INT */ + regmap_reg_range(0x25, 0x27), /* Debug */ +}; + +static const struct regmap_range s2mpg11_common_nonvolatile_registers[] = { + regmap_reg_range(0x00, 0x00), /* CHIP_ID_S */ + regmap_reg_range(0x02, 0x02), /* INT_MASK */ + regmap_reg_range(0x0a, 0x0c), /* Speedy control */ +}; + +static const struct regmap_range s2mpg11_common_precious_registers[] = { + regmap_reg_range(0x01, 0x01), /* INT */ +}; + +static const struct regmap_access_table s2mpg11_common_wr_table = { + .yes_ranges = s2mpg11_common_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg11_common_registers), + .no_ranges = s2mpg11_common_ro_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg11_common_ro_registers), +}; + +static const struct regmap_access_table s2mpg11_common_rd_table = { + .yes_ranges = s2mpg11_common_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg11_common_registers), +}; + +static const struct regmap_access_table s2mpg11_common_volatile_table = { + .no_ranges = s2mpg11_common_nonvolatile_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg11_common_nonvolatile_registers), +}; + +static const struct regmap_access_table s2mpg11_common_precious_table = { + .yes_ranges = s2mpg11_common_precious_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg11_common_precious_registers), +}; + +static const struct regmap_config s2mpg11_regmap_config_common = { + .name = "common", + .reg_bits = ACPM_ADDR_BITS, + .val_bits = 8, + .max_register = S2MPG11_COMMON_SPD_DEBUG4, + .wr_table = &s2mpg11_common_wr_table, + .rd_table = &s2mpg11_common_rd_table, + .volatile_table = &s2mpg11_common_volatile_table, + .precious_table = &s2mpg11_common_precious_table, + .num_reg_defaults_raw = S2MPG11_COMMON_SPD_DEBUG4 + 1, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_range s2mpg11_pmic_registers[] = { + regmap_reg_range(0x00, 0x5a), /* All PMIC registers */ + regmap_reg_range(0x5c, 0xb7), /* All PMIC registers */ +}; + +static const struct regmap_range s2mpg11_pmic_ro_registers[] = { + regmap_reg_range(0x00, 0x05), /* INTx */ + regmap_reg_range(0x0c, 0x0d), /* STATUS OFFSRC */ + regmap_reg_range(0x98, 0x98), /* GPIO input */ +}; + +static const struct regmap_range s2mpg11_pmic_nonvolatile_registers[] = { + regmap_reg_range(0x06, 0x0b), /* INTxM */ +}; + +static const struct regmap_range s2mpg11_pmic_precious_registers[] = { + regmap_reg_range(0x00, 0x05), /* INTx */ +}; + +static const struct regmap_access_table s2mpg11_pmic_wr_table = { + .yes_ranges = s2mpg11_pmic_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg11_pmic_registers), + .no_ranges = s2mpg11_pmic_ro_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg11_pmic_ro_registers), +}; + +static const struct regmap_access_table s2mpg11_pmic_rd_table = { + .yes_ranges = s2mpg11_pmic_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg11_pmic_registers), +}; + +static const struct regmap_access_table s2mpg11_pmic_volatile_table = { + .no_ranges = s2mpg11_pmic_nonvolatile_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg11_pmic_nonvolatile_registers), +}; + +static const struct regmap_access_table s2mpg11_pmic_precious_table = { + .yes_ranges = s2mpg11_pmic_precious_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg11_pmic_precious_registers), +}; + +static const struct regmap_config s2mpg11_regmap_config_pmic = { + .name = "pmic", + .reg_bits = ACPM_ADDR_BITS, + .val_bits = 8, + .max_register = S2MPG11_PMIC_LDO_SENSE2, + .wr_table = &s2mpg11_pmic_wr_table, + .rd_table = &s2mpg11_pmic_rd_table, + .volatile_table = &s2mpg11_pmic_volatile_table, + .precious_table = &s2mpg11_pmic_precious_table, + .num_reg_defaults_raw = S2MPG11_PMIC_LDO_SENSE2 + 1, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_range s2mpg11_meter_registers[] = { + regmap_reg_range(0x00, 0x3e), /* Meter config */ + regmap_reg_range(0x40, 0x8a), /* Meter data */ + regmap_reg_range(0x8d, 0x9c), /* Meter data */ +}; + +static const struct regmap_range s2mpg11_meter_ro_registers[] = { + regmap_reg_range(0x40, 0x9c), /* Meter data */ +}; + +static const struct regmap_access_table s2mpg11_meter_wr_table = { + .yes_ranges = s2mpg11_meter_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg11_meter_registers), + .no_ranges = s2mpg11_meter_ro_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg11_meter_ro_registers), +}; + +static const struct regmap_access_table s2mpg11_meter_rd_table = { + .yes_ranges = s2mpg11_meter_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg11_meter_registers), +}; + +static const struct regmap_access_table s2mpg11_meter_volatile_table = { + .yes_ranges = s2mpg11_meter_ro_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg11_meter_ro_registers), +}; + +static const struct regmap_config s2mpg11_regmap_config_meter = { + .name = "meter", + .reg_bits = ACPM_ADDR_BITS, + .val_bits = 8, + .max_register = S2MPG11_METER_LPF_DATA_NTC7_2, + .wr_table = &s2mpg11_meter_wr_table, + .rd_table = &s2mpg11_meter_rd_table, + .volatile_table = &s2mpg11_meter_volatile_table, + .num_reg_defaults_raw = S2MPG11_METER_LPF_DATA_NTC7_2 + 1, + .cache_type = REGCACHE_FLAT, +}; + struct sec_pmic_acpm_shared_bus_context { const struct acpm_handle *acpm; unsigned int acpm_chan_id; @@ -364,10 +514,12 @@ static int sec_pmic_acpm_probe(struct platform_device *pdev) if (IS_ERR(regmap_pmic)) return PTR_ERR(regmap_pmic); - regmap = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_RTC, - pdata->regmap_cfg_rtc, true); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + if (pdata->regmap_cfg_rtc) { + regmap = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_RTC, + pdata->regmap_cfg_rtc, true); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + } regmap = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_METER, pdata->regmap_cfg_meter, true); @@ -399,8 +551,18 @@ static const struct sec_pmic_acpm_platform_data s2mpg10_data = { .regmap_cfg_meter = &s2mpg10_regmap_config_meter, }; +static const struct sec_pmic_acpm_platform_data s2mpg11_data = { + .device_type = S2MPG11, + .acpm_chan_id = 2, + .speedy_channel = 1, + .regmap_cfg_common = &s2mpg11_regmap_config_common, + .regmap_cfg_pmic = &s2mpg11_regmap_config_pmic, + .regmap_cfg_meter = &s2mpg11_regmap_config_meter, +}; + static const struct of_device_id sec_pmic_acpm_of_match[] = { { .compatible = "samsung,s2mpg10-pmic", .data = &s2mpg10_data, }, + { .compatible = "samsung,s2mpg11-pmic", .data = &s2mpg11_data, }, { }, }; MODULE_DEVICE_TABLE(of, sec_pmic_acpm_of_match); @@ -408,6 +570,7 @@ MODULE_DEVICE_TABLE(of, sec_pmic_acpm_of_match); static struct platform_driver sec_pmic_acpm_driver = { .driver = { .name = "sec-pmic-acpm", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = pm_sleep_ptr(&sec_pmic_pm_ops), .of_match_table = sec_pmic_acpm_of_match, }, diff --git a/drivers/mfd/sec-common.c b/drivers/mfd/sec-common.c index 42d55e70e34c..bd8b5f968689 100644 --- a/drivers/mfd/sec-common.c +++ b/drivers/mfd/sec-common.c @@ -23,9 +23,13 @@ #include <linux/regmap.h> #include "sec-core.h" +static const struct resource s5m8767_rtc_resources[] = { + DEFINE_RES_IRQ_NAMED(S5M8767_IRQ_RTCA1, "alarm"), +}; + static const struct mfd_cell s5m8767_devs[] = { MFD_CELL_NAME("s5m8767-pmic"), - MFD_CELL_NAME("s5m-rtc"), + MFD_CELL_RES("s5m-rtc", s5m8767_rtc_resources), MFD_CELL_OF("s5m8767-clk", NULL, NULL, 0, 0, "samsung,s5m8767-clk"), }; @@ -33,50 +37,72 @@ static const struct mfd_cell s2dos05_devs[] = { MFD_CELL_NAME("s2dos05-regulator"), }; +static const struct resource s2mpg10_rtc_resources[] = { + DEFINE_RES_IRQ_NAMED(S2MPG10_IRQ_RTCA0, "alarm"), +}; + static const struct mfd_cell s2mpg10_devs[] = { MFD_CELL_NAME("s2mpg10-meter"), MFD_CELL_NAME("s2mpg10-regulator"), - MFD_CELL_NAME("s2mpg10-rtc"), + MFD_CELL_RES("s2mpg10-rtc", s2mpg10_rtc_resources), MFD_CELL_OF("s2mpg10-clk", NULL, NULL, 0, 0, "samsung,s2mpg10-clk"), MFD_CELL_OF("s2mpg10-gpio", NULL, NULL, 0, 0, "samsung,s2mpg10-gpio"), }; +static const struct mfd_cell s2mpg11_devs[] = { + MFD_CELL_NAME("s2mpg11-meter"), + MFD_CELL_NAME("s2mpg11-regulator"), + MFD_CELL_OF("s2mpg11-gpio", NULL, NULL, 0, 0, "samsung,s2mpg11-gpio"), +}; + +static const struct resource s2mps11_rtc_resources[] = { + DEFINE_RES_IRQ_NAMED(S2MPS11_IRQ_RTCA0, "alarm"), +}; + static const struct mfd_cell s2mps11_devs[] = { MFD_CELL_NAME("s2mps11-regulator"), - MFD_CELL_NAME("s2mps14-rtc"), + MFD_CELL_RES("s2mps14-rtc", s2mps11_rtc_resources), MFD_CELL_OF("s2mps11-clk", NULL, NULL, 0, 0, "samsung,s2mps11-clk"), }; +static const struct resource s2mps14_rtc_resources[] = { + DEFINE_RES_IRQ_NAMED(S2MPS14_IRQ_RTCA0, "alarm"), +}; + static const struct mfd_cell s2mps13_devs[] = { MFD_CELL_NAME("s2mps13-regulator"), - MFD_CELL_NAME("s2mps13-rtc"), + MFD_CELL_RES("s2mps13-rtc", s2mps14_rtc_resources), MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"), }; static const struct mfd_cell s2mps14_devs[] = { MFD_CELL_NAME("s2mps14-regulator"), - MFD_CELL_NAME("s2mps14-rtc"), + MFD_CELL_RES("s2mps14-rtc", s2mps14_rtc_resources), MFD_CELL_OF("s2mps14-clk", NULL, NULL, 0, 0, "samsung,s2mps14-clk"), }; static const struct mfd_cell s2mps15_devs[] = { MFD_CELL_NAME("s2mps15-regulator"), - MFD_CELL_NAME("s2mps15-rtc"), + MFD_CELL_RES("s2mps15-rtc", s2mps14_rtc_resources), MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"), }; static const struct mfd_cell s2mpa01_devs[] = { MFD_CELL_NAME("s2mpa01-pmic"), - MFD_CELL_NAME("s2mps14-rtc"), + MFD_CELL_RES("s2mps14-rtc", s2mps14_rtc_resources), }; static const struct mfd_cell s2mpu02_devs[] = { MFD_CELL_NAME("s2mpu02-regulator"), }; +static const struct resource s2mpu05_rtc_resources[] = { + DEFINE_RES_IRQ_NAMED(S2MPU05_IRQ_RTCA0, "alarm"), +}; + static const struct mfd_cell s2mpu05_devs[] = { MFD_CELL_NAME("s2mpu05-regulator"), - MFD_CELL_NAME("s2mps15-rtc"), + MFD_CELL_RES("s2mps15-rtc", s2mpu05_rtc_resources), }; static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic) @@ -84,8 +110,13 @@ static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic) unsigned int val; /* For s2mpg1x, the revision is in a different regmap */ - if (sec_pmic->device_type == S2MPG10) + switch (sec_pmic->device_type) { + case S2MPG10: + case S2MPG11: return; + default: + break; + } /* For each device type, the REG_ID is always the first register */ if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val)) @@ -143,6 +174,7 @@ sec_pmic_parse_dt_pdata(struct device *dev) int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq, struct regmap *regmap, struct i2c_client *client) { + struct regmap_irq_chip_data *irq_data; struct sec_platform_data *pdata; const struct mfd_cell *sec_devs; struct sec_pmic_dev *sec_pmic; @@ -167,9 +199,9 @@ int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq, sec_pmic->pdata = pdata; - ret = sec_irq_init(sec_pmic); - if (ret) - return ret; + irq_data = sec_irq_init(sec_pmic); + if (IS_ERR(irq_data)) + return PTR_ERR(irq_data); pm_runtime_set_active(sec_pmic->dev); @@ -190,6 +222,10 @@ int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq, sec_devs = s2mpg10_devs; num_sec_devs = ARRAY_SIZE(s2mpg10_devs); break; + case S2MPG11: + sec_devs = s2mpg11_devs; + num_sec_devs = ARRAY_SIZE(s2mpg11_devs); + break; case S2MPS11X: sec_devs = s2mps11_devs; num_sec_devs = ARRAY_SIZE(s2mps11_devs); @@ -220,7 +256,7 @@ int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq, sec_pmic->device_type); } ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, - NULL, 0, NULL); + NULL, 0, regmap_irq_get_domain(irq_data)); if (ret) return ret; diff --git a/drivers/mfd/sec-core.h b/drivers/mfd/sec-core.h index 92c7558ab8b0..8d85c70c2326 100644 --- a/drivers/mfd/sec-core.h +++ b/drivers/mfd/sec-core.h @@ -18,6 +18,6 @@ int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq, struct regmap *regmap, struct i2c_client *client); void sec_pmic_shutdown(struct device *dev); -int sec_irq_init(struct sec_pmic_dev *sec_pmic); +struct regmap_irq_chip_data *sec_irq_init(struct sec_pmic_dev *sec_pmic); #endif /* __SEC_CORE_INT_H */ diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index 74ac70002d1f..ee722fa35f3b 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -11,6 +11,7 @@ #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/irq.h> #include <linux/mfd/samsung/s2mpg10.h> +#include <linux/mfd/samsung/s2mpg11.h> #include <linux/mfd/samsung/s2mps11.h> #include <linux/mfd/samsung/s2mps14.h> #include <linux/mfd/samsung/s2mpu02.h> @@ -79,6 +80,64 @@ static const struct regmap_irq s2mpg10_pmic_irqs[] = { REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH7, 5, S2MPG10_IRQ_PWR_WARN_CH7_MASK), }; +static const struct regmap_irq s2mpg11_irqs[] = { + REGMAP_IRQ_REG(S2MPG11_COMMON_IRQ_PMIC, 0, S2MPG11_COMMON_INT_SRC_PMIC), + /* No documentation or other reference for remaining bits */ + REGMAP_IRQ_REG(S2MPG11_COMMON_IRQ_UNUSED, 0, GENMASK(7, 1)), +}; + +static const struct regmap_irq s2mpg11_pmic_irqs[] = { + REGMAP_IRQ_REG(S2MPG11_IRQ_PWRONF, 0, S2MPG11_IRQ_PWRONF_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PWRONR, 0, S2MPG11_IRQ_PWRONR_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PIF_TIMEOUT_MIF, 0, S2MPG11_IRQ_PIF_TIMEOUT_MIF_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PIF_TIMEOUTS, 0, S2MPG11_IRQ_PIF_TIMEOUTS_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_WTSR, 0, S2MPG11_IRQ_WTSR_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_SPD_ABNORMAL_STOP, 0, S2MPG11_IRQ_SPD_ABNORMAL_STOP_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_SPD_PARITY_ERR, 0, S2MPG11_IRQ_SPD_PARITY_ERR_MASK), + + REGMAP_IRQ_REG(S2MPG11_IRQ_140C, 1, S2MPG11_IRQ_INT140C_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_120C, 1, S2MPG11_IRQ_INT120C_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_TSD, 1, S2MPG11_IRQ_TSD_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_WRST, 1, S2MPG11_IRQ_WRST_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_NTC_CYCLE_DONE, 1, S2MPG11_IRQ_NTC_CYCLE_DONE_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PMETER_OVERF, 1, S2MPG11_IRQ_PMETER_OVERF_MASK), + + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B1S, 2, S2MPG11_IRQ_OCP_B1S_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B2S, 2, S2MPG11_IRQ_OCP_B2S_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B3S, 2, S2MPG11_IRQ_OCP_B3S_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B4S, 2, S2MPG11_IRQ_OCP_B4S_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B5S, 2, S2MPG11_IRQ_OCP_B5S_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B6S, 2, S2MPG11_IRQ_OCP_B6S_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B7S, 2, S2MPG11_IRQ_OCP_B7S_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B8S, 2, S2MPG11_IRQ_OCP_B8S_MASK), + + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B9S, 3, S2MPG11_IRQ_OCP_B9S_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_B10S, 3, S2MPG11_IRQ_OCP_B10S_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_BDS, 3, S2MPG11_IRQ_OCP_BDS_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_BAS, 3, S2MPG11_IRQ_OCP_BAS_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_OCP_BBS, 3, S2MPG11_IRQ_OCP_BBS_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_WLWP_ACC, 3, S2MPG11_IRQ_WLWP_ACC_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_SPD_SRP_PKT_RST, 3, S2MPG11_IRQ_SPD_SRP_PKT_RST_MASK), + + REGMAP_IRQ_REG(S2MPG11_IRQ_PWR_WARN_CH0, 4, S2MPG11_IRQ_PWR_WARN_CH0_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PWR_WARN_CH1, 4, S2MPG11_IRQ_PWR_WARN_CH1_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PWR_WARN_CH2, 4, S2MPG11_IRQ_PWR_WARN_CH2_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PWR_WARN_CH3, 4, S2MPG11_IRQ_PWR_WARN_CH3_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PWR_WARN_CH4, 4, S2MPG11_IRQ_PWR_WARN_CH4_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PWR_WARN_CH5, 4, S2MPG11_IRQ_PWR_WARN_CH5_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PWR_WARN_CH6, 4, S2MPG11_IRQ_PWR_WARN_CH6_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_PWR_WARN_CH7, 4, S2MPG11_IRQ_PWR_WARN_CH7_MASK), + + REGMAP_IRQ_REG(S2MPG11_IRQ_NTC_WARN_CH0, 5, S2MPG11_IRQ_NTC_WARN_CH0_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_NTC_WARN_CH1, 5, S2MPG11_IRQ_NTC_WARN_CH1_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_NTC_WARN_CH2, 5, S2MPG11_IRQ_NTC_WARN_CH2_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_NTC_WARN_CH3, 5, S2MPG11_IRQ_NTC_WARN_CH3_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_NTC_WARN_CH4, 5, S2MPG11_IRQ_NTC_WARN_CH4_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_NTC_WARN_CH5, 5, S2MPG11_IRQ_NTC_WARN_CH5_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_NTC_WARN_CH6, 5, S2MPG11_IRQ_NTC_WARN_CH6_MASK), + REGMAP_IRQ_REG(S2MPG11_IRQ_NTC_WARN_CH7, 5, S2MPG11_IRQ_NTC_WARN_CH7_MASK), +}; + static const struct regmap_irq s2mps11_irqs[] = { REGMAP_IRQ_REG(S2MPS11_IRQ_PWRONF, 0, S2MPS11_IRQ_PWRONF_MASK), REGMAP_IRQ_REG(S2MPS11_IRQ_PWRONR, 0, S2MPS11_IRQ_PWRONR_MASK), @@ -186,7 +245,7 @@ static const struct regmap_irq s5m8767_irqs[] = { REGMAP_IRQ_REG(S5M8767_IRQ_WTSR, 2, S5M8767_IRQ_WTSR_MASK), }; -/* All S2MPG10 interrupt sources are read-only and don't require clearing */ +/* All S2MPG1x interrupt sources are read-only and don't require clearing */ static const struct regmap_irq_chip s2mpg10_irq_chip = { .name = "s2mpg10", .status_base = S2MPG10_COMMON_INT, @@ -205,6 +264,25 @@ static const struct regmap_irq_chip s2mpg10_irq_chip_pmic = { .num_irqs = ARRAY_SIZE(s2mpg10_pmic_irqs), }; +static const struct regmap_irq_chip s2mpg11_irq_chip = { + .name = "s2mpg11", + .status_base = S2MPG11_COMMON_INT, + .mask_base = S2MPG11_COMMON_INT_MASK, + .num_regs = 1, + .irqs = s2mpg11_irqs, + .num_irqs = ARRAY_SIZE(s2mpg11_irqs), +}; + +static const struct regmap_irq_chip s2mpg11_irq_chip_pmic = { + .name = "s2mpg11-pmic", + .domain_suffix = "pmic", + .status_base = S2MPG11_PMIC_INT1, + .mask_base = S2MPG11_PMIC_INT1M, + .num_regs = 6, + .irqs = s2mpg11_pmic_irqs, + .num_irqs = ARRAY_SIZE(s2mpg11_pmic_irqs), +}; + static const struct regmap_irq_chip s2mps11_irq_chip = { .name = "s2mps11", .irqs = s2mps11_irqs, @@ -268,26 +346,28 @@ static const struct regmap_irq_chip s5m8767_irq_chip = { .ack_base = S5M8767_REG_INT1, }; -static int s2mpg1x_add_chained_irq_chip(struct device *dev, struct regmap *regmap, int pirq, - struct regmap_irq_chip_data *parent, - const struct regmap_irq_chip *chip, - struct regmap_irq_chip_data **data) +static struct regmap_irq_chip_data * +s2mpg1x_add_chained_pmic(struct sec_pmic_dev *sec_pmic, int pirq, + struct regmap_irq_chip_data *parent, const struct regmap_irq_chip *chip) { + struct device *dev = sec_pmic->dev; + struct regmap_irq_chip_data *data; int irq, ret; irq = regmap_irq_get_virq(parent, pirq); if (irq < 0) - return dev_err_probe(dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", pirq, - chip->name); + return dev_err_ptr_probe(dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", + pirq, chip->name); - ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT | IRQF_SHARED, 0, chip, data); + ret = devm_regmap_add_irq_chip(dev, sec_pmic->regmap_pmic, irq, + IRQF_ONESHOT | IRQF_SHARED, 0, chip, &data); if (ret) - return dev_err_probe(dev, ret, "Failed to add %s IRQ chip\n", chip->name); + return dev_err_ptr_probe(dev, ret, "Failed to add %s IRQ chip\n", chip->name); - return 0; + return data; } -static int sec_irq_init_s2mpg1x(struct sec_pmic_dev *sec_pmic) +static struct regmap_irq_chip_data *sec_irq_init_s2mpg1x(struct sec_pmic_dev *sec_pmic) { const struct regmap_irq_chip *irq_chip, *chained_irq_chip; struct regmap_irq_chip_data *irq_data; @@ -301,28 +381,33 @@ static int sec_irq_init_s2mpg1x(struct sec_pmic_dev *sec_pmic) chained_irq_chip = &s2mpg10_irq_chip_pmic; chained_pirq = S2MPG10_COMMON_IRQ_PMIC; break; + case S2MPG11: + irq_chip = &s2mpg11_irq_chip; + chained_irq_chip = &s2mpg11_irq_chip_pmic; + chained_pirq = S2MPG11_COMMON_IRQ_PMIC; + break; default: - return dev_err_probe(sec_pmic->dev, -EINVAL, "Unsupported device type %d\n", - sec_pmic->device_type); + return dev_err_ptr_probe(sec_pmic->dev, -EINVAL, "Unsupported device type %d\n", + sec_pmic->device_type); } regmap_common = dev_get_regmap(sec_pmic->dev, "common"); if (!regmap_common) - return dev_err_probe(sec_pmic->dev, -EINVAL, "No 'common' regmap %d\n", - sec_pmic->device_type); + return dev_err_ptr_probe(sec_pmic->dev, -EINVAL, "No 'common' regmap %d\n", + sec_pmic->device_type); ret = devm_regmap_add_irq_chip(sec_pmic->dev, regmap_common, sec_pmic->irq, IRQF_ONESHOT, 0, irq_chip, &irq_data); if (ret) - return dev_err_probe(sec_pmic->dev, ret, "Failed to add %s IRQ chip\n", - irq_chip->name); + return dev_err_ptr_probe(sec_pmic->dev, ret, "Failed to add %s IRQ chip\n", + irq_chip->name); - return s2mpg1x_add_chained_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic, chained_pirq, - irq_data, chained_irq_chip, &sec_pmic->irq_data); + return s2mpg1x_add_chained_pmic(sec_pmic, chained_pirq, irq_data, chained_irq_chip); } -int sec_irq_init(struct sec_pmic_dev *sec_pmic) +struct regmap_irq_chip_data *sec_irq_init(struct sec_pmic_dev *sec_pmic) { + struct regmap_irq_chip_data *sec_irq_chip_data; const struct regmap_irq_chip *sec_irq_chip; int ret; @@ -331,11 +416,12 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) sec_irq_chip = &s5m8767_irq_chip; break; case S2DOS05: - return 0; + return NULL; case S2MPA01: sec_irq_chip = &s2mps14_irq_chip; break; case S2MPG10: + case S2MPG11: return sec_irq_init_s2mpg1x(sec_pmic); case S2MPS11X: sec_irq_chip = &s2mps11_irq_chip; @@ -356,30 +442,22 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) sec_irq_chip = &s2mpu05_irq_chip; break; default: - return dev_err_probe(sec_pmic->dev, -EINVAL, - "Unsupported device type %d\n", - sec_pmic->device_type); + return dev_err_ptr_probe(sec_pmic->dev, -EINVAL, "Unsupported device type %d\n", + sec_pmic->device_type); } if (!sec_pmic->irq) { dev_warn(sec_pmic->dev, "No interrupt specified, no interrupts\n"); - return 0; + return NULL; } ret = devm_regmap_add_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic, sec_pmic->irq, IRQF_ONESHOT, - 0, sec_irq_chip, &sec_pmic->irq_data); + 0, sec_irq_chip, &sec_irq_chip_data); if (ret) - return dev_err_probe(sec_pmic->dev, ret, - "Failed to add %s IRQ chip\n", - sec_irq_chip->name); - - /* - * The rtc-s5m driver requests S2MPS14_IRQ_RTCA0 also for S2MPS11 - * so the interrupt number must be consistent. - */ - BUILD_BUG_ON(((enum s2mps14_irq)S2MPS11_IRQ_RTCA0) != S2MPS14_IRQ_RTCA0); + return dev_err_ptr_probe(sec_pmic->dev, ret, "Failed to add %s IRQ chip\n", + sec_irq_chip->name); - return 0; + return sec_irq_chip_data; } diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 04ae9c6150bd..2d5510acd078 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -3,6 +3,7 @@ // Copyright (c) 2012-2014 Samsung Electronics Co., Ltd // http://www.samsung.com +#include <dt-bindings/regulator/samsung,s2mpg10-regulator.h> #include <linux/bug.h> #include <linux/cleanup.h> #include <linux/err.h> @@ -16,6 +17,8 @@ #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/mfd/samsung/core.h> +#include <linux/mfd/samsung/s2mpg10.h> +#include <linux/mfd/samsung/s2mpg11.h> #include <linux/mfd/samsung/s2mps11.h> #include <linux/mfd/samsung/s2mps13.h> #include <linux/mfd/samsung/s2mps14.h> @@ -23,6 +26,11 @@ #include <linux/mfd/samsung/s2mpu02.h> #include <linux/mfd/samsung/s2mpu05.h> +enum { + S2MPG10_REGULATOR_OPS_STD, + S2MPG10_REGULATOR_OPS_EXTCONTROL, +}; + /* The highest number of possible regulators for supported devices. */ #define S2MPS_REGULATOR_MAX S2MPS13_REGULATOR_MAX struct s2mps11_info { @@ -40,12 +48,21 @@ struct s2mps11_info { * the suspend mode was enabled. */ DECLARE_BITMAP(suspend_state, S2MPS_REGULATOR_MAX); +}; - /* - * Array (size: number of regulators) with GPIO-s for external - * sleep control. - */ - struct gpio_desc **ext_control_gpiod; +#define to_s2mpg10_regulator_desc(x) container_of((x), struct s2mpg10_regulator_desc, desc) + +struct s2mpg10_regulator_desc { + struct regulator_desc desc; + + /* Ramp rate during enable, valid for bucks only. */ + unsigned int enable_ramp_rate; + + /* Registers for external control of rail. */ + unsigned int pctrlsel_reg; + unsigned int pctrlsel_mask; + /* Populated from DT. */ + unsigned int pctrlsel_val; }; static int get_ramp_delay(int ramp_delay) @@ -244,7 +261,7 @@ static int s2mps11_regulator_enable(struct regulator_dev *rdev) case S2MPS14X: if (test_bit(rdev_id, s2mps11->suspend_state)) val = S2MPS14_ENABLE_SUSPEND; - else if (s2mps11->ext_control_gpiod[rdev_id]) + else if (rdev->ena_pin) val = S2MPS14_ENABLE_EXT_CONTROL; else val = rdev->desc->enable_mask; @@ -334,6 +351,916 @@ static int s2mps11_regulator_set_suspend_disable(struct regulator_dev *rdev) rdev->desc->enable_mask, state); } +static int s2mps11_of_parse_gpiod(struct device_node *np, + const char *con_id, bool optional, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct gpio_desc *ena_gpiod; + int ret; + + ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(np), con_id, 0, + GPIOD_OUT_HIGH | + GPIOD_FLAGS_BIT_NONEXCLUSIVE, + desc->name + ? : dev_name(config->dev)); + if (IS_ERR(ena_gpiod)) { + ret = PTR_ERR(ena_gpiod); + + /* Ignore all errors except probe defer. */ + if (ret == -EPROBE_DEFER) + return ret; + + if (ret == -ENOENT) { + if (optional) + return 0; + + dev_info(config->dev, + "No entry for control GPIO for %d/%s in node %pOF\n", + desc->id, desc->name, np); + } else { + dev_warn_probe(config->dev, ret, + "Failed to get control GPIO for %d/%s in node %pOF\n", + desc->id, desc->name, np); + } + + return 0; + } + + dev_info(config->dev, "Using GPIO for ext-control over %d/%s\n", + desc->id, desc->name); + + config->ena_gpiod = ena_gpiod; + + return 0; +} + +static int s2mps11_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + const struct s2mps11_info *s2mps11 = config->driver_data; + + if (s2mps11->dev_type == S2MPS14X) + switch (desc->id) { + case S2MPS14_LDO10: + case S2MPS14_LDO11: + case S2MPS14_LDO12: + break; + + default: + return 0; + } + else + return 0; + + return s2mps11_of_parse_gpiod(np, "samsung,ext-control", false, desc, + config); +} + +static int s2mpg10_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + const struct s2mps11_info *s2mps11 = config->driver_data; + struct s2mpg10_regulator_desc *s2mpg10_desc = to_s2mpg10_regulator_desc(desc); + static const u32 ext_control_s2mpg10[] = { + [S2MPG10_EXTCTRL_PWREN] = S2MPG10_PCTRLSEL_PWREN, + [S2MPG10_EXTCTRL_PWREN_MIF] = S2MPG10_PCTRLSEL_PWREN_MIF, + [S2MPG10_EXTCTRL_AP_ACTIVE_N] = S2MPG10_PCTRLSEL_AP_ACTIVE_N, + [S2MPG10_EXTCTRL_CPUCL1_EN] = S2MPG10_PCTRLSEL_CPUCL1_EN, + [S2MPG10_EXTCTRL_CPUCL1_EN2] = S2MPG10_PCTRLSEL_CPUCL1_EN2, + [S2MPG10_EXTCTRL_CPUCL2_EN] = S2MPG10_PCTRLSEL_CPUCL2_EN, + [S2MPG10_EXTCTRL_CPUCL2_EN2] = S2MPG10_PCTRLSEL_CPUCL2_EN2, + [S2MPG10_EXTCTRL_TPU_EN] = S2MPG10_PCTRLSEL_TPU_EN, + [S2MPG10_EXTCTRL_TPU_EN2] = S2MPG10_PCTRLSEL_TPU_EN2, + [S2MPG10_EXTCTRL_TCXO_ON] = S2MPG10_PCTRLSEL_TCXO_ON, + [S2MPG10_EXTCTRL_TCXO_ON2] = S2MPG10_PCTRLSEL_TCXO_ON2, + [S2MPG10_EXTCTRL_LDO20M_EN2] = S2MPG10_PCTRLSEL_LDO20M_EN2, + [S2MPG10_EXTCTRL_LDO20M_EN] = S2MPG10_PCTRLSEL_LDO20M_EN, + }; + static const u32 ext_control_s2mpg11[] = { + [S2MPG11_EXTCTRL_PWREN] = S2MPG10_PCTRLSEL_PWREN, + [S2MPG11_EXTCTRL_PWREN_MIF] = S2MPG10_PCTRLSEL_PWREN_MIF, + [S2MPG11_EXTCTRL_AP_ACTIVE_N] = S2MPG10_PCTRLSEL_AP_ACTIVE_N, + [S2MPG11_EXTCTRL_G3D_EN] = S2MPG10_PCTRLSEL_CPUCL1_EN, + [S2MPG11_EXTCTRL_G3D_EN2] = S2MPG10_PCTRLSEL_CPUCL1_EN2, + [S2MPG11_EXTCTRL_AOC_VDD] = S2MPG10_PCTRLSEL_CPUCL2_EN, + [S2MPG11_EXTCTRL_AOC_RET] = S2MPG10_PCTRLSEL_CPUCL2_EN2, + [S2MPG11_EXTCTRL_UFS_EN] = S2MPG10_PCTRLSEL_TPU_EN, + [S2MPG11_EXTCTRL_LDO13S_EN] = S2MPG10_PCTRLSEL_TPU_EN2, + }; + u32 ext_control; + + if (s2mps11->dev_type != S2MPG10 && s2mps11->dev_type != S2MPG11) + return 0; + + if (of_property_read_u32(np, "samsung,ext-control", &ext_control)) + return 0; + + switch (s2mps11->dev_type) { + case S2MPG10: + switch (desc->id) { + case S2MPG10_BUCK1 ... S2MPG10_BUCK7: + case S2MPG10_BUCK10: + case S2MPG10_LDO3 ... S2MPG10_LDO19: + if (ext_control > S2MPG10_EXTCTRL_TCXO_ON2) + return -EINVAL; + break; + + case S2MPG10_LDO20: + if (ext_control < S2MPG10_EXTCTRL_LDO20M_EN2 || + ext_control > S2MPG10_EXTCTRL_LDO20M_EN) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + if (ext_control > ARRAY_SIZE(ext_control_s2mpg10)) + return -EINVAL; + ext_control = ext_control_s2mpg10[ext_control]; + break; + + case S2MPG11: + switch (desc->id) { + case S2MPG11_BUCK1 ... S2MPG11_BUCK3: + case S2MPG11_BUCK5: + case S2MPG11_BUCK8: + case S2MPG11_BUCK9: + case S2MPG11_BUCKD: + case S2MPG11_BUCKA: + case S2MPG11_LDO1: + case S2MPG11_LDO2: + case S2MPG11_LDO8: + case S2MPG11_LDO13: + if (ext_control > S2MPG11_EXTCTRL_LDO13S_EN) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + if (ext_control > ARRAY_SIZE(ext_control_s2mpg11)) + return -EINVAL; + ext_control = ext_control_s2mpg11[ext_control]; + break; + + default: + return -EINVAL; + } + + /* + * If the regulator should be configured for external control, then: + * 1) the PCTRLSELx register needs to be set accordingly + * 2) regulator_desc::enable_val needs to be: + * a) updated and + * b) written to the hardware + * 3) we switch to the ::ops that provide an empty ::enable() and no + * ::disable() implementations + * + * Points 1) and 2b) will be handled in _probe(), after + * devm_regulator_register() returns, so that we can properly act on + * failures, since the regulator core ignores most return values from + * this parse callback. + */ + s2mpg10_desc->pctrlsel_val = ext_control; + s2mpg10_desc->pctrlsel_val <<= (ffs(s2mpg10_desc->pctrlsel_mask) - 1); + + s2mpg10_desc->desc.enable_val = S2MPG10_PMIC_CTRL_ENABLE_EXT; + s2mpg10_desc->desc.enable_val <<= (ffs(desc->enable_mask) - 1); + + ++s2mpg10_desc->desc.ops; + + return s2mps11_of_parse_gpiod(np, "enable", true, desc, config); +} + +static int s2mpg10_enable_ext_control(struct s2mps11_info *s2mps11, + struct regulator_dev *rdev) +{ + const struct s2mpg10_regulator_desc *s2mpg10_desc; + int ret; + + switch (s2mps11->dev_type) { + case S2MPG10: + case S2MPG11: + s2mpg10_desc = to_s2mpg10_regulator_desc(rdev->desc); + break; + + default: + return 0; + } + + ret = regmap_update_bits(rdev_get_regmap(rdev), + s2mpg10_desc->pctrlsel_reg, + s2mpg10_desc->pctrlsel_mask, + s2mpg10_desc->pctrlsel_val); + if (ret) + return dev_err_probe(rdev_get_dev(rdev), ret, + "failed to configure pctrlsel for %s\n", + rdev->desc->name); + + /* + * When using external control, the enable bit of the regulator still + * needs to be set. The actual state will still be determined by the + * external signal. + */ + ret = regulator_enable_regmap(rdev); + if (ret) + return dev_err_probe(rdev_get_dev(rdev), ret, + "failed to enable regulator %s\n", + rdev->desc->name); + + return 0; +} + +static int s2mpg10_regulator_enable_nop(struct regulator_dev *rdev) +{ + /* + * We need to provide this, otherwise the regulator core's enable on + * this regulator will return a failure and subsequently disable our + * parent regulator. + */ + return 0; +} + +static int s2mpg10_regulator_buck_enable_time(struct regulator_dev *rdev) +{ + const struct s2mpg10_regulator_desc * const s2mpg10_desc = + to_s2mpg10_regulator_desc(rdev->desc); + const struct regulator_ops * const ops = rdev->desc->ops; + int vsel, curr_uV; + + vsel = ops->get_voltage_sel(rdev); + if (vsel < 0) + return vsel; + + curr_uV = ops->list_voltage(rdev, vsel); + if (curr_uV < 0) + return curr_uV; + + return (rdev->desc->enable_time + + DIV_ROUND_UP(curr_uV, s2mpg10_desc->enable_ramp_rate)); +} + +static int s2mpg1x_regulator_buck_set_voltage_time(struct regulator_dev *rdev, + int old_uV, int new_uV, + unsigned int ramp_reg, + unsigned int ramp_mask) +{ + unsigned int ramp_sel, ramp_rate; + int ret; + + if (old_uV == new_uV) + return 0; + + ret = regmap_read(rdev->regmap, ramp_reg, &ramp_sel); + if (ret) + return ret; + + ramp_sel &= ramp_mask; + ramp_sel >>= ffs(ramp_mask) - 1; + if (ramp_sel >= rdev->desc->n_ramp_values || + !rdev->desc->ramp_delay_table) + return -EINVAL; + + ramp_rate = rdev->desc->ramp_delay_table[ramp_sel]; + + return DIV_ROUND_UP(abs(new_uV - old_uV), ramp_rate); +} + +static int s2mpg10_regulator_buck_set_voltage_time(struct regulator_dev *rdev, + int old_uV, int new_uV) +{ + unsigned int ramp_reg; + + ramp_reg = rdev->desc->ramp_reg; + if (old_uV > new_uV) + /* The downwards ramp is at a different offset. */ + ramp_reg += S2MPG10_PMIC_DVS_RAMP4 - S2MPG10_PMIC_DVS_RAMP1; + + return s2mpg1x_regulator_buck_set_voltage_time(rdev, old_uV, new_uV, + ramp_reg, + rdev->desc->ramp_mask); +} + +static int s2mpg11_regulator_buck_set_voltage_time(struct regulator_dev *rdev, + int old_uV, int new_uV) +{ + unsigned int ramp_mask; + + ramp_mask = rdev->desc->ramp_mask; + if (old_uV > new_uV) + /* The downwards mask is at a different position. */ + ramp_mask >>= 2; + + return s2mpg1x_regulator_buck_set_voltage_time(rdev, old_uV, new_uV, + rdev->desc->ramp_reg, + ramp_mask); +} + +/* + * We assign both, ::set_voltage_time() and ::set_voltage_time_sel(), because + * only if the latter is != NULL, the regulator core will call neither during + * DVS if the regulator is disabled. If the latter is NULL, the core always + * calls the ::set_voltage_time() callback, which would give incorrect results + * if the regulator is off. + * At the same time, we do need ::set_voltage_time() due to differing upwards + * and downwards ramps and we can not make that code dependent on the regulator + * enable state, as that would break regulator_set_voltage_time() which + * expects a correct result no matter the enable state. + */ +static const struct regulator_ops s2mpg10_reg_buck_ops[] = { + [S2MPG10_REGULATOR_OPS_STD] = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .enable_time = s2mpg10_regulator_buck_enable_time, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time = s2mpg10_regulator_buck_set_voltage_time, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + }, + [S2MPG10_REGULATOR_OPS_EXTCONTROL] = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .enable = s2mpg10_regulator_enable_nop, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time = s2mpg10_regulator_buck_set_voltage_time, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + } +}; + +#define s2mpg10_buck_to_ramp_mask(n) (GENMASK(1, 0) << (((n) % 4) * 2)) + +/* + * The ramp_delay during enable is fixed (12.5mV/μs), while the ramp during + * DVS can be adjusted. Linux can adjust the ramp delay via DT, in which case + * the regulator core will modify the regulator's constraints and call our + * .set_ramp_delay() which updates the DVS ramp in ramp_reg. + * For enable, our .enable_time() unconditionally uses enable_ramp_rate + * (12.5mV/μs) while our ::set_voltage_time() takes the value in ramp_reg + * into account. + */ +#define regulator_desc_s2mpg1x_buck_cmn(_name, _id, _supply, _ops, \ + _vrange, _vsel_reg, _vsel_mask, _en_reg, _en_mask, \ + _r_reg, _r_mask, _r_table, _r_table_sz, \ + _en_time) { \ + .name = "buck" _name, \ + .supply_name = _supply, \ + .of_match = of_match_ptr("buck" _name), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = s2mpg10_of_parse_cb, \ + .id = _id, \ + .ops = &(_ops)[0], \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .linear_ranges = _vrange, \ + .n_linear_ranges = ARRAY_SIZE(_vrange), \ + .n_voltages = _vrange##_count, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .enable_reg = _en_reg, \ + .enable_mask = _en_mask, \ + .ramp_reg = _r_reg, \ + .ramp_mask = _r_mask, \ + .ramp_delay_table = _r_table, \ + .n_ramp_values = _r_table_sz, \ + .enable_time = _en_time, /* + V/enable_ramp_rate */ \ +} + +#define regulator_desc_s2mpg10_buck(_num, _vrange, _r_reg) \ + regulator_desc_s2mpg1x_buck_cmn(#_num "m", S2MPG10_BUCK##_num, \ + "vinb"#_num "m", s2mpg10_reg_buck_ops, _vrange, \ + S2MPG10_PMIC_B##_num##M_OUT1, GENMASK(7, 0), \ + S2MPG10_PMIC_B##_num##M_CTRL, GENMASK(7, 6), \ + S2MPG10_PMIC_##_r_reg, \ + s2mpg10_buck_to_ramp_mask(S2MPG10_BUCK##_num \ + - S2MPG10_BUCK1), \ + s2mpg10_buck_ramp_table, \ + ARRAY_SIZE(s2mpg10_buck_ramp_table), 30) + +#define s2mpg10_regulator_desc_buck_cm(_num, _vrange, _r_reg) \ + .desc = regulator_desc_s2mpg10_buck(_num, _vrange, _r_reg), \ + .enable_ramp_rate = 12500 + +#define s2mpg10_regulator_desc_buck_gpio(_num, _vrange, _r_reg, \ + _pc_reg, _pc_mask) \ + [S2MPG10_BUCK##_num] = { \ + s2mpg10_regulator_desc_buck_cm(_num, _vrange, _r_reg), \ + .pctrlsel_reg = S2MPG10_PMIC_##_pc_reg, \ + .pctrlsel_mask = _pc_mask, \ + } + +#define s2mpg10_regulator_desc_buck(_num, _vrange, _r_reg) \ + [S2MPG10_BUCK##_num] = { \ + s2mpg10_regulator_desc_buck_cm(_num, _vrange, _r_reg), \ + } + +/* ops for S2MPG1x LDO regulators without ramp control */ +static const struct regulator_ops s2mpg10_reg_ldo_ops[] = { + [S2MPG10_REGULATOR_OPS_STD] = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + }, + [S2MPG10_REGULATOR_OPS_EXTCONTROL] = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .enable = s2mpg10_regulator_enable_nop, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + } +}; + +/* ops for S2MPG1x LDO regulators that have ramp control */ +static const struct regulator_ops s2mpg10_reg_ldo_ramp_ops[] = { + [S2MPG10_REGULATOR_OPS_STD] = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + }, + [S2MPG10_REGULATOR_OPS_EXTCONTROL] = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .enable = s2mpg10_regulator_enable_nop, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + } +}; + +#define regulator_desc_s2mpg1x_ldo_cmn(_name, _id, _supply, _ops, \ + _vrange, _vsel_reg, _vsel_mask, _en_reg, _en_mask, \ + _ramp_delay, _r_reg, _r_mask, _r_table, _r_table_sz) { \ + .name = "ldo" _name, \ + .supply_name = _supply, \ + .of_match = of_match_ptr("ldo" _name), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = s2mpg10_of_parse_cb, \ + .id = _id, \ + .ops = &(_ops)[0], \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .linear_ranges = _vrange, \ + .n_linear_ranges = ARRAY_SIZE(_vrange), \ + .n_voltages = _vrange##_count, \ + .vsel_reg = _vsel_reg, \ + .vsel_mask = _vsel_mask, \ + .enable_reg = _en_reg, \ + .enable_mask = _en_mask, \ + .ramp_delay = _ramp_delay, \ + .ramp_reg = _r_reg, \ + .ramp_mask = _r_mask, \ + .ramp_delay_table = _r_table, \ + .n_ramp_values = _r_table_sz, \ + .enable_time = 130, /* startup 20+-10 + ramp 30..100μs */ \ +} + +#define s2mpg10_regulator_desc_ldo_cmn(_num, _supply, _ops, _vrange, \ + _vsel_reg_sfx, _vsel_mask, _en_reg, _en_mask, \ + _ramp_delay, _r_reg, _r_mask, _r_table, _r_table_sz, \ + _pc_reg, _pc_mask) \ + [S2MPG10_LDO##_num] = { \ + .desc = regulator_desc_s2mpg1x_ldo_cmn(#_num "m", \ + S2MPG10_LDO##_num, _supply, _ops, \ + _vrange, \ + S2MPG10_PMIC_L##_num##M_##_vsel_reg_sfx, \ + _vsel_mask, \ + S2MPG10_PMIC_##_en_reg, _en_mask, \ + _ramp_delay, _r_reg, _r_mask, _r_table, \ + _r_table_sz), \ + .pctrlsel_reg = _pc_reg, \ + .pctrlsel_mask = _pc_mask, \ + } + +/* standard LDO via LxM_CTRL */ +#define s2mpg10_regulator_desc_ldo(_num, _supply, _vrange) \ + s2mpg10_regulator_desc_ldo_cmn(_num, _supply, \ + s2mpg10_reg_ldo_ops, _vrange, CTRL, GENMASK(5, 0), \ + L##_num##M_CTRL, BIT(7), \ + 0, 0, 0, NULL, 0, \ + 0, 0) + +/* standard LDO but possibly GPIO controlled */ +#define s2mpg10_regulator_desc_ldo_gpio(_num, _supply, _vrange, \ + _pc_reg, _pc_mask) \ + s2mpg10_regulator_desc_ldo_cmn(_num, _supply, \ + s2mpg10_reg_ldo_ops, _vrange, CTRL, GENMASK(5, 0), \ + L##_num##M_CTRL, GENMASK(7, 6), \ + 0, 0, 0, NULL, 0, \ + S2MPG10_PMIC_##_pc_reg, _pc_mask) + +/* LDO with ramp support and possibly GPIO controlled */ +#define s2mpg10_regulator_desc_ldo_ramp(_num, _supply, _vrange, \ + _en_mask, _r_reg, _pc_reg, _pc_mask) \ + s2mpg10_regulator_desc_ldo_cmn(_num, _supply, \ + s2mpg10_reg_ldo_ramp_ops, _vrange, CTRL1, GENMASK(6, 0), \ + LDO_CTRL2, _en_mask, \ + 6250, S2MPG10_PMIC_##_r_reg, GENMASK(1, 0), \ + s2mpg10_ldo_ramp_table, \ + ARRAY_SIZE(s2mpg10_ldo_ramp_table), \ + S2MPG10_PMIC_##_pc_reg, _pc_mask) + +#define S2MPG10_VOLTAGE_RANGE(_prefix, _idx, _offs_uV, _min_uV, \ + _max_uV, _step_uV) \ +static const struct linear_range _prefix##_vranges##_idx[] = { \ + REGULATOR_LINEAR_VRANGE(_offs_uV, _min_uV, _max_uV, _step_uV) \ +}; \ +static const unsigned int _prefix##_vranges##_idx##_count = \ + ((((_max_uV) - (_offs_uV)) / (_step_uV)) + 1) + +/* voltage range for s2mpg10 BUCK 1, 2, 3, 4, 5, 7, 8, 9, 10 */ +S2MPG10_VOLTAGE_RANGE(s2mpg10_buck, 1, 200000, 450000, 1300000, STEP_6_25_MV); + +/* voltage range for s2mpg10 BUCK 6 */ +S2MPG10_VOLTAGE_RANGE(s2mpg10_buck, 6, 200000, 450000, 1350000, STEP_6_25_MV); + +static const unsigned int s2mpg10_buck_ramp_table[] = { + 6250, 12500, 25000 +}; + +/* voltage range for s2mpg10 LDO 1, 11, 12 */ +S2MPG10_VOLTAGE_RANGE(s2mpg10_ldo, 1, 300000, 700000, 1300000, STEP_12_5_MV); + +/* voltage range for s2mpg10 LDO 2, 4, 9, 14, 18, 19, 20, 23, 25, 29, 30, 31 */ +S2MPG10_VOLTAGE_RANGE(s2mpg10_ldo, 2, 700000, 1600000, 1950000, STEP_25_MV); + +/* voltage range for s2mpg10 LDO 3, 5, 6, 8, 16, 17, 24, 28 */ +S2MPG10_VOLTAGE_RANGE(s2mpg10_ldo, 3, 725000, 725000, 1300000, STEP_12_5_MV); + +/* voltage range for s2mpg10 LDO 7 */ +S2MPG10_VOLTAGE_RANGE(s2mpg10_ldo, 7, 300000, 450000, 1300000, STEP_12_5_MV); + +/* voltage range for s2mpg10 LDO 13, 15 */ +S2MPG10_VOLTAGE_RANGE(s2mpg10_ldo, 13, 300000, 450000, 950000, STEP_12_5_MV); + +/* voltage range for s2mpg10 LDO 10 */ +S2MPG10_VOLTAGE_RANGE(s2mpg10_ldo, 10, 1800000, 1800000, 3350000, STEP_25_MV); + +/* voltage range for s2mpg10 LDO 21, 22, 26, 27 */ +S2MPG10_VOLTAGE_RANGE(s2mpg10_ldo, 21, 1800000, 2500000, 3300000, STEP_25_MV); + +/* possible ramp values for s2mpg10 LDO 1, 7, 11, 12, 13, 15 */ +static const unsigned int s2mpg10_ldo_ramp_table[] = { + 6250, 12500 +}; + +static const struct s2mpg10_regulator_desc s2mpg10_regulators[] = { + s2mpg10_regulator_desc_buck_gpio(1, s2mpg10_buck_vranges1, DVS_RAMP1, + PCTRLSEL1, GENMASK(3, 0)), + s2mpg10_regulator_desc_buck_gpio(2, s2mpg10_buck_vranges1, DVS_RAMP1, + PCTRLSEL1, GENMASK(7, 4)), + s2mpg10_regulator_desc_buck_gpio(3, s2mpg10_buck_vranges1, DVS_RAMP1, + PCTRLSEL2, GENMASK(3, 0)), + s2mpg10_regulator_desc_buck_gpio(4, s2mpg10_buck_vranges1, DVS_RAMP1, + PCTRLSEL2, GENMASK(7, 4)), + s2mpg10_regulator_desc_buck_gpio(5, s2mpg10_buck_vranges1, DVS_RAMP2, + PCTRLSEL3, GENMASK(3, 0)), + s2mpg10_regulator_desc_buck_gpio(6, s2mpg10_buck_vranges6, DVS_RAMP2, + PCTRLSEL3, GENMASK(7, 4)), + s2mpg10_regulator_desc_buck_gpio(7, s2mpg10_buck_vranges1, DVS_RAMP2, + PCTRLSEL4, GENMASK(3, 0)), + s2mpg10_regulator_desc_buck(8, s2mpg10_buck_vranges1, DVS_RAMP2), + s2mpg10_regulator_desc_buck(9, s2mpg10_buck_vranges1, DVS_RAMP3), + s2mpg10_regulator_desc_buck_gpio(10, s2mpg10_buck_vranges1, DVS_RAMP3, + PCTRLSEL4, GENMASK(7, 4)), + /* + * Standard LDO via LxM_CTRL but non-standard (greater) V-range and with + * ramp support. + */ + s2mpg10_regulator_desc_ldo_cmn(1, "vinl3m", s2mpg10_reg_ldo_ramp_ops, + s2mpg10_ldo_vranges1, + CTRL, GENMASK(6, 0), + L1M_CTRL, BIT(7), + 6250, S2MPG10_PMIC_DVS_RAMP6, + GENMASK(5, 4), s2mpg10_ldo_ramp_table, + ARRAY_SIZE(s2mpg10_ldo_ramp_table), + 0, 0), + s2mpg10_regulator_desc_ldo(2, "vinl9m", s2mpg10_ldo_vranges2), + s2mpg10_regulator_desc_ldo_gpio(3, "vinl4m", s2mpg10_ldo_vranges3, + PCTRLSEL5, GENMASK(3, 0)), + s2mpg10_regulator_desc_ldo_gpio(4, "vinl9m", s2mpg10_ldo_vranges2, + PCTRLSEL5, GENMASK(7, 4)), + s2mpg10_regulator_desc_ldo_gpio(5, "vinl3m", s2mpg10_ldo_vranges3, + PCTRLSEL6, GENMASK(3, 0)), + s2mpg10_regulator_desc_ldo_gpio(6, "vinl7m", s2mpg10_ldo_vranges3, + PCTRLSEL6, GENMASK(7, 4)), + /* + * Ramp support, possibly GPIO controlled, non-standard (greater) V- + * range and enable reg & mask. + */ + s2mpg10_regulator_desc_ldo_cmn(7, "vinl3m", s2mpg10_reg_ldo_ramp_ops, + s2mpg10_ldo_vranges7, + CTRL, GENMASK(6, 0), + LDO_CTRL1, GENMASK(4, 3), + 6250, S2MPG10_PMIC_DVS_RAMP6, + GENMASK(7, 6), s2mpg10_ldo_ramp_table, + ARRAY_SIZE(s2mpg10_ldo_ramp_table), + S2MPG10_PMIC_PCTRLSEL7, GENMASK(3, 0)), + s2mpg10_regulator_desc_ldo_gpio(8, "vinl4m", s2mpg10_ldo_vranges3, + PCTRLSEL7, GENMASK(7, 4)), + s2mpg10_regulator_desc_ldo_gpio(9, "vinl10m", s2mpg10_ldo_vranges2, + PCTRLSEL8, GENMASK(3, 0)), + s2mpg10_regulator_desc_ldo_gpio(10, "vinl15m", s2mpg10_ldo_vranges10, + PCTRLSEL8, GENMASK(7, 4)), + s2mpg10_regulator_desc_ldo_ramp(11, "vinl7m", s2mpg10_ldo_vranges1, + GENMASK(1, 0), DVS_SYNC_CTRL3, + PCTRLSEL9, GENMASK(3, 0)), + s2mpg10_regulator_desc_ldo_ramp(12, "vinl8m", s2mpg10_ldo_vranges1, + GENMASK(3, 2), DVS_SYNC_CTRL4, + PCTRLSEL9, GENMASK(7, 4)), + s2mpg10_regulator_desc_ldo_ramp(13, "vinl1m", s2mpg10_ldo_vranges13, + GENMASK(5, 4), DVS_SYNC_CTRL5, + PCTRLSEL10, GENMASK(3, 0)), + s2mpg10_regulator_desc_ldo_gpio(14, "vinl10m", s2mpg10_ldo_vranges2, + PCTRLSEL10, GENMASK(7, 4)), + s2mpg10_regulator_desc_ldo_ramp(15, "vinl2m", s2mpg10_ldo_vranges13, + GENMASK(7, 6), DVS_SYNC_CTRL6, + PCTRLSEL11, GENMASK(3, 0)), + s2mpg10_regulator_desc_ldo_gpio(16, "vinl5m", s2mpg10_ldo_vranges3, + PCTRLSEL11, GENMASK(7, 4)), + s2mpg10_regulator_desc_ldo_gpio(17, "vinl6m", s2mpg10_ldo_vranges3, + PCTRLSEL12, GENMASK(3, 0)), + s2mpg10_regulator_desc_ldo_gpio(18, "vinl10m", s2mpg10_ldo_vranges2, + PCTRLSEL12, GENMASK(7, 4)), + s2mpg10_regulator_desc_ldo_gpio(19, "vinl10m", s2mpg10_ldo_vranges2, + PCTRLSEL13, GENMASK(3, 0)), + s2mpg10_regulator_desc_ldo_gpio(20, "vinl10m", s2mpg10_ldo_vranges2, + PCTRLSEL13, GENMASK(7, 4)), + s2mpg10_regulator_desc_ldo(21, "vinl14m", s2mpg10_ldo_vranges21), + s2mpg10_regulator_desc_ldo(22, "vinl15m", s2mpg10_ldo_vranges21), + s2mpg10_regulator_desc_ldo(23, "vinl11m", s2mpg10_ldo_vranges2), + s2mpg10_regulator_desc_ldo(24, "vinl7m", s2mpg10_ldo_vranges3), + s2mpg10_regulator_desc_ldo(25, "vinl10m", s2mpg10_ldo_vranges2), + s2mpg10_regulator_desc_ldo(26, "vinl15m", s2mpg10_ldo_vranges21), + s2mpg10_regulator_desc_ldo(27, "vinl15m", s2mpg10_ldo_vranges21), + s2mpg10_regulator_desc_ldo(28, "vinl7m", s2mpg10_ldo_vranges3), + s2mpg10_regulator_desc_ldo(29, "vinl12m", s2mpg10_ldo_vranges2), + s2mpg10_regulator_desc_ldo(30, "vinl13m", s2mpg10_ldo_vranges2), + s2mpg10_regulator_desc_ldo(31, "vinl11m", s2mpg10_ldo_vranges2) +}; + +static const struct regulator_ops s2mpg11_reg_buck_ops[] = { + [S2MPG10_REGULATOR_OPS_STD] = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time = s2mpg11_regulator_buck_set_voltage_time, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable_time = s2mpg10_regulator_buck_enable_time, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + }, + [S2MPG10_REGULATOR_OPS_EXTCONTROL] = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .enable = s2mpg10_regulator_enable_nop, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_time = s2mpg11_regulator_buck_set_voltage_time, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable_time = s2mpg10_regulator_buck_enable_time, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + } +}; + +#define s2mpg11_buck_to_ramp_mask(n) (GENMASK(3, 2) << (((n) % 2) * 4)) + +#define regulator_desc_s2mpg11_buckx(_name, _id, _supply, _vrange, \ + _vsel_reg, _en_reg, _en_mask, _r_reg) \ + regulator_desc_s2mpg1x_buck_cmn(_name, _id, _supply, \ + s2mpg11_reg_buck_ops, _vrange, \ + S2MPG11_PMIC_##_vsel_reg, GENMASK(7, 0), \ + S2MPG11_PMIC_##_en_reg, _en_mask, \ + S2MPG11_PMIC_##_r_reg, \ + s2mpg11_buck_to_ramp_mask(_id - S2MPG11_BUCK1), \ + s2mpg10_buck_ramp_table, \ + ARRAY_SIZE(s2mpg10_buck_ramp_table), 30) + +#define s2mpg11_regulator_desc_buck_xm(_num, _vrange, _vsel_reg_sfx, \ + _en_mask, _r_reg, _en_rrate) \ + .desc = regulator_desc_s2mpg11_buckx(#_num"s", \ + S2MPG11_BUCK##_num, "vinb"#_num"s", \ + _vrange, \ + B##_num##S_##_vsel_reg_sfx, \ + B##_num##S_CTRL, _en_mask, \ + _r_reg), \ + .enable_ramp_rate = _en_rrate + +#define s2mpg11_regulator_desc_buck_cm(_num, _vrange, _vsel_reg_sfx, \ + _en_mask, _r_reg) \ + [S2MPG11_BUCK##_num] = { \ + s2mpg11_regulator_desc_buck_xm(_num, _vrange, \ + _vsel_reg_sfx, _en_mask, _r_reg, 12500), \ + } + +#define s2mpg11_regulator_desc_buckn_cm_gpio(_num, _vrange, \ + _vsel_reg_sfx, _en_mask, _r_reg, _pc_reg, _pc_mask) \ + [S2MPG11_BUCK##_num] = { \ + s2mpg11_regulator_desc_buck_xm(_num, _vrange, \ + _vsel_reg_sfx, _en_mask, _r_reg, 12500), \ + .pctrlsel_reg = S2MPG11_PMIC_##_pc_reg, \ + .pctrlsel_mask = _pc_mask, \ + } + +#define s2mpg11_regulator_desc_buck_vm(_num, _vrange, _vsel_reg_sfx, \ + _en_mask, _r_reg) \ + [S2MPG11_BUCK##_num] = { \ + s2mpg11_regulator_desc_buck_xm(_num, _vrange, \ + _vsel_reg_sfx, _en_mask, _r_reg, 25000), \ + } + +#define s2mpg11_regulator_desc_bucka(_num, _num_lower, _r_reg, \ + _pc_reg, _pc_mask) \ + [S2MPG11_BUCK##_num] = { \ + .desc = regulator_desc_s2mpg11_buckx(#_num_lower, \ + S2MPG11_BUCK##_num, "vinb"#_num_lower, \ + s2mpg11_buck_vranges##_num_lower, \ + BUCK##_num##_OUT, \ + BUCK##_num##_CTRL, GENMASK(7, 6), \ + _r_reg), \ + .enable_ramp_rate = 25000, \ + .pctrlsel_reg = S2MPG11_PMIC_##_pc_reg, \ + .pctrlsel_mask = _pc_mask, \ + } + +#define s2mpg11_regulator_desc_buckboost() \ + [S2MPG11_BUCKBOOST] = { \ + .desc = regulator_desc_s2mpg1x_buck_cmn("boost", \ + S2MPG11_BUCKBOOST, "vinbb", \ + s2mpg10_reg_ldo_ops, \ + s2mpg11_buck_vrangesboost, \ + S2MPG11_PMIC_BB_OUT1, GENMASK(6, 0), \ + S2MPG11_PMIC_BB_CTRL, BIT(7), \ + 0, 0, NULL, 0, 35), \ + .enable_ramp_rate = 17500, \ + } + +#define s2mpg11_regulator_desc_ldo_cmn(_num, _supply, _ops, \ + _vrange, _vsel_reg_sfx, _vsel_mask, _en_reg, _en_mask, \ + _ramp_delay, _r_reg, _r_mask, _r_table, _r_table_sz, \ + _pc_reg, _pc_mask) \ + [S2MPG11_LDO##_num] = { \ + .desc = regulator_desc_s2mpg1x_ldo_cmn(#_num "s", \ + S2MPG11_LDO##_num, _supply, _ops, \ + _vrange, \ + S2MPG11_PMIC_L##_num##S_##_vsel_reg_sfx, \ + _vsel_mask, \ + S2MPG11_PMIC_##_en_reg, _en_mask, \ + _ramp_delay, _r_reg, _r_mask, _r_table, \ + _r_table_sz), \ + .pctrlsel_reg = _pc_reg, \ + .pctrlsel_mask = _pc_mask, \ + } + +/* standard LDO via LxM_CTRL */ +#define s2mpg11_regulator_desc_ldo(_num, _supply, _vrange) \ + s2mpg11_regulator_desc_ldo_cmn(_num, _supply, \ + s2mpg10_reg_ldo_ops, _vrange, CTRL, GENMASK(5, 0), \ + L##_num##S_CTRL, BIT(7), \ + 0, 0, 0, NULL, 0, \ + 0, 0) + +/* standard LDO but possibly GPIO controlled */ +#define s2mpg11_regulator_desc_ldo_gpio(_num, _supply, _vrange, \ + _pc_reg, _pc_mask) \ + s2mpg11_regulator_desc_ldo_cmn(_num, _supply, \ + s2mpg10_reg_ldo_ops, _vrange, CTRL, GENMASK(5, 0), \ + L##_num##S_CTRL, GENMASK(7, 6), \ + 0, 0, 0, NULL, 0, \ + S2MPG11_PMIC_##_pc_reg, _pc_mask) + +/* LDO with ramp support and possibly GPIO controlled */ +#define s2mpg11_regulator_desc_ldo_ramp(_num, _supply, _vrange, \ + _en_mask, _r_reg, _pc_reg, _pc_mask) \ + s2mpg11_regulator_desc_ldo_cmn(_num, _supply, \ + s2mpg10_reg_ldo_ramp_ops, _vrange, CTRL1, GENMASK(6, 0), \ + LDO_CTRL1, _en_mask, \ + 6250, S2MPG11_PMIC_##_r_reg, GENMASK(1, 0), \ + s2mpg10_ldo_ramp_table, \ + ARRAY_SIZE(s2mpg10_ldo_ramp_table), \ + S2MPG11_PMIC_##_pc_reg, _pc_mask) + +/* voltage range for s2mpg11 BUCK 1, 2, 3, 4, 8, 9, 10 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_buck, 1, 200000, 450000, 1300000, STEP_6_25_MV); + +/* voltage range for s2mpg11 BUCK 5 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_buck, 5, 200000, 400000, 1300000, STEP_6_25_MV); + +/* voltage range for s2mpg11 BUCK 6 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_buck, 6, 200000, 1000000, 1500000, STEP_6_25_MV); + +/* voltage range for s2mpg11 BUCK 7 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_buck, 7, 600000, 1500000, 2200000, STEP_12_5_MV); + +/* voltage range for s2mpg11 BUCK D */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_buck, d, 600000, 2400000, 3300000, STEP_12_5_MV); + +/* voltage range for s2mpg11 BUCK A */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_buck, a, 600000, 1700000, 2100000, STEP_12_5_MV); + +/* voltage range for s2mpg11 BUCK BOOST */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_buck, boost, + 2600000, 3000000, 3600000, STEP_12_5_MV); + +/* voltage range for s2mpg11 LDO 1, 2 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_ldo, 1, 300000, 450000, 950000, STEP_12_5_MV); + +/* voltage range for s2mpg11 LDO 3, 7, 10, 11, 12, 14, 15 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_ldo, 3, 700000, 1600000, 1950000, STEP_25_MV); + +/* voltage range for s2mpg11 LDO 4, 6 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_ldo, 4, 1800000, 2500000, 3300000, STEP_25_MV); + +/* voltage range for s2mpg11 LDO 5 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_ldo, 5, 1600000, 1600000, 1950000, STEP_12_5_MV); + +/* voltage range for s2mpg11 LDO 8 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_ldo, 8, 979600, 1130400, 1281200, 5800); + +/* voltage range for s2mpg11 LDO 9 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_ldo, 9, 725000, 725000, 1300000, STEP_12_5_MV); + +/* voltage range for s2mpg11 LDO 13 */ +S2MPG10_VOLTAGE_RANGE(s2mpg11_ldo, 13, 1800000, 1800000, 3350000, STEP_25_MV); + +static const struct s2mpg10_regulator_desc s2mpg11_regulators[] = { + s2mpg11_regulator_desc_buckboost(), + s2mpg11_regulator_desc_buckn_cm_gpio(1, s2mpg11_buck_vranges1, + OUT1, GENMASK(7, 6), DVS_RAMP1, + PCTRLSEL1, GENMASK(3, 0)), + s2mpg11_regulator_desc_buckn_cm_gpio(2, s2mpg11_buck_vranges1, + OUT1, GENMASK(7, 6), DVS_RAMP1, + PCTRLSEL1, GENMASK(7, 4)), + s2mpg11_regulator_desc_buckn_cm_gpio(3, s2mpg11_buck_vranges1, + OUT1, GENMASK(7, 6), DVS_RAMP2, + PCTRLSEL2, GENMASK(3, 0)), + s2mpg11_regulator_desc_buck_cm(4, s2mpg11_buck_vranges1, + OUT, BIT(7), DVS_RAMP2), + s2mpg11_regulator_desc_buckn_cm_gpio(5, s2mpg11_buck_vranges5, + OUT, GENMASK(7, 6), DVS_RAMP3, + PCTRLSEL2, GENMASK(7, 4)), + s2mpg11_regulator_desc_buck_cm(6, s2mpg11_buck_vranges6, + OUT1, BIT(7), DVS_RAMP3), + s2mpg11_regulator_desc_buck_vm(7, s2mpg11_buck_vranges7, + OUT1, BIT(7), DVS_RAMP4), + s2mpg11_regulator_desc_buckn_cm_gpio(8, s2mpg11_buck_vranges1, + OUT1, GENMASK(7, 6), DVS_RAMP4, + PCTRLSEL3, GENMASK(3, 0)), + s2mpg11_regulator_desc_buckn_cm_gpio(9, s2mpg11_buck_vranges1, + OUT1, GENMASK(7, 6), DVS_RAMP5, + PCTRLSEL3, GENMASK(7, 4)), + s2mpg11_regulator_desc_buck_cm(10, s2mpg11_buck_vranges1, + OUT, BIT(7), DVS_RAMP5), + s2mpg11_regulator_desc_bucka(D, d, DVS_RAMP6, PCTRLSEL4, GENMASK(3, 0)), + s2mpg11_regulator_desc_bucka(A, a, DVS_RAMP6, PCTRLSEL4, GENMASK(7, 4)), + s2mpg11_regulator_desc_ldo_ramp(1, "vinl1s", s2mpg11_ldo_vranges1, + GENMASK(5, 4), DVS_SYNC_CTRL1, + PCTRLSEL5, GENMASK(3, 0)), + s2mpg11_regulator_desc_ldo_ramp(2, "vinl1s", s2mpg11_ldo_vranges1, + GENMASK(7, 6), DVS_SYNC_CTRL2, + PCTRLSEL5, GENMASK(7, 4)), + s2mpg11_regulator_desc_ldo(3, "vinl3s", s2mpg11_ldo_vranges3), + s2mpg11_regulator_desc_ldo(4, "vinl5s", s2mpg11_ldo_vranges4), + s2mpg11_regulator_desc_ldo(5, "vinl3s", s2mpg11_ldo_vranges5), + s2mpg11_regulator_desc_ldo(6, "vinl5s", s2mpg11_ldo_vranges4), + s2mpg11_regulator_desc_ldo(7, "vinl3s", s2mpg11_ldo_vranges3), + s2mpg11_regulator_desc_ldo_gpio(8, "vinl2s", s2mpg11_ldo_vranges8, + PCTRLSEL6, GENMASK(3, 0)), + s2mpg11_regulator_desc_ldo(9, "vinl2s", s2mpg11_ldo_vranges9), + s2mpg11_regulator_desc_ldo(10, "vinl4s", s2mpg11_ldo_vranges3), + s2mpg11_regulator_desc_ldo(11, "vinl4s", s2mpg11_ldo_vranges3), + s2mpg11_regulator_desc_ldo(12, "vinl4s", s2mpg11_ldo_vranges3), + s2mpg11_regulator_desc_ldo_gpio(13, "vinl6s", s2mpg11_ldo_vranges13, + PCTRLSEL6, GENMASK(7, 4)), + s2mpg11_regulator_desc_ldo(14, "vinl4s", s2mpg11_ldo_vranges3), + s2mpg11_regulator_desc_ldo(15, "vinl3s", s2mpg11_ldo_vranges3) +}; + static const struct regulator_ops s2mps11_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -362,6 +1289,8 @@ static const struct regulator_ops s2mps11_buck_ops = { #define regulator_desc_s2mps11_ldo(num, step) { \ .name = "LDO"#num, \ .id = S2MPS11_LDO##num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps11_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -378,6 +1307,8 @@ static const struct regulator_ops s2mps11_buck_ops = { #define regulator_desc_s2mps11_buck1_4(num) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -395,6 +1326,8 @@ static const struct regulator_ops s2mps11_buck_ops = { #define regulator_desc_s2mps11_buck5 { \ .name = "BUCK5", \ .id = S2MPS11_BUCK5, \ + .of_match = of_match_ptr("BUCK5"), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -412,6 +1345,8 @@ static const struct regulator_ops s2mps11_buck_ops = { #define regulator_desc_s2mps11_buck67810(num, min, step, min_sel, voltages) { \ .name = "BUCK"#num, \ .id = S2MPS11_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -429,6 +1364,8 @@ static const struct regulator_ops s2mps11_buck_ops = { #define regulator_desc_s2mps11_buck9 { \ .name = "BUCK9", \ .id = S2MPS11_BUCK9, \ + .of_match = of_match_ptr("BUCK9"), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps11_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -502,6 +1439,8 @@ static const struct regulator_ops s2mps14_reg_ops; #define regulator_desc_s2mps13_ldo(num, min, step, min_sel) { \ .name = "LDO"#num, \ .id = S2MPS13_LDO##num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps14_reg_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -518,6 +1457,8 @@ static const struct regulator_ops s2mps14_reg_ops; #define regulator_desc_s2mps13_buck(num, min, step, min_sel) { \ .name = "BUCK"#num, \ .id = S2MPS13_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps14_reg_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -535,6 +1476,8 @@ static const struct regulator_ops s2mps14_reg_ops; #define regulator_desc_s2mps13_buck7(num, min, step, min_sel) { \ .name = "BUCK"#num, \ .id = S2MPS13_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps14_reg_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -552,6 +1495,8 @@ static const struct regulator_ops s2mps14_reg_ops; #define regulator_desc_s2mps13_buck8_10(num, min, step, min_sel) { \ .name = "BUCK"#num, \ .id = S2MPS13_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps14_reg_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -634,6 +1579,9 @@ static const struct regulator_ops s2mps14_reg_ops = { #define regulator_desc_s2mps14_ldo(num, min, step) { \ .name = "LDO"#num, \ .id = S2MPS14_LDO##num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = s2mps11_of_parse_cb, \ .ops = &s2mps14_reg_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -649,6 +1597,9 @@ static const struct regulator_ops s2mps14_reg_ops = { #define regulator_desc_s2mps14_buck(num, min, step, min_sel) { \ .name = "BUCK"#num, \ .id = S2MPS14_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ + .of_parse_cb = s2mps11_of_parse_cb, \ .ops = &s2mps14_reg_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -725,6 +1676,8 @@ static const struct regulator_ops s2mps15_reg_buck_ops = { #define regulator_desc_s2mps15_ldo(num, range) { \ .name = "LDO"#num, \ .id = S2MPS15_LDO##num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps15_reg_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -740,6 +1693,8 @@ static const struct regulator_ops s2mps15_reg_buck_ops = { #define regulator_desc_s2mps15_buck(num, range) { \ .name = "BUCK"#num, \ .id = S2MPS15_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mps15_reg_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -829,63 +1784,15 @@ static const struct regulator_desc s2mps15_regulators[] = { }; static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, - struct regulator_dev *rdev) -{ - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, S2MPS14_ENABLE_EXT_CONTROL); -} - -static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, - struct of_regulator_match *rdata, struct s2mps11_info *s2mps11) + struct regulator_dev *rdev) { - struct gpio_desc **gpio = s2mps11->ext_control_gpiod; - unsigned int i; - unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11, - S2MPS14_LDO12 }; - - for (i = 0; i < ARRAY_SIZE(valid_regulators); i++) { - unsigned int reg = valid_regulators[i]; - - if (!rdata[reg].init_data || !rdata[reg].of_node) - continue; - - gpio[reg] = devm_fwnode_gpiod_get(&pdev->dev, - of_fwnode_handle(rdata[reg].of_node), - "samsung,ext-control", - GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, - "s2mps11-regulator"); - if (PTR_ERR(gpio[reg]) == -ENOENT) - gpio[reg] = NULL; - else if (IS_ERR(gpio[reg])) { - dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n", - reg, rdata[reg].name); - gpio[reg] = NULL; - continue; - } - if (gpio[reg]) - dev_dbg(&pdev->dev, "Using GPIO for ext-control over %d/%s\n", - reg, rdata[reg].name); - } -} - -static int s2mps11_pmic_dt_parse(struct platform_device *pdev, - struct of_regulator_match *rdata, struct s2mps11_info *s2mps11, - unsigned int rdev_num) -{ - struct device_node *reg_np; - - reg_np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); - if (!reg_np) { - dev_err(&pdev->dev, "could not find regulators sub-node\n"); - return -EINVAL; - } - - of_regulator_match(&pdev->dev, reg_np, rdata, rdev_num); - if (s2mps11->dev_type == S2MPS14X) - s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11); - - of_node_put(reg_np); - + int ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + S2MPS14_ENABLE_EXT_CONTROL); + if (ret < 0) + return dev_err_probe(rdev_get_dev(rdev), ret, + "failed to enable GPIO control over %d/%s\n", + rdev->desc->id, rdev->desc->name); return 0; } @@ -946,6 +1853,8 @@ static const struct regulator_ops s2mpu02_buck_ops = { #define regulator_desc_s2mpu02_ldo1(num) { \ .name = "LDO"#num, \ .id = S2MPU02_LDO##num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -961,6 +1870,8 @@ static const struct regulator_ops s2mpu02_buck_ops = { #define regulator_desc_s2mpu02_ldo2(num) { \ .name = "LDO"#num, \ .id = S2MPU02_LDO##num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -976,6 +1887,8 @@ static const struct regulator_ops s2mpu02_buck_ops = { #define regulator_desc_s2mpu02_ldo3(num) { \ .name = "LDO"#num, \ .id = S2MPU02_LDO##num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -991,6 +1904,8 @@ static const struct regulator_ops s2mpu02_buck_ops = { #define regulator_desc_s2mpu02_ldo4(num) { \ .name = "LDO"#num, \ .id = S2MPU02_LDO##num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -1006,6 +1921,8 @@ static const struct regulator_ops s2mpu02_buck_ops = { #define regulator_desc_s2mpu02_ldo5(num) { \ .name = "LDO"#num, \ .id = S2MPU02_LDO##num, \ + .of_match = of_match_ptr("LDO"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -1022,6 +1939,8 @@ static const struct regulator_ops s2mpu02_buck_ops = { #define regulator_desc_s2mpu02_buck1234(num) { \ .name = "BUCK"#num, \ .id = S2MPU02_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -1038,6 +1957,8 @@ static const struct regulator_ops s2mpu02_buck_ops = { #define regulator_desc_s2mpu02_buck5(num) { \ .name = "BUCK"#num, \ .id = S2MPU02_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -1054,6 +1975,8 @@ static const struct regulator_ops s2mpu02_buck_ops = { #define regulator_desc_s2mpu02_buck6(num) { \ .name = "BUCK"#num, \ .id = S2MPU02_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -1070,6 +1993,8 @@ static const struct regulator_ops s2mpu02_buck_ops = { #define regulator_desc_s2mpu02_buck7(num) { \ .name = "BUCK"#num, \ .id = S2MPU02_BUCK##num, \ + .of_match = of_match_ptr("BUCK"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -1125,6 +2050,8 @@ static const struct regulator_desc s2mpu02_regulators[] = { #define regulator_desc_s2mpu05_ldo_reg(num, min, step, reg) { \ .name = "ldo"#num, \ .id = S2MPU05_LDO##num, \ + .of_match = of_match_ptr("ldo"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -1156,6 +2083,8 @@ static const struct regulator_desc s2mpu02_regulators[] = { #define regulator_desc_s2mpu05_buck(num, which) { \ .name = "buck"#num, \ .id = S2MPU05_BUCK##num, \ + .of_match = of_match_ptr("buck"#num), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &s2mpu02_buck_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -1202,14 +2131,48 @@ static const struct regulator_desc s2mpu05_regulators[] = { regulator_desc_s2mpu05_buck45(5), }; +static int s2mps11_handle_ext_control(struct s2mps11_info *s2mps11, + struct regulator_dev *rdev) +{ + int ret; + + switch (s2mps11->dev_type) { + case S2MPS14X: + if (!rdev->ena_pin) + return 0; + + ret = s2mps14_pmic_enable_ext_control(s2mps11, rdev); + break; + + case S2MPG10: + case S2MPG11: + /* + * If desc.enable_val is != 0, then external control was + * requested. We can not test s2mpg10_desc::ext_control, + * because 0 is a valid value. + */ + if (!rdev->desc->enable_val) + return 0; + + ret = s2mpg10_enable_ext_control(s2mps11, rdev); + break; + + default: + return 0; + } + + return ret; +} + static int s2mps11_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; struct s2mps11_info *s2mps11; - unsigned int rdev_num = 0; - int i, ret = 0; + unsigned int rdev_num; + int i, ret; const struct regulator_desc *regulators; + const struct s2mpg10_regulator_desc *s2mpg1x_regulators = NULL; s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info), GFP_KERNEL); @@ -1218,58 +2181,64 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) s2mps11->dev_type = platform_get_device_id(pdev)->driver_data; switch (s2mps11->dev_type) { + case S2MPG10: + rdev_num = ARRAY_SIZE(s2mpg10_regulators); + s2mpg1x_regulators = s2mpg10_regulators; + BUILD_BUG_ON(ARRAY_SIZE(s2mpg10_regulators) > S2MPS_REGULATOR_MAX); + break; + case S2MPG11: + rdev_num = ARRAY_SIZE(s2mpg11_regulators); + s2mpg1x_regulators = s2mpg11_regulators; + BUILD_BUG_ON(ARRAY_SIZE(s2mpg11_regulators) > S2MPS_REGULATOR_MAX); + break; case S2MPS11X: rdev_num = ARRAY_SIZE(s2mps11_regulators); regulators = s2mps11_regulators; - BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps11_regulators)); + BUILD_BUG_ON(ARRAY_SIZE(s2mps11_regulators) > S2MPS_REGULATOR_MAX); break; case S2MPS13X: rdev_num = ARRAY_SIZE(s2mps13_regulators); regulators = s2mps13_regulators; - BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps13_regulators)); + BUILD_BUG_ON(ARRAY_SIZE(s2mps13_regulators) > S2MPS_REGULATOR_MAX); break; case S2MPS14X: rdev_num = ARRAY_SIZE(s2mps14_regulators); regulators = s2mps14_regulators; - BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps14_regulators)); + BUILD_BUG_ON(ARRAY_SIZE(s2mps14_regulators) > S2MPS_REGULATOR_MAX); break; case S2MPS15X: rdev_num = ARRAY_SIZE(s2mps15_regulators); regulators = s2mps15_regulators; - BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mps15_regulators)); + BUILD_BUG_ON(ARRAY_SIZE(s2mps15_regulators) > S2MPS_REGULATOR_MAX); break; case S2MPU02: rdev_num = ARRAY_SIZE(s2mpu02_regulators); regulators = s2mpu02_regulators; - BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mpu02_regulators)); + BUILD_BUG_ON(ARRAY_SIZE(s2mpu02_regulators) > S2MPS_REGULATOR_MAX); break; case S2MPU05: rdev_num = ARRAY_SIZE(s2mpu05_regulators); regulators = s2mpu05_regulators; - BUILD_BUG_ON(S2MPS_REGULATOR_MAX < ARRAY_SIZE(s2mpu05_regulators)); + BUILD_BUG_ON(ARRAY_SIZE(s2mpu05_regulators) > S2MPS_REGULATOR_MAX); break; default: - dev_err(&pdev->dev, "Invalid device type: %u\n", - s2mps11->dev_type); - return -EINVAL; + return dev_err_probe(&pdev->dev, -ENODEV, + "Unsupported device type %d\n", + s2mps11->dev_type); } - s2mps11->ext_control_gpiod = devm_kcalloc(&pdev->dev, rdev_num, - sizeof(*s2mps11->ext_control_gpiod), GFP_KERNEL); - if (!s2mps11->ext_control_gpiod) - return -ENOMEM; + if (s2mpg1x_regulators) { + size_t regulators_sz = rdev_num * sizeof(*s2mpg1x_regulators); - struct of_regulator_match *rdata __free(kfree) = - kcalloc(rdev_num, sizeof(*rdata), GFP_KERNEL); - if (!rdata) - return -ENOMEM; + s2mpg1x_regulators = devm_kmemdup(&pdev->dev, + s2mpg1x_regulators, + regulators_sz, + GFP_KERNEL); + if (!s2mpg1x_regulators) + return -ENOMEM; + } - for (i = 0; i < rdev_num; i++) - rdata[i].name = regulators[i].name; - - ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, rdev_num); - if (ret) - return ret; + device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); platform_set_drvdata(pdev, s2mps11); @@ -1277,41 +2246,32 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; for (i = 0; i < rdev_num; i++) { + const struct regulator_desc *rdesc; struct regulator_dev *regulator; - config.init_data = rdata[i].init_data; - config.of_node = rdata[i].of_node; - config.ena_gpiod = s2mps11->ext_control_gpiod[i]; - /* - * Hand the GPIO descriptor management over to the regulator - * core, remove it from devres management. - */ - if (config.ena_gpiod) - devm_gpiod_unhinge(&pdev->dev, config.ena_gpiod); - regulator = devm_regulator_register(&pdev->dev, - ®ulators[i], &config); - if (IS_ERR(regulator)) { - dev_err(&pdev->dev, "regulator init failed for %d\n", - i); - return PTR_ERR(regulator); - } + if (s2mpg1x_regulators) + rdesc = &s2mpg1x_regulators[i].desc; + else + rdesc = ®ulators[i]; - if (config.ena_gpiod) { - ret = s2mps14_pmic_enable_ext_control(s2mps11, - regulator); - if (ret < 0) { - dev_err(&pdev->dev, - "failed to enable GPIO control over %s: %d\n", - regulator->desc->name, ret); - return ret; - } - } + regulator = devm_regulator_register(&pdev->dev, + rdesc, &config); + if (IS_ERR(regulator)) + return dev_err_probe(&pdev->dev, PTR_ERR(regulator), + "regulator init failed for %d/%s\n", + rdesc->id, rdesc->name); + + ret = s2mps11_handle_ext_control(s2mps11, regulator); + if (ret < 0) + return ret; } return 0; } static const struct platform_device_id s2mps11_pmic_id[] = { + { "s2mpg10-regulator", S2MPG10}, + { "s2mpg11-regulator", S2MPG11}, { "s2mps11-regulator", S2MPS11X}, { "s2mps13-regulator", S2MPS13X}, { "s2mps14-regulator", S2MPS14X}, diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index a7220b4d0e8d..c6ed5a4ca8a0 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -15,7 +15,6 @@ #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/mfd/samsung/core.h> -#include <linux/mfd/samsung/irq.h> #include <linux/mfd/samsung/rtc.h> #include <linux/mfd/samsung/s2mps14.h> @@ -683,22 +682,18 @@ static int s5m_rtc_probe(struct platform_device *pdev) case S2MPS15X: regmap_cfg = &s2mps14_rtc_regmap_config; info->regs = &s2mps15_rtc_regs; - alarm_irq = S2MPS14_IRQ_RTCA0; break; case S2MPS14X: regmap_cfg = &s2mps14_rtc_regmap_config; info->regs = &s2mps14_rtc_regs; - alarm_irq = S2MPS14_IRQ_RTCA0; break; case S2MPS13X: regmap_cfg = &s2mps14_rtc_regmap_config; info->regs = &s2mps13_rtc_regs; - alarm_irq = S2MPS14_IRQ_RTCA0; break; case S5M8767X: regmap_cfg = &s5m_rtc_regmap_config; info->regs = &s5m_rtc_regs; - alarm_irq = S5M8767_IRQ_RTCA1; break; default: return dev_err_probe(&pdev->dev, -ENODEV, @@ -719,7 +714,6 @@ static int s5m_rtc_probe(struct platform_device *pdev) "Failed to allocate regmap\n"); } else if (device_type == S2MPG10) { info->regs = &s2mpg10_rtc_regs; - alarm_irq = S2MPG10_IRQ_RTCA0; } else { return dev_err_probe(&pdev->dev, -ENODEV, "Unsupported device type %d\n", @@ -730,13 +724,14 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->s5m87xx = s5m87xx; info->device_type = device_type; - if (s5m87xx->irq_data) { - info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq); - if (info->irq <= 0) - return dev_err_probe(&pdev->dev, -EINVAL, - "Failed to get virtual IRQ %d\n", - alarm_irq); - } + alarm_irq = platform_get_irq_byname_optional(pdev, "alarm"); + if (alarm_irq > 0) + info->irq = alarm_irq; + else if (alarm_irq == -ENXIO) + info->irq = 0; + else + return dev_err_probe(&pdev->dev, alarm_irq ? : -EINVAL, + "IRQ 'alarm' not found\n"); platform_set_drvdata(pdev, info); |
