diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 18:35:35 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 18:35:35 +0300 |
commit | d042380886fb2fc6c4b0fcfe1214ba473769a8e9 (patch) | |
tree | 61e29ff167e0f83f67930ee9911062415030e1ef /drivers/regulator/axp20x-regulator.c | |
parent | 3477d168ba61c5b0ca42d3d4642f3463609a5417 (diff) | |
parent | b8d336ed90f541097a2ce583be430bb3e895dfbd (diff) | |
download | linux-d042380886fb2fc6c4b0fcfe1214ba473769a8e9.tar.xz |
Merge tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"Core framework:
- Add the MFD bindings doc to MAINTAINERS
New drivers:
- X-Powers AC100 Audio CODEC and RTC
- TI LP873x PMIC
- Rockchip RK808 PMIC
- Samsung Exynos Low Power Audio
New device support:
- Add support for STMPE1600 variant to stmpe
- Add support for PM8018 PMIC to pm8921-core
- Add support for AXP806 PMIC in axp20x
- Add support for AXP209 GPIO in axp20x
New functionality:
- Add support for Reset to all STMPE variants
- Add support for MKBP event support to cros_ec
- Add support for USB to intel_soc_pmic_bxtwc
- Add support for IRQs and Power Button to tps65217
Fix-ups:
- Clean-up defunct author emails (da9063, max14577)
- Kconfig fixups (wm8350-i2c, as37220
- Constify (altera-a10sr, sm501)
- Supply PCI IDs (intel-lpss-pci)
- Improve clocking (qcom_rpm)
- Fix IRQ probing (ucb1x00-core)
- Ensure fault log is cleared (da9052)
- Remove NO_IRQ check (ucb1x00-core)
- Supply I2C properties (intel-lpss-acpi, intel-lpss-pci)
- Non standard declaration (tps65217, max8997-irq)
- Remove unused code (lp873x, db8500-prcmu, ab8500-debugfs,
cros_ec_spi)
- Make non-modular (altera-a10sr, intel_msic, smsc-ece1099,
sun6i-prcm, twl-core)
- OF bindings (ac100, stmpe, qcom-pm8xxx, qcom-rpm, rk808, axp20x,
lp873x, exynos5433-lpass, act8945a, aspeed-scu, twl6040, arizona)
Bugfixes:
- Release OF pointer (qcom_rpm)
- Avoid double shifting in suspend/resume (88pm80x)
- Fix 'defined but not used' error (exynos-lpass)
- Fix 'sleeping whilst attomic' (atmel-hlcdc)"
* tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (69 commits)
mfd: arizona: Handle probe deferral for reset GPIO
mfd: arizona: Remove arizona_of_get_named_gpio helper function
mfd: arizona: Add DT options for max_channels_clocked and PDM speaker config
mfd: twl6040: Register child device for twl6040-pdmclk
mfd: cros_ec_spi: Remove unused variable 'request'
mfd: omap-usb-host: Return value is not 'const int'
mfd: ab8500-debugfs: Remove 'weak' function suspend_test_wake_cause_interrupt_is_mine()
mfd: ab8500-debugfs: Remove ab8500_dump_all_banks_to_mem()
mfd: db8500-prcmu: Remove unused *prcmu_set_ddr_opp() calls
mfd: ab8500-debugfs: Prevent initialised field from being over-written
mfd: max8997-irq: 'inline' should be at the beginning of the declaration
mfd: rk808: Fix RK818_IRQ_DISCHG_ILIM initializer
mfd: tps65217: Fix nonstandard declaration
mfd: lp873x: Remove unused mutex lock from struct lp873x
mfd: atmel-hlcdc: Do not sleep in atomic context
mfd: exynos-lpass: Mark PM functions as __maybe_unused
mfd: intel-lpss: Add default I2C device properties for Apollo Lake
mfd: twl-core: Make it explicitly non-modular
mfd: sun6i-prcm: Make it explicitly non-modular
mfd: smsc-ece1099: Make it explicitly non-modular
...
Diffstat (limited to 'drivers/regulator/axp20x-regulator.c')
-rw-r--r-- | drivers/regulator/axp20x-regulator.c | 118 |
1 files changed, 111 insertions, 7 deletions
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 6d9ac76a772f..54382ef902c6 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -244,16 +244,64 @@ static const struct regulator_desc axp22x_drivevbus_regulator = { .ops = &axp20x_ops_sw, }; -static const struct regulator_linear_range axp809_dcdc4_ranges[] = { - REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000), - REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000), +static const struct regulator_linear_range axp806_dcdca_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000), + REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000), }; -static const struct regulator_linear_range axp809_dldo1_ranges[] = { +static const struct regulator_linear_range axp806_dcdcd_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2d, 20000), + REGULATOR_LINEAR_RANGE(1600000, 0x2e, 0x3f, 100000), +}; + +static const struct regulator_linear_range axp806_cldo2_ranges[] = { REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000), REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000), }; +static const struct regulator_desc axp806_regulators[] = { + AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", axp806_dcdca_ranges, + 72, AXP806_DCDCA_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1, + BIT(0)), + AXP_DESC(AXP806, DCDCB, "dcdcb", "vinb", 1000, 2550, 50, + AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(1)), + AXP_DESC_RANGES(AXP806, DCDCC, "dcdcc", "vinc", axp806_dcdca_ranges, + 72, AXP806_DCDCC_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1, + BIT(2)), + AXP_DESC_RANGES(AXP806, DCDCD, "dcdcd", "vind", axp806_dcdcd_ranges, + 64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1, + BIT(3)), + AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100, + AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)), + AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100, + AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)), + AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100, + AXP806_ALDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(6)), + AXP_DESC(AXP806, ALDO3, "aldo3", "aldoin", 700, 3300, 100, + AXP806_ALDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(7)), + AXP_DESC(AXP806, BLDO1, "bldo1", "bldoin", 700, 1900, 100, + AXP806_BLDO1_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(0)), + AXP_DESC(AXP806, BLDO2, "bldo2", "bldoin", 700, 1900, 100, + AXP806_BLDO2_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(1)), + AXP_DESC(AXP806, BLDO3, "bldo3", "bldoin", 700, 1900, 100, + AXP806_BLDO3_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(2)), + AXP_DESC(AXP806, BLDO4, "bldo4", "bldoin", 700, 1900, 100, + AXP806_BLDO4_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(3)), + AXP_DESC(AXP806, CLDO1, "cldo1", "cldoin", 700, 3300, 100, + AXP806_CLDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(4)), + AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", axp806_cldo2_ranges, + 32, AXP806_CLDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, + BIT(5)), + AXP_DESC(AXP806, CLDO3, "cldo3", "cldoin", 700, 3300, 100, + AXP806_CLDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(6)), + AXP_DESC_SW(AXP806, SW, "sw", "swin", AXP806_PWR_OUT_CTRL2, BIT(7)), +}; + +static const struct regulator_linear_range axp809_dcdc4_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000), + REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000), +}; + static const struct regulator_desc axp809_regulators[] = { AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)), @@ -278,7 +326,7 @@ static const struct regulator_desc axp809_regulators[] = { AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100, AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), - AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp809_dldo1_ranges, + AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp806_cldo2_ranges, 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)), AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100, @@ -302,6 +350,7 @@ static const struct regulator_desc axp809_regulators[] = { static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); + unsigned int reg = AXP20X_DCDC_FREQ; u32 min, max, def, step; switch (axp20x->variant) { @@ -312,6 +361,14 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) def = 1500; step = 75; break; + case AXP806_ID: + /* + * AXP806 DCDC work frequency setting has the same range and + * step as AXP22X, but at a different register. + * Fall through to the check below. + * (See include/linux/mfd/axp20x.h) + */ + reg = AXP806_DCDC_FREQ_CTRL; case AXP221_ID: case AXP223_ID: case AXP809_ID: @@ -343,7 +400,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) dcdcfreq = (dcdcfreq - min) / step; - return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ, + return regmap_update_bits(axp20x->regmap, reg, AXP20X_FREQ_DCDC_MASK, dcdcfreq); } @@ -377,6 +434,7 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev) static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode) { struct axp20x_dev *axp20x = rdev_get_drvdata(rdev); + unsigned int reg = AXP20X_DCDC_MODE; unsigned int mask; switch (axp20x->variant) { @@ -392,6 +450,13 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work workmode <<= ffs(mask) - 1; break; + case AXP806_ID: + reg = AXP806_DCDC_MODE_CTRL2; + /* + * AXP806 DCDC regulator IDs have the same range as AXP22X. + * Fall through to the check below. + * (See include/linux/mfd/axp20x.h) + */ case AXP221_ID: case AXP223_ID: case AXP809_ID: @@ -408,7 +473,34 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work return -EINVAL; } - return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode); + return regmap_update_bits(rdev->regmap, reg, mask, workmode); +} + +/* + * This function checks whether a regulator is part of a poly-phase + * output setup based on the registers settings. Returns true if it is. + */ +static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) +{ + u32 reg = 0; + + /* Only AXP806 has poly-phase outputs */ + if (axp20x->variant != AXP806_ID) + return false; + + regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, ®); + + switch (id) { + case AXP806_DCDCB: + return (((reg & GENMASK(7, 6)) == BIT(6)) || + ((reg & GENMASK(7, 6)) == BIT(7))); + case AXP806_DCDCC: + return ((reg & GENMASK(7, 6)) == BIT(7)); + case AXP806_DCDCE: + return !!(reg & BIT(5)); + } + + return false; } static int axp20x_regulator_probe(struct platform_device *pdev) @@ -440,6 +532,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev) drivevbus = of_property_read_bool(pdev->dev.parent->of_node, "x-powers,drive-vbus-en"); break; + case AXP806_ID: + regulators = axp806_regulators; + nregulators = AXP806_REG_ID_MAX; + break; case AXP809_ID: regulators = axp809_regulators; nregulators = AXP809_REG_ID_MAX; @@ -458,6 +554,14 @@ static int axp20x_regulator_probe(struct platform_device *pdev) struct regulator_desc *new_desc; /* + * If this regulator is a slave in a poly-phase setup, + * skip it, as its controls are bound to the master + * regulator and won't work. + */ + if (axp20x_is_polyphase_slave(axp20x, i)) + continue; + + /* * Regulators DC1SW and DC5LDO are connected internally, * so we have to handle their supply names separately. * |