summaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2016-11-04 12:16:38 -0600
committerMark Brown <broonie@kernel.org>2016-11-04 12:16:38 -0600
commitcc9b94029e9ef51787af908e9856b1eed314bc00 (patch)
tree9675310b89d0f6fb1f7bd9423f0638c4ee5226fd /drivers/regulator
parent13bed58ce8748d430a26e353a09b89f9d613a71f (diff)
parent1b5b42216469b05ef4b5916cb40b127dfab1da88 (diff)
downloadlinux-cc9b94029e9ef51787af908e9856b1eed314bc00.tar.gz
linux-cc9b94029e9ef51787af908e9856b1eed314bc00.tar.bz2
linux-cc9b94029e9ef51787af908e9856b1eed314bc00.zip
Merge branch 'topic/error' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator into regulator-fixed
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig34
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/ab8500-ext.c465
-rw-r--r--drivers/regulator/act8865-regulator.c12
-rw-r--r--drivers/regulator/anatop-regulator.c2
-rw-r--r--drivers/regulator/axp20x-regulator.c255
-rw-r--r--drivers/regulator/core.c214
-rw-r--r--drivers/regulator/da9052-regulator.c6
-rw-r--r--drivers/regulator/da9210-regulator.c21
-rw-r--r--drivers/regulator/da9211-regulator.c13
-rw-r--r--drivers/regulator/da9211-regulator.h3
-rw-r--r--drivers/regulator/dbx500-prcmu.c18
-rw-r--r--drivers/regulator/devres.c7
-rw-r--r--drivers/regulator/hi6421-regulator.c3
-rw-r--r--drivers/regulator/lp873x-regulator.c14
-rw-r--r--drivers/regulator/ltc3676.c420
-rw-r--r--drivers/regulator/max14577-regulator.c4
-rw-r--r--drivers/regulator/max77620-regulator.c7
-rw-r--r--drivers/regulator/max77693-regulator.c4
-rw-r--r--drivers/regulator/max8973-regulator.c19
-rw-r--r--drivers/regulator/mt6323-regulator.c425
-rw-r--r--drivers/regulator/mt6397-regulator.c95
-rw-r--r--drivers/regulator/of_regulator.c3
-rw-r--r--drivers/regulator/pfuze100-regulator.c15
-rw-r--r--drivers/regulator/pv88060-regulator.c3
-rw-r--r--drivers/regulator/pv88080-regulator.c266
-rw-r--r--drivers/regulator/pv88080-regulator.h114
-rw-r--r--drivers/regulator/pv88090-regulator.c3
-rw-r--r--drivers/regulator/pwm-regulator.c194
-rw-r--r--drivers/regulator/qcom_rpm-regulator.c66
-rw-r--r--drivers/regulator/qcom_smd-regulator.c46
-rw-r--r--drivers/regulator/qcom_spmi-regulator.c7
-rw-r--r--drivers/regulator/rk808-regulator.c146
-rw-r--r--drivers/regulator/rn5t618-regulator.c40
-rw-r--r--drivers/regulator/s2mps11.c6
-rw-r--r--drivers/regulator/tps51632-regulator.c9
-rw-r--r--drivers/regulator/tps65217-regulator.c69
-rw-r--r--drivers/regulator/tps65218-regulator.c84
-rw-r--r--drivers/regulator/tps65910-regulator.c6
-rw-r--r--drivers/regulator/twl-regulator.c2
40 files changed, 2704 insertions, 418 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 144cbf5b3e5a..936f7ccc9736 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -323,7 +323,7 @@ config REGULATOR_LP872X
config REGULATOR_LP873X
tristate "TI LP873X Power regulators"
- depends on MFD_LP873X && OF
+ depends on MFD_TI_LP873X && OF
help
This driver supports LP873X voltage regulator chips. LP873X
provides two step-down converters and two general-purpose LDO
@@ -353,6 +353,14 @@ config REGULATOR_LTC3589
This enables support for the LTC3589, LTC3589-1, and LTC3589-2
8-output regulators controlled via I2C.
+config REGULATOR_LTC3676
+ tristate "LTC3676 8-output voltage regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This enables support for the LTC3676
+ 8-output regulators controlled via I2C.
+
config REGULATOR_MAX14577
tristate "Maxim 14577/77836 regulator"
depends on MFD_MAX14577
@@ -498,6 +506,15 @@ config REGULATOR_MT6311
This driver supports the control of different power rails of device
through regulator interface.
+config REGULATOR_MT6323
+ tristate "MediaTek MT6323 PMIC"
+ depends on MFD_MT6397
+ help
+ Say y here to select this option to enable the power regulator of
+ MediaTek MT6323 PMIC.
+ This driver supports the control of different power rails of device
+ through regulator interface.
+
config REGULATOR_MT6397
tristate "MediaTek MT6397 PMIC"
depends on MFD_MT6397
@@ -543,12 +560,12 @@ config REGULATOR_PCF50633
on PCF50633
config REGULATOR_PFUZE100
- tristate "Freescale PFUZE100/PFUZE200 regulator driver"
+ tristate "Freescale PFUZE100/200/3000 regulator driver"
depends on I2C
select REGMAP_I2C
help
Say y here to support the regulators found on the Freescale
- PFUZE100/PFUZE200 PMIC.
+ PFUZE100/200/3000 PMIC.
config REGULATOR_PV88060
tristate "Powerventure Semiconductor PV88060 regulator"
@@ -626,20 +643,21 @@ config REGULATOR_RC5T583
outputs which can be controlled by i2c communication.
config REGULATOR_RK808
- tristate "Rockchip RK808 Power regulators"
+ tristate "Rockchip RK808/RK818 Power regulators"
depends on MFD_RK808
help
Select this option to enable the power regulator of ROCKCHIP
- PMIC RK808.
+ PMIC RK808 and RK818.
This driver supports the control of different power rails of device
through regulator interface. The device supports multiple DCDC/LDO
outputs which can be controlled by i2c communication.
config REGULATOR_RN5T618
- tristate "Ricoh RN5T618 voltage regulators"
+ tristate "Ricoh RN5T567/618 voltage regulators"
depends on MFD_RN5T618
help
- Say y here to support the regulators found on Ricoh RN5T618 PMIC.
+ Say y here to support the regulators found on Ricoh RN5T567 or
+ RN5T618 PMIC.
config REGULATOR_RT5033
tristate "Richtek RT5033 Regulators"
@@ -810,7 +828,7 @@ config REGULATOR_TPS65912
This driver supports TPS65912 voltage regulator chip.
config REGULATOR_TPS80031
- tristate "TI TPS80031/TPS80032 power regualtor driver"
+ tristate "TI TPS80031/TPS80032 power regulator driver"
depends on MFD_TPS80031
help
TPS80031/ TPS80032 Fully Integrated Power Management with Power
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 85a1d44a3939..2142a5d3fc08 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o
obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
+obj-$(CONFIG_REGULATOR_LTC3676) += ltc3676.o
obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
@@ -65,6 +66,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
+obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c
index 84c1ee39ddae..2ca00045eb99 100644
--- a/drivers/regulator/ab8500-ext.c
+++ b/drivers/regulator/ab8500-ext.c
@@ -25,6 +25,456 @@
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/ab8500.h>
+static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
+ /* Main display, u8500 R3 uib */
+ REGULATOR_SUPPLY("vddi", "mcde_disp_sony_acx424akp.0"),
+ /* Main display, u8500 uib and ST uib */
+ REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.0"),
+ /* Secondary display, ST uib */
+ REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.1"),
+ /* SFH7741 proximity sensor */
+ REGULATOR_SUPPLY("vcc", "gpio-keys.0"),
+ /* BH1780GLS ambient light sensor */
+ REGULATOR_SUPPLY("vcc", "2-0029"),
+ /* lsm303dlh accelerometer */
+ REGULATOR_SUPPLY("vdd", "2-0018"),
+ /* lsm303dlhc accelerometer */
+ REGULATOR_SUPPLY("vdd", "2-0019"),
+ /* lsm303dlh magnetometer */
+ REGULATOR_SUPPLY("vdd", "2-001e"),
+ /* Rohm BU21013 Touchscreen devices */
+ REGULATOR_SUPPLY("avdd", "3-005c"),
+ REGULATOR_SUPPLY("avdd", "3-005d"),
+ /* Synaptics RMI4 Touchscreen device */
+ REGULATOR_SUPPLY("vdd", "3-004b"),
+ /* L3G4200D Gyroscope device */
+ REGULATOR_SUPPLY("vdd", "2-0068"),
+ /* Ambient light sensor device */
+ REGULATOR_SUPPLY("vdd", "3-0029"),
+ /* Pressure sensor device */
+ REGULATOR_SUPPLY("vdd", "2-005c"),
+ /* Cypress TrueTouch Touchscreen device */
+ REGULATOR_SUPPLY("vcpin", "spi8.0"),
+ /* Camera device */
+ REGULATOR_SUPPLY("vaux12v5", "mmio_camera"),
+};
+
+static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
+ /* On-board eMMC power */
+ REGULATOR_SUPPLY("vmmc", "sdi4"),
+ /* AB8500 audio codec */
+ REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"),
+ /* AB8500 accessory detect 1 */
+ REGULATOR_SUPPLY("vcc-N2158", "ab8500-acc-det.0"),
+ /* AB8500 Tv-out device */
+ REGULATOR_SUPPLY("vcc-N2158", "mcde_tv_ab8500.4"),
+ /* AV8100 HDMI device */
+ REGULATOR_SUPPLY("vcc-N2158", "av8100_hdmi.3"),
+};
+
+static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
+ REGULATOR_SUPPLY("v-SD-STM", "stm"),
+ /* External MMC slot power */
+ REGULATOR_SUPPLY("vmmc", "sdi0"),
+};
+
+static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
+ /* TV-out DENC supply */
+ REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"),
+ /* Internal general-purpose ADC */
+ REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
+ /* ADC for charger */
+ REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
+ /* AB8500 Tv-out device */
+ REGULATOR_SUPPLY("vtvout", "mcde_tv_ab8500.4"),
+};
+
+static struct regulator_consumer_supply ab8500_vaud_consumers[] = {
+ /* AB8500 audio-codec main supply */
+ REGULATOR_SUPPLY("vaud", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vamic1_consumers[] = {
+ /* AB8500 audio-codec Mic1 supply */
+ REGULATOR_SUPPLY("vamic1", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vamic2_consumers[] = {
+ /* AB8500 audio-codec Mic2 supply */
+ REGULATOR_SUPPLY("vamic2", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vdmic_consumers[] = {
+ /* AB8500 audio-codec DMic supply */
+ REGULATOR_SUPPLY("vdmic", "ab8500-codec.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
+ /* SoC core supply, no device */
+ REGULATOR_SUPPLY("v-intcore", NULL),
+ /* USB Transceiver */
+ REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"),
+ /* Handled by abx500 clk driver */
+ REGULATOR_SUPPLY("v-intcore", "abx500-clk.0"),
+};
+
+static struct regulator_consumer_supply ab8500_vana_consumers[] = {
+ /* DB8500 DSI */
+ REGULATOR_SUPPLY("vdddsi1v2", "mcde"),
+ REGULATOR_SUPPLY("vdddsi1v2", "b2r2_core"),
+ REGULATOR_SUPPLY("vdddsi1v2", "b2r2_1_core"),
+ REGULATOR_SUPPLY("vdddsi1v2", "dsilink.0"),
+ REGULATOR_SUPPLY("vdddsi1v2", "dsilink.1"),
+ REGULATOR_SUPPLY("vdddsi1v2", "dsilink.2"),
+ /* DB8500 CSI */
+ REGULATOR_SUPPLY("vddcsi1v2", "mmio_camera"),
+};
+
+/* ab8500 regulator register initialization */
+static struct ab8500_regulator_reg_init ab8500_reg_init[] = {
+ /*
+ * VanaRequestCtrl = HP/LP depending on VxRequest
+ * VextSupply1RequestCtrl = HP/LP depending on VxRequest
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xf0, 0x00),
+ /*
+ * VextSupply2RequestCtrl = HP/LP depending on VxRequest
+ * VextSupply3RequestCtrl = HP/LP depending on VxRequest
+ * Vaux1RequestCtrl = HP/LP depending on VxRequest
+ * Vaux2RequestCtrl = HP/LP depending on VxRequest
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0xff, 0x00),
+ /*
+ * Vaux3RequestCtrl = HP/LP depending on VxRequest
+ * SwHPReq = Control through SWValid disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x07, 0x00),
+ /*
+ * VanaSysClkReq1HPValid = disabled
+ * Vaux1SysClkReq1HPValid = disabled
+ * Vaux2SysClkReq1HPValid = disabled
+ * Vaux3SysClkReq1HPValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
+ /*
+ * VextSupply1SysClkReq1HPValid = disabled
+ * VextSupply2SysClkReq1HPValid = disabled
+ * VextSupply3SysClkReq1HPValid = SysClkReq1 controlled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x70, 0x40),
+ /*
+ * VanaHwHPReq1Valid = disabled
+ * Vaux1HwHPreq1Valid = disabled
+ * Vaux2HwHPReq1Valid = disabled
+ * Vaux3HwHPReqValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0xe8, 0x00),
+ /*
+ * VextSupply1HwHPReq1Valid = disabled
+ * VextSupply2HwHPReq1Valid = disabled
+ * VextSupply3HwHPReq1Valid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x07, 0x00),
+ /*
+ * VanaHwHPReq2Valid = disabled
+ * Vaux1HwHPReq2Valid = disabled
+ * Vaux2HwHPReq2Valid = disabled
+ * Vaux3HwHPReq2Valid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0xe8, 0x00),
+ /*
+ * VextSupply1HwHPReq2Valid = disabled
+ * VextSupply2HwHPReq2Valid = disabled
+ * VextSupply3HwHPReq2Valid = HWReq2 controlled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x07, 0x04),
+ /*
+ * VanaSwHPReqValid = disabled
+ * Vaux1SwHPReqValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0xa0, 0x00),
+ /*
+ * Vaux2SwHPReqValid = disabled
+ * Vaux3SwHPReqValid = disabled
+ * VextSupply1SwHPReqValid = disabled
+ * VextSupply2SwHPReqValid = disabled
+ * VextSupply3SwHPReqValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x1f, 0x00),
+ /*
+ * SysClkReq2Valid1 = SysClkReq2 controlled
+ * SysClkReq3Valid1 = disabled
+ * SysClkReq4Valid1 = SysClkReq4 controlled
+ * SysClkReq5Valid1 = disabled
+ * SysClkReq6Valid1 = SysClkReq6 controlled
+ * SysClkReq7Valid1 = disabled
+ * SysClkReq8Valid1 = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0xfe, 0x2a),
+ /*
+ * SysClkReq2Valid2 = disabled
+ * SysClkReq3Valid2 = disabled
+ * SysClkReq4Valid2 = disabled
+ * SysClkReq5Valid2 = disabled
+ * SysClkReq6Valid2 = SysClkReq6 controlled
+ * SysClkReq7Valid2 = disabled
+ * SysClkReq8Valid2 = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0xfe, 0x20),
+ /*
+ * VTVoutEna = disabled
+ * Vintcore12Ena = disabled
+ * Vintcore12Sel = 1.25 V
+ * Vintcore12LP = inactive (HP)
+ * VTVoutLP = inactive (HP)
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0xfe, 0x10),
+ /*
+ * VaudioEna = disabled
+ * VdmicEna = disabled
+ * Vamic1Ena = disabled
+ * Vamic2Ena = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x1e, 0x00),
+ /*
+ * Vamic1_dzout = high-Z when Vamic1 is disabled
+ * Vamic2_dzout = high-Z when Vamic2 is disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00),
+ /*
+ * VPll = Hw controlled (NOTE! PRCMU bits)
+ * VanaRegu = force off
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x0f, 0x02),
+ /*
+ * VrefDDREna = disabled
+ * VrefDDRSleepMode = inactive (no pulldown)
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x03, 0x00),
+ /*
+ * VextSupply1Regu = force LP
+ * VextSupply2Regu = force OFF
+ * VextSupply3Regu = force HP (-> STBB2=LP and TPS=LP)
+ * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
+ * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
+ */
+ INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0xff, 0x13),
+ /*
+ * Vaux1Regu = force HP
+ * Vaux2Regu = force off
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x0f, 0x01),
+ /*
+ * Vaux3Regu = force off
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x03, 0x00),
+ /*
+ * Vaux1Sel = 2.8 V
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x0f, 0x0C),
+ /*
+ * Vaux2Sel = 2.9 V
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0f, 0x0d),
+ /*
+ * Vaux3Sel = 2.91 V
+ */
+ INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07, 0x07),
+ /*
+ * VextSupply12LP = disabled (no LP)
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x01, 0x00),
+ /*
+ * Vaux1Disch = short discharge time
+ * Vaux2Disch = short discharge time
+ * Vaux3Disch = short discharge time
+ * Vintcore12Disch = short discharge time
+ * VTVoutDisch = short discharge time
+ * VaudioDisch = short discharge time
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0xfc, 0x00),
+ /*
+ * VanaDisch = short discharge time
+ * VdmicPullDownEna = pulldown disabled when Vdmic is disabled
+ * VdmicDisch = short discharge time
+ */
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x16, 0x00),
+};
+
+/* AB8500 regulators */
+static struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
+ /* supplies to the display/camera */
+ [AB8500_LDO_AUX1] = {
+ .supply_regulator = "ab8500-ext-supply3",
+ .constraints = {
+ .name = "V-DISPLAY",
+ .min_uV = 2800000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .boot_on = 1, /* display is on at boot */
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
+ .consumer_supplies = ab8500_vaux1_consumers,
+ },
+ /* supplies to the on-board eMMC */
+ [AB8500_LDO_AUX2] = {
+ .supply_regulator = "ab8500-ext-supply3",
+ .constraints = {
+ .name = "V-eMMC1",
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
+ .consumer_supplies = ab8500_vaux2_consumers,
+ },
+ /* supply for VAUX3, supplies to SDcard slots */
+ [AB8500_LDO_AUX3] = {
+ .supply_regulator = "ab8500-ext-supply3",
+ .constraints = {
+ .name = "V-MMC-SD",
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
+ .consumer_supplies = ab8500_vaux3_consumers,
+ },
+ /* supply for tvout, gpadc, TVOUT LDO */
+ [AB8500_LDO_TVOUT] = {
+ .constraints = {
+ .name = "V-TVOUT",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vtvout_consumers),
+ .consumer_supplies = ab8500_vtvout_consumers,
+ },
+ /* supply for ab8500-vaudio, VAUDIO LDO */
+ [AB8500_LDO_AUDIO] = {
+ .constraints = {
+ .name = "V-AUD",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
+ .consumer_supplies = ab8500_vaud_consumers,
+ },
+ /* supply for v-anamic1 VAMic1-LDO */
+ [AB8500_LDO_ANAMIC1] = {
+ .constraints = {
+ .name = "V-AMIC1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
+ .consumer_supplies = ab8500_vamic1_consumers,
+ },
+ /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
+ [AB8500_LDO_ANAMIC2] = {
+ .constraints = {
+ .name = "V-AMIC2",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
+ .consumer_supplies = ab8500_vamic2_consumers,
+ },
+ /* supply for v-dmic, VDMIC LDO */
+ [AB8500_LDO_DMIC] = {
+ .constraints = {
+ .name = "V-DMIC",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vdmic_consumers),
+ .consumer_supplies = ab8500_vdmic_consumers,
+ },
+ /* supply for v-intcore12, VINTCORE12 LDO */
+ [AB8500_LDO_INTCORE] = {
+ .constraints = {
+ .name = "V-INTCORE",
+ .min_uV = 1250000,
+ .max_uV = 1350000,
+ .input_uV = 1800000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE |
+ REGULATOR_CHANGE_DRMS,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
+ .consumer_supplies = ab8500_vintcore_consumers,
+ },
+ /* supply for U8500 CSI-DSI, VANA LDO */
+ [AB8500_LDO_ANA] = {
+ .constraints = {
+ .name = "V-CSI-DSI",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
+ .consumer_supplies = ab8500_vana_consumers,
+ },
+};
+
+/* supply for VextSupply3 */
+static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = {
+ /* SIM supply for 3 V SIM cards */
+ REGULATOR_SUPPLY("vinvsim", "sim-detect.0"),
+};
+
+/*
+ * AB8500 external regulators
+ */
+static struct regulator_init_data ab8500_ext_regulators[] = {
+ /* fixed Vbat supplies VSMPS1_EXT_1V8 */
+ [AB8500_EXT_SUPPLY1] = {
+ .constraints = {
+ .name = "ab8500-ext-supply1",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .initial_mode = REGULATOR_MODE_IDLE,
+ .boot_on = 1,
+ .always_on = 1,
+ },
+ },
+ /* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */
+ [AB8500_EXT_SUPPLY2] = {
+ .constraints = {
+ .name = "ab8500-ext-supply2",
+ .min_uV = 1360000,
+ .max_uV = 1360000,
+ },
+ },
+ /* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */
+ [AB8500_EXT_SUPPLY3] = {
+ .constraints = {
+ .name = "ab8500-ext-supply3",
+ .min_uV = 3400000,
+ .max_uV = 3400000,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies =
+ ARRAY_SIZE(ab8500_ext_supply3_consumers),
+ .consumer_supplies = ab8500_ext_supply3_consumers,
+ },
+};
+
+static struct ab8500_regulator_platform_data ab8500_regulator_plat_data = {
+ .reg_init = ab8500_reg_init,
+ .num_reg_init = ARRAY_SIZE(ab8500_reg_init),
+ .regulator = ab8500_regulators,
+ .num_regulator = ARRAY_SIZE(ab8500_regulators),
+ .ext_regulator = ab8500_ext_regulators,
+ .num_ext_regulator = ARRAY_SIZE(ab8500_ext_regulators),
+};
+
/**
* struct ab8500_ext_regulator_info - ab8500 regulator information
* @dev: device pointer
@@ -344,8 +794,7 @@ static struct of_regulator_match ab8500_ext_regulator_match[] = {
static int ab8500_ext_regulator_probe(struct platform_device *pdev)
{
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
- struct ab8500_platform_data *ppdata;
- struct ab8500_regulator_platform_data *pdata;
+ struct ab8500_regulator_platform_data *pdata = &ab8500_regulator_plat_data;
struct device_node *np = pdev->dev.of_node;
struct regulator_config config = { };
int i, err;
@@ -366,18 +815,6 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev)
return -EINVAL;
}
- ppdata = dev_get_platdata(ab8500->dev);
- if (!ppdata) {
- dev_err(&pdev->dev, "null parent pdata\n");
- return -EINVAL;
- }
-
- pdata = ppdata->regulator;
- if (!pdata) {
- dev_err(&pdev->dev, "null pdata\n");
- return -EINVAL;
- }
-
/* make sure the platform data has the correct size */
if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) {
dev_err(&pdev->dev, "Configuration error: size mismatch.\n");
diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c
index a1cd0d4f8257..7652477e6a9d 100644
--- a/drivers/regulator/act8865-regulator.c
+++ b/drivers/regulator/act8865-regulator.c
@@ -395,12 +395,6 @@ static int act8865_pdata_from_dt(struct device *dev,
struct act8865_regulator_data *regulator;
struct of_regulator_match *matches;
- np = of_get_child_by_name(dev->of_node, "regulators");
- if (!np) {
- dev_err(dev, "missing 'regulators' subnode in DT\n");
- return -EINVAL;
- }
-
switch (type) {
case ACT8600:
matches = act8600_matches;
@@ -419,6 +413,12 @@ static int act8865_pdata_from_dt(struct device *dev,
return -EINVAL;
}
+ np = of_get_child_by_name(dev->of_node, "regulators");
+ if (!np) {
+ dev_err(dev, "missing 'regulators' subnode in DT\n");
+ return -EINVAL;
+ }
+
matched = of_regulator_match(dev, np, matches, num_matches);
of_node_put(np);
if (matched <= 0)
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 63cd5e68c864..3a6d0290c54c 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -296,7 +296,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
if (!sreg->sel && !strcmp(sreg->name, "vddpu"))
sreg->sel = 22;
- if (!sreg->sel) {
+ if (!sreg->bypass && !sreg->sel) {
dev_err(&pdev->dev, "Failed to read a valid default voltage selector.\n");
return -EINVAL;
}
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 514a5e8fdbab..54382ef902c6 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -36,6 +36,8 @@
#define AXP20X_FREQ_DCDC_MASK 0x0f
+#define AXP22X_MISC_N_VBUSEN_FUNC BIT(4)
+
#define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
_vmask, _ereg, _emask, _enable_val, _disable_val) \
[_family##_##_id] = { \
@@ -230,9 +232,125 @@ static const struct regulator_desc axp22x_regulators[] = {
AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000),
};
+static const struct regulator_desc axp22x_drivevbus_regulator = {
+ .name = "drivevbus",
+ .supply_name = "drivevbus",
+ .of_match = of_match_ptr("drivevbus"),
+ .regulators_node = of_match_ptr("regulators"),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .enable_reg = AXP20X_VBUS_IPSOUT_MGMT,
+ .enable_mask = BIT(2),
+ .ops = &axp20x_ops_sw,
+};
+
+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 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)),
+ AXP_DESC(AXP809, DCDC2, "dcdc2", "vin2", 600, 1540, 20,
+ AXP22X_DCDC2_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(2)),
+ AXP_DESC(AXP809, DCDC3, "dcdc3", "vin3", 600, 1860, 20,
+ AXP22X_DCDC3_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)),
+ AXP_DESC_RANGES(AXP809, DCDC4, "dcdc4", "vin4", axp809_dcdc4_ranges,
+ 57, AXP22X_DCDC4_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1,
+ BIT(4)),
+ AXP_DESC(AXP809, DCDC5, "dcdc5", "vin5", 1000, 2550, 50,
+ AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)),
+ /* secondary switchable output of DCDC1 */
+ AXP_DESC_SW(AXP809, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2,
+ BIT(7)),
+ /* LDO regulator internally chained to DCDC5 */
+ AXP_DESC(AXP809, DC5LDO, "dc5ldo", NULL, 700, 1400, 100,
+ AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)),
+ AXP_DESC(AXP809, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
+ AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)),
+ AXP_DESC(AXP809, ALDO2, "aldo2", "aldoin", 700, 3300, 100,
+ 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", axp806_cldo2_ranges,
+ 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2,
+ BIT(3)),
+ AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100,
+ AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(4)),
+ AXP_DESC(AXP809, ELDO1, "eldo1", "eldoin", 700, 3300, 100,
+ AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)),
+ AXP_DESC(AXP809, ELDO2, "eldo2", "eldoin", 700, 3300, 100,
+ AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)),
+ AXP_DESC(AXP809, ELDO3, "eldo3", "eldoin", 700, 3300, 100,
+ AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)),
+ AXP_DESC_IO(AXP809, LDO_IO0, "ldo_io0", "ips", 700, 3300, 100,
+ AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07,
+ AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
+ AXP_DESC_IO(AXP809, LDO_IO1, "ldo_io1", "ips", 700, 3300, 100,
+ AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07,
+ AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
+ AXP_DESC_FIXED(AXP809, RTC_LDO, "rtc_ldo", "ips", 1800),
+ AXP_DESC_SW(AXP809, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(6)),
+};
+
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) {
@@ -243,8 +361,17 @@ 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:
min = 1800;
max = 4050;
def = 3000;
@@ -273,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);
}
@@ -307,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) {
@@ -322,8 +450,16 @@ 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:
if (id < AXP22X_DCDC1 || id > AXP22X_DCDC5)
return -EINVAL;
@@ -337,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, &reg);
+
+ 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)
@@ -352,8 +515,9 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
};
int ret, i, nregulators;
u32 workmode;
- const char *axp22x_dc1_name = axp22x_regulators[AXP22X_DCDC1].name;
- const char *axp22x_dc5_name = axp22x_regulators[AXP22X_DCDC5].name;
+ const char *dcdc1_name = axp22x_regulators[AXP22X_DCDC1].name;
+ const char *dcdc5_name = axp22x_regulators[AXP22X_DCDC5].name;
+ bool drivevbus = false;
switch (axp20x->variant) {
case AXP202_ID:
@@ -365,6 +529,16 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
case AXP223_ID:
regulators = axp22x_regulators;
nregulators = AXP22X_REG_ID_MAX;
+ 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;
break;
default:
dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n",
@@ -380,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.
*
@@ -388,22 +570,22 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
* part of this loop to see where we save the DT defined
* name.
*/
- if (regulators == axp22x_regulators) {
- if (i == AXP22X_DC1SW) {
- new_desc = devm_kzalloc(&pdev->dev,
- sizeof(*desc),
- GFP_KERNEL);
- *new_desc = regulators[i];
- new_desc->supply_name = axp22x_dc1_name;
- desc = new_desc;
- } else if (i == AXP22X_DC5LDO) {
- new_desc = devm_kzalloc(&pdev->dev,
- sizeof(*desc),
- GFP_KERNEL);
- *new_desc = regulators[i];
- new_desc->supply_name = axp22x_dc5_name;
- desc = new_desc;
- }
+ if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) ||
+ (regulators == axp809_regulators && i == AXP809_DC1SW)) {
+ new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc),
+ GFP_KERNEL);
+ *new_desc = regulators[i];
+ new_desc->supply_name = dcdc1_name;
+ desc = new_desc;
+ }
+
+ if ((regulators == axp22x_regulators && i == AXP22X_DC5LDO) ||
+ (regulators == axp809_regulators && i == AXP809_DC5LDO)) {
+ new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc),
+ GFP_KERNEL);
+ *new_desc = regulators[i];
+ new_desc->supply_name = dcdc5_name;
+ desc = new_desc;
}
rdev = devm_regulator_register(&pdev->dev, desc, &config);
@@ -426,16 +608,29 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
/*
* Save AXP22X DCDC1 / DCDC5 regulator names for later.
*/
- if (regulators == axp22x_regulators) {
- /* Can we use rdev->constraints->name instead? */
- if (i == AXP22X_DCDC1)
- of_property_read_string(rdev->dev.of_node,
- "regulator-name",
- &axp22x_dc1_name);
- else if (i == AXP22X_DCDC5)
- of_property_read_string(rdev->dev.of_node,
- "regulator-name",
- &axp22x_dc5_name);
+ if ((regulators == axp22x_regulators && i == AXP22X_DCDC1) ||
+ (regulators == axp809_regulators && i == AXP809_DCDC1))
+ of_property_read_string(rdev->dev.of_node,
+ "regulator-name",
+ &dcdc1_name);
+
+ if ((regulators == axp22x_regulators && i == AXP22X_DCDC5) ||
+ (regulators == axp809_regulators && i == AXP809_DCDC5))
+ of_property_read_string(rdev->dev.of_node,
+ "regulator-name",
+ &dcdc5_name);
+ }
+
+ if (drivevbus) {
+ /* Change N_VBUSEN sense pin to DRIVEVBUS output pin */
+ regmap_update_bits(axp20x->regmap, AXP20X_OVER_TMP,
+ AXP22X_MISC_N_VBUSEN_FUNC, 0);
+ rdev = devm_regulator_register(&pdev->dev,
+ &axp22x_drivevbus_regulator,
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "Failed to register drivevbus\n");
+ return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index ec8184d53f13..08260c215895 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -679,24 +679,6 @@ static int drms_uA_update(struct regulator_dev *rdev)
!rdev->desc->ops->set_load)
return -EINVAL;
- /* get output voltage */
- output_uV = _regulator_get_voltage(rdev);
- if (output_uV <= 0) {
- rdev_err(rdev, "invalid output voltage found\n");
- return -EINVAL;
- }
-
- /* get input voltage */
- input_uV = 0;
- if (rdev->supply)
- input_uV = regulator_get_voltage(rdev->supply);
- if (input_uV <= 0)
- input_uV = rdev->constraints->input_uV;
- if (input_uV <= 0) {
- rdev_err(rdev, "invalid input voltage found\n");
- return -EINVAL;
- }
-
/* calc total requested load */
list_for_each_entry(sibling, &rdev->consumer_list, list)
current_uA += sibling->uA_load;
@@ -709,6 +691,24 @@ static int drms_uA_update(struct regulator_dev *rdev)
if (err < 0)
rdev_err(rdev, "failed to set load %d\n", current_uA);
} else {
+ /* get output voltage */
+ output_uV = _regulator_get_voltage(rdev);
+ if (output_uV <= 0) {
+ rdev_err(rdev, "invalid output voltage found\n");
+ return -EINVAL;
+ }
+
+ /* get input voltage */
+ input_uV = 0;
+ if (rdev->supply)
+ input_uV = regulator_get_voltage(rdev->supply);
+ if (input_uV <= 0)
+ input_uV = rdev->constraints->input_uV;
+ if (input_uV <= 0) {
+ rdev_err(rdev, "invalid input voltage found\n");
+ return -EINVAL;
+ }
+
/* now get the optimum mode for our new total regulator load */
mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV,
output_uV, current_uA);
@@ -2509,33 +2509,6 @@ int regulator_is_enabled(struct regulator *regulator)
EXPORT_SYMBOL_GPL(regulator_is_enabled);
/**
- * regulator_can_change_voltage - check if regulator can change voltage
- * @regulator: regulator source
- *
- * Returns positive if the regulator driver backing the source/client
- * can change its voltage, false otherwise. Useful for detecting fixed
- * or dummy regulators and disabling voltage change logic in the client
- * driver.
- */
-int regulator_can_change_voltage(struct regulator *regulator)
-{
- struct regulator_dev *rdev = regulator->rdev;
-
- if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
- if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1)
- return 1;
-
- if (rdev->desc->continuous_voltage_range &&
- rdev->constraints->min_uV && rdev->constraints->max_uV &&
- rdev->constraints->min_uV != rdev->constraints->max_uV)
- return 1;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(regulator_can_change_voltage);
-
-/**
* regulator_count_voltages - count regulator_list_voltage() selectors
* @regulator: regulator source
*
@@ -2770,6 +2743,24 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev,
return ret;
}
+static int _regulator_set_voltage_time(struct regulator_dev *rdev,
+ int old_uV, int new_uV)
+{
+ unsigned int ramp_delay = 0;
+
+ if (rdev->constraints->ramp_delay)
+ ramp_delay = rdev->constraints->ramp_delay;
+ else if (rdev->desc->ramp_delay)
+ ramp_delay = rdev->desc->ramp_delay;
+
+ if (ramp_delay == 0) {
+ rdev_warn(rdev, "ramp_delay not set\n");
+ return 0;
+ }
+
+ return DIV_ROUND_UP(abs(new_uV - old_uV), ramp_delay);
+}
+
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
@@ -2778,6 +2769,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int best_val = 0;
unsigned int selector;
int old_selector = -1;
+ const struct regulator_ops *ops = rdev->desc->ops;
+ int old_uV = _regulator_get_voltage(rdev);
trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
@@ -2789,29 +2782,28 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
* info to call set_voltage_time_sel().
*/
if (_regulator_is_enabled(rdev) &&
- rdev->desc->ops->set_voltage_time_sel &&
- rdev->desc->ops->get_voltage_sel) {
- old_selector = rdev->desc->ops->get_voltage_sel(rdev);
+ ops->set_voltage_time_sel && ops->get_voltage_sel) {
+ old_selector = ops->get_voltage_sel(rdev);
if (old_selector < 0)
return old_selector;
}
- if (rdev->desc->ops->set_voltage) {
+ if (ops->set_voltage) {
ret = _regulator_call_set_voltage(rdev, min_uV, max_uV,
&selector);
if (ret >= 0) {
- if (rdev->desc->ops->list_voltage)
- best_val = rdev->desc->ops->list_voltage(rdev,
- selector);
+ if (ops->list_voltage)
+ best_val = ops->list_voltage(rdev,
+ selector);
else
best_val = _regulator_get_voltage(rdev);
}
- } else if (rdev->desc->ops->set_voltage_sel) {
+ } else if (ops->set_voltage_sel) {
ret = regulator_map_voltage(rdev, min_uV, max_uV);
if (ret >= 0) {
- best_val = rdev->desc->ops->list_voltage(rdev, ret);
+ best_val = ops->list_voltage(rdev, ret);
if (min_uV <= best_val && max_uV >= best_val) {
selector = ret;
if (old_selector == selector)
@@ -2827,34 +2819,50 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
ret = -EINVAL;
}
- /* Call set_voltage_time_sel if successfully obtained old_selector */
- if (ret == 0 && !rdev->constraints->ramp_disable && old_selector >= 0
- && old_selector != selector) {
+ if (ret)
+ goto out;
- delay = rdev->desc->ops->set_voltage_time_sel(rdev,
- old_selector, selector);
- if (delay < 0) {
- rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n",
- delay);
- delay = 0;
+ if (ops->set_voltage_time_sel) {
+ /*
+ * Call set_voltage_time_sel if successfully obtained
+ * old_selector
+ */
+ if (old_selector >= 0 && old_selector != selector)
+ delay = ops->set_voltage_time_sel(rdev, old_selector,
+ selector);
+ } else {
+ if (old_uV != best_val) {
+ if (ops->set_voltage_time)
+ delay = ops->set_voltage_time(rdev, old_uV,
+ best_val);
+ else
+ delay = _regulator_set_voltage_time(rdev,
+ old_uV,
+ best_val);
}
+ }
- /* Insert any necessary delays */
- if (delay >= 1000) {
- mdelay(delay / 1000);
- udelay(delay % 1000);
- } else if (delay) {
- udelay(delay);
- }
+ if (delay < 0) {
+ rdev_warn(rdev, "failed to get delay: %d\n", delay);
+ delay = 0;
+ }
+
+ /* Insert any necessary delays */
+ if (delay >= 1000) {
+ mdelay(delay / 1000);
+ udelay(delay % 1000);
+ } else if (delay) {
+ udelay(delay);
}
- if (ret == 0 && best_val >= 0) {
+ if (best_val >= 0) {
unsigned long data = best_val;
_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
(void *)data);
}
+out:
trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val);
return ret;
@@ -3025,9 +3033,13 @@ int regulator_set_voltage_time(struct regulator *regulator,
int voltage;
int i;
+ if (ops->set_voltage_time)
+ return ops->set_voltage_time(rdev, old_uV, new_uV);
+ else if (!ops->set_voltage_time_sel)
+ return _regulator_set_voltage_time(rdev, old_uV, new_uV);
+
/* Currently requires operations to do this */
- if (!ops->list_voltage || !ops->set_voltage_time_sel
- || !rdev->desc->n_voltages)
+ if (!ops->list_voltage || !rdev->desc->n_voltages)
return -EINVAL;
for (i = 0; i < rdev->desc->n_voltages; i++) {
@@ -3066,19 +3078,8 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int old_selector,
unsigned int new_selector)
{
- unsigned int ramp_delay = 0;
int old_volt, new_volt;
- if (rdev->constraints->ramp_delay)
- ramp_delay = rdev->constraints->ramp_delay;
- else if (rdev->desc->ramp_delay)
- ramp_delay = rdev->desc->ramp_delay;
-
- if (ramp_delay == 0) {
- rdev_warn(rdev, "ramp_delay not set\n");
- return 0;
- }
-
/* sanity check */
if (!rdev->desc->ops->list_voltage)
return -EINVAL;
@@ -3086,7 +3087,11 @@ int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
old_volt = rdev->desc->ops->list_voltage(rdev, old_selector);
new_volt = rdev->desc->ops->list_voltage(rdev, new_selector);
- return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+ if (rdev->desc->ops->set_voltage_time)
+ return rdev->desc->ops->set_voltage_time(rdev, old_volt,
+ new_volt);
+ else
+ return _regulator_set_voltage_time(rdev, old_volt, new_volt);
}
EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
@@ -3354,6 +3359,39 @@ unsigned int regulator_get_mode(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL(regulator_get_mode);
+static int _regulator_get_error_flags(struct regulator_dev *rdev,
+ unsigned int *flags)
+{
+ int ret;
+
+ mutex_lock(&rdev->mutex);
+
+ /* sanity check */
+ if (!rdev->desc->ops->get_error_flags) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = rdev->desc->ops->get_error_flags(rdev, flags);
+out:
+ mutex_unlock(&rdev->mutex);
+ return ret;
+}
+
+/**
+ * regulator_get_error_flags - get regulator error information
+ * @regulator: regulator source
+ * @flags: pointer to store error flags
+ *
+ * Get the current regulator error information.
+ */
+int regulator_get_error_flags(struct regulator *regulator,
+ unsigned int *flags)
+{
+ return _regulator_get_error_flags(regulator->rdev, flags);
+}
+EXPORT_SYMBOL_GPL(regulator_get_error_flags);
+
/**
* regulator_set_load - set regulator load
* @regulator: regulator source
@@ -3510,10 +3548,8 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
consumers[i].consumer = NULL;
for (i = 0; i < num_consumers; i++) {
- consumers[i].consumer = _regulator_get(dev,
- consumers[i].supply,
- false,
- !consumers[i].optional);
+ consumers[i].consumer = regulator_get(dev,
+ consumers[i].supply);
if (IS_ERR(consumers[i].consumer)) {
ret = PTR_ERR(consumers[i].consumer);
dev_err(dev, "Failed to get supply '%s': %d\n",
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 1050cb77561a..9ececfef42d6 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -333,7 +333,7 @@ static const struct regulator_ops da9052_ldo_ops = {
static struct da9052_regulator_info da9052_regulator_info[] = {
DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
- DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO),
+ DA9052_DCDC(BUCK3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),
DA9052_DCDC(BUCK4, 50, 1800, 3600, 5, 6, 0),
DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0),
DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
@@ -350,8 +350,8 @@ static struct da9052_regulator_info da9052_regulator_info[] = {
static struct da9052_regulator_info da9053_regulator_info[] = {
DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),
DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),
- DA9052_DCDC(BUCK3, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO),
- DA9052_DCDC(BUCK4, 25, 925, 2500, 6, 6, 0),
+ DA9052_DCDC(BUCK3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),
+ DA9052_DCDC(BUCK4, 25, 950, 2525, 6, 6, 0),
DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0),
DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),
DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),
diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c
index 01c0e3709b66..d0496d6b0934 100644
--- a/drivers/regulator/da9210-regulator.c
+++ b/drivers/regulator/da9210-regulator.c
@@ -21,12 +21,11 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/slab.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/of_device.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regmap.h>
@@ -179,6 +178,13 @@ error_i2c:
/*
* I2C driver interface functions
*/
+
+static const struct of_device_id da9210_dt_ids[] = {
+ { .compatible = "dlg,da9210", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da9210_dt_ids);
+
static int da9210_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -188,6 +194,16 @@ static int da9210_i2c_probe(struct i2c_client *i2c,
struct regulator_dev *rdev = NULL;
struct regulator_config config = { };
int error;
+ const struct of_device_id *match;
+
+ if (i2c->dev.of_node && !pdata) {
+ match = of_match_device(of_match_ptr(da9210_dt_ids),
+ &i2c->dev);
+ if (!match) {
+ dev_err(&i2c->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ }
chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL);
if (!chip)
@@ -264,6 +280,7 @@ MODULE_DEVICE_TABLE(i2c, da9210_i2c_id);
static struct i2c_driver da9210_regulator_driver = {
.driver = {
.name = "da9210",
+ .of_match_table = of_match_ptr(da9210_dt_ids),
},
.probe = da9210_i2c_probe,
.id_table = da9210_i2c_id,
diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c
index 236abf473db5..aa47280efd32 100644
--- a/drivers/regulator/da9211-regulator.c
+++ b/drivers/regulator/da9211-regulator.c
@@ -1,5 +1,6 @@
/*
- * da9211-regulator.c - Regulator device driver for DA9211/DA9213/DA9215
+ * da9211-regulator.c - Regulator device driver for DA9211/DA9212
+ * /DA9213/DA9214/DA9215
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*
* This library is free software; you can redistribute it and/or
@@ -493,7 +494,9 @@ static int da9211_i2c_probe(struct i2c_client *i2c,
static const struct i2c_device_id da9211_i2c_id[] = {
{"da9211", DA9211},
+ {"da9212", DA9212},
{"da9213", DA9213},
+ {"da9214", DA9214},
{"da9215", DA9215},
{},
};
@@ -502,8 +505,10 @@ MODULE_DEVICE_TABLE(i2c, da9211_i2c_id);
#ifdef CONFIG_OF
static const struct of_device_id da9211_dt_ids[] = {
{ .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] },
- { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] },
- { .compatible = "dlg,da9215", .data = &da9211_i2c_id[2] },
+ { .compatible = "dlg,da9212", .data = &da9211_i2c_id[1] },
+ { .compatible = "dlg,da9213", .data = &da9211_i2c_id[2] },
+ { .compatible = "dlg,da9214", .data = &da9211_i2c_id[3] },
+ { .compatible = "dlg,da9215", .data = &da9211_i2c_id[4] },
{},
};
MODULE_DEVICE_TABLE(of, da9211_dt_ids);
@@ -521,5 +526,5 @@ static struct i2c_driver da9211_regulator_driver = {
module_i2c_driver(da9211_regulator_driver);
MODULE_AUTHOR("James Ban <James.Ban.opensource@diasemi.com>");
-MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213/DA9215");
+MODULE_DESCRIPTION("DA9211/DA9212/DA9213/DA9214/DA9215 regulator driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h
index d6ad96fc64d3..b841bbf330cc 100644
--- a/drivers/regulator/da9211-regulator.h
+++ b/drivers/regulator/da9211-regulator.h
@@ -1,5 +1,6 @@
/*
- * da9211-regulator.h - Regulator definitions for DA9211/DA9213/DA9215
+ * da9211-regulator.h - Regulator definitions for DA9211/DA9212
+ * /DA9213/DA9214/DA9215
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c
index 3963dfad766c..8976141c1438 100644
--- a/drivers/regulator/dbx500-prcmu.c
+++ b/drivers/regulator/dbx500-prcmu.c
@@ -75,24 +75,6 @@ static struct ux500_regulator_debug {
u8 *state_after_suspend;
} rdebug;
-void ux500_regulator_suspend_debug(void)
-{
- int i;
-
- for (i = 0; i < rdebug.num_regulators; i++)
- rdebug.state_before_suspend[i] =
- rdebug.regulator_array[i].is_enabled;
-}
-
-void ux500_regulator_resume_debug(void)
-{
- int i;
-
- for (i = 0; i < rdebug.num_regulators; i++)
- rdebug.state_after_suspend[i] =
- rdebug.regulator_array[i].is_enabled;
-}
-
static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
{
/* print power state count */
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index 6ad8ab4c578d..6ec1d400adae 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -164,11 +164,8 @@ int devm_regulator_bulk_get(struct device *dev, int num_consumers,
consumers[i].consumer = NULL;
for (i = 0; i < num_consumers; i++) {
- consumers[i].consumer = _devm_regulator_get(dev,
- consumers[i].supply,
- consumers[i].optional ?
- OPTIONAL_GET :
- NORMAL_GET);
+ consumers[i].consumer = devm_regulator_get(dev,
+ consumers[i].supply);
if (IS_ERR(consumers[i].consumer)) {
ret = PTR_ERR(consumers[i].consumer);
dev_err(dev, "Failed to get supply '%s': %d\n",
diff --git a/drivers/regulator/hi6421-regulator.c b/drivers/regulator/hi6421-regulator.c
index 42dc5fb8c899..62c5f5445d44 100644
--- a/drivers/regulator/hi6421-regulator.c
+++ b/drivers/regulator/hi6421-regulator.c
@@ -477,7 +477,8 @@ static int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev,
return 0;
}
-unsigned int hi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev,
+static unsigned int
+hi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev,
int input_uV, int output_uV, int load_uA)
{
struct hi6421_regulator_info *info = rdev_get_drvdata(rdev);
diff --git a/drivers/regulator/lp873x-regulator.c b/drivers/regulator/lp873x-regulator.c
index b4ffd113ba21..e504b9148226 100644
--- a/drivers/regulator/lp873x-regulator.c
+++ b/drivers/regulator/lp873x-regulator.c
@@ -20,7 +20,7 @@
#include <linux/mfd/lp873x.h>
#define LP873X_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, _er, _em, \
- _delay, _lr, _nlr, _cr) \
+ _delay, _lr, _cr) \
[_id] = { \
.desc = { \
.name = _name, \
@@ -37,7 +37,7 @@
.enable_mask = _em, \
.ramp_delay = _delay, \
.linear_ranges = _lr, \
- .n_linear_ranges = _nlr, \
+ .n_linear_ranges = ARRAY_SIZE(_lr), \
}, \
.ctrl2_reg = _cr, \
}
@@ -175,22 +175,20 @@ static const struct lp873x_regulator regulators[] = {
256, LP873X_REG_BUCK0_VOUT,
LP873X_BUCK0_VOUT_BUCK0_VSET, LP873X_REG_BUCK0_CTRL_1,
LP873X_BUCK0_CTRL_1_BUCK0_EN, 10000,
- buck0_buck1_ranges, 4, LP873X_REG_BUCK0_CTRL_2),
+ buck0_buck1_ranges, LP873X_REG_BUCK0_CTRL_2),
LP873X_REGULATOR("BUCK1", LP873X_BUCK_1, "buck1", lp873x_buck01_ops,
256, LP873X_REG_BUCK1_VOUT,
LP873X_BUCK1_VOUT_BUCK1_VSET, LP873X_REG_BUCK1_CTRL_1,
LP873X_BUCK1_CTRL_1_BUCK1_EN, 10000,
- buck0_buck1_ranges, 4, LP873X_REG_BUCK1_CTRL_2),
+ buck0_buck1_ranges, LP873X_REG_BUCK1_CTRL_2),
LP873X_REGULATOR("LDO0", LP873X_LDO_0, "ldo0", lp873x_ldo01_ops, 26,
LP873X_REG_LDO0_VOUT, LP873X_LDO0_VOUT_LDO0_VSET,
LP873X_REG_LDO0_CTRL,
- LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 1,
- 0xFF),
+ LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 0xFF),
LP873X_REGULATOR("LDO1", LP873X_LDO_1, "ldo1", lp873x_ldo01_ops, 26,
LP873X_REG_LDO1_VOUT, LP873X_LDO1_VOUT_LDO1_VSET,
LP873X_REG_LDO1_CTRL,
- LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 1,
- 0xFF),
+ LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 0xFF),
};
static int lp873x_regulator_probe(struct platform_device *pdev)
diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c
new file mode 100644
index 000000000000..e2b476ca2b4d
--- /dev/null
+++ b/drivers/regulator/ltc3676.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2016 Gateworks Corporation, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define DRIVER_NAME "ltc3676"
+
+/* LTC3676 Registers */
+#define LTC3676_BUCK1 0x01
+#define LTC3676_BUCK2 0x02
+#define LTC3676_BUCK3 0x03
+#define LTC3676_BUCK4 0x04
+#define LTC3676_LDOA 0x05
+#define LTC3676_LDOB 0x06
+#define LTC3676_SQD1 0x07
+#define LTC3676_SQD2 0x08
+#define LTC3676_CNTRL 0x09
+#define LTC3676_DVB1A 0x0A
+#define LTC3676_DVB1B 0x0B
+#define LTC3676_DVB2A 0x0C
+#define LTC3676_DVB2B 0x0D
+#define LTC3676_DVB3A 0x0E
+#define LTC3676_DVB3B 0x0F
+#define LTC3676_DVB4A 0x10
+#define LTC3676_DVB4B 0x11
+#define LTC3676_MSKIRQ 0x12
+#define LTC3676_MSKPG 0x13
+#define LTC3676_USER 0x14
+#define LTC3676_IRQSTAT 0x15
+#define LTC3676_PGSTATL 0x16
+#define LTC3676_PGSTATRT 0x17
+#define LTC3676_HRST 0x1E
+#define LTC3676_CLIRQ 0x1F
+
+#define LTC3676_DVBxA_REF_SELECT BIT(5)
+
+#define LTC3676_IRQSTAT_PGOOD_TIMEOUT BIT(3)
+#define LTC3676_IRQSTAT_UNDERVOLT_WARN BIT(4)
+#define LTC3676_IRQSTAT_UNDERVOLT_FAULT BIT(5)
+#define LTC3676_IRQSTAT_THERMAL_WARN BIT(6)
+#define LTC3676_IRQSTAT_THERMAL_FAULT BIT(7)
+
+enum ltc3676_reg {
+ LTC3676_SW1,
+ LTC3676_SW2,
+ LTC3676_SW3,
+ LTC3676_SW4,
+ LTC3676_LDO1,
+ LTC3676_LDO2,
+ LTC3676_LDO3,
+ LTC3676_LDO4,
+ LTC3676_NUM_REGULATORS,
+};
+
+struct ltc3676 {
+ struct regmap *regmap;
+ struct device *dev;
+ struct regulator_desc regulator_descs[LTC3676_NUM_REGULATORS];
+ struct regulator_dev *regulators[LTC3676_NUM_REGULATORS];
+};
+
+static int ltc3676_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct ltc3676 *ltc3676 = rdev_get_drvdata(rdev);
+ struct device *dev = ltc3676->dev;
+ int dcdc = rdev_get_id(rdev);
+ int sel;
+
+ dev_dbg(dev, "%s id=%d uV=%d\n", __func__, dcdc, uV);
+ sel = regulator_map_voltage_linear(rdev, uV, uV);
+ if (sel < 0)
+ return sel;
+
+ /* DVBB register follows right after the corresponding DVBA register */
+ return regmap_update_bits(ltc3676->regmap, rdev->desc->vsel_reg + 1,
+ rdev->desc->vsel_mask, sel);
+}
+
+static int ltc3676_set_suspend_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct ltc3676 *ltc3676= rdev_get_drvdata(rdev);
+ struct device *dev = ltc3676->dev;
+ int mask, val;
+ int dcdc = rdev_get_id(rdev);
+
+ dev_dbg(dev, "%s id=%d mode=%d\n", __func__, dcdc, mode);
+
+ mask = LTC3676_DVBxA_REF_SELECT;
+ switch (mode) {
+ case REGULATOR_MODE_STANDBY:
+ val = 0; /* select DVBxA */
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = LTC3676_DVBxA_REF_SELECT; /* select DVBxB */
+ break;
+ default:
+ dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n",
+ rdev->desc->name, mode);
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(ltc3676->regmap, rdev->desc->vsel_reg,
+ mask, val);
+}
+
+static inline unsigned int ltc3676_scale(unsigned int uV, u32 r1, u32 r2)
+{
+ uint64_t tmp;
+ if (uV == 0)
+ return 0;
+ tmp = (uint64_t)uV * r1;
+ do_div(tmp, r2);
+ return uV + (unsigned int)tmp;
+}
+
+static int ltc3676_of_parse_cb(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ struct ltc3676 *ltc3676 = config->driver_data;
+ struct regulator_desc *rdesc = &ltc3676->regulator_descs[desc->id];
+ u32 r[2];
+ int ret;
+
+ /* LDO3 has a fixed output */
+ if (desc->id == LTC3676_LDO3)
+ return 0;
+
+ ret = of_property_read_u32_array(np, "lltc,fb-voltage-divider", r, 2);
+ if (ret) {
+ dev_err(ltc3676->dev, "Failed to parse voltage divider: %d\n",
+ ret);
+ return ret;
+ }
+
+ rdesc->min_uV = ltc3676_scale(desc->min_uV, r[0], r[1]);
+ rdesc->uV_step = ltc3676_scale(desc->uV_step, r[0], r[1]);
+ rdesc->fixed_uV = ltc3676_scale(desc->fixed_uV, r[0], r[1]);
+
+ return 0;
+}
+
+/* SW1, SW2, SW3, SW4 linear 0.8V-3.3V with scalar via R1/R2 feeback res */
+static struct regulator_ops ltc3676_linear_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_suspend_voltage = ltc3676_set_suspend_voltage,
+ .set_suspend_mode = ltc3676_set_suspend_mode,
+};
+
+/* LDO1 always on fixed 0.8V-3.3V via scalar via R1/R2 feeback res */
+static struct regulator_ops ltc3676_fixed_standby_regulator_ops = {
+};
+
+/* LDO2, LDO3 fixed (LDO2 has external scalar via R1/R2 feedback res) */
+static struct regulator_ops ltc3676_fixed_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+};
+
+#define LTC3676_REG(_id, _name, _ops, en_reg, en_bit, dvba_reg, dvb_mask) \
+ [LTC3676_ ## _id] = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .of_parse_cb = ltc3676_of_parse_cb, \
+ .n_voltages = (dvb_mask) + 1, \
+ .min_uV = (dvba_reg) ? 412500 : 0, \
+ .uV_step = (dvba_reg) ? 12500 : 0, \
+ .ramp_delay = (dvba_reg) ? 800 : 0, \
+ .fixed_uV = (dvb_mask) ? 0 : 725000, \
+ .ops = &ltc3676_ ## _ops ## _regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = LTC3676_ ## _id, \
+ .owner = THIS_MODULE, \
+ .vsel_reg = (dvba_reg), \
+ .vsel_mask = (dvb_mask), \
+ .enable_reg = (en_reg), \
+ .enable_mask = (1 << en_bit), \
+ }
+
+#define LTC3676_LINEAR_REG(_id, _name, _en, _dvba) \
+ LTC3676_REG(_id, _name, linear, \
+ LTC3676_ ## _en, 7, \
+ LTC3676_ ## _dvba, 0x1f)
+
+#define LTC3676_FIXED_REG(_id, _name, _en_reg, _en_bit) \
+ LTC3676_REG(_id, _name, fixed, LTC3676_ ## _en_reg, _en_bit, 0, 0)
+
+static struct regulator_desc ltc3676_regulators[LTC3676_NUM_REGULATORS] = {
+ LTC3676_LINEAR_REG(SW1, sw1, BUCK1, DVB1A),
+ LTC3676_LINEAR_REG(SW2, sw2, BUCK2, DVB2A),
+ LTC3676_LINEAR_REG(SW3, sw3, BUCK3, DVB3A),
+ LTC3676_LINEAR_REG(SW4, sw4, BUCK4, DVB4A),
+ LTC3676_REG(LDO1, ldo1, fixed_standby, 0, 0, 0, 0),
+ LTC3676_FIXED_REG(LDO2, ldo2, LDOA, 2),
+ LTC3676_FIXED_REG(LDO3, ldo3, LDOA, 5),
+ LTC3676_FIXED_REG(LDO4, ldo4, LDOB, 2),
+};
+
+static bool ltc3676_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LTC3676_IRQSTAT:
+ case LTC3676_BUCK1:
+ case LTC3676_BUCK2:
+ case LTC3676_BUCK3:
+ case LTC3676_BUCK4:
+ case LTC3676_LDOA:
+ case LTC3676_LDOB:
+ case LTC3676_SQD1:
+ case LTC3676_SQD2:
+ case LTC3676_CNTRL:
+ case LTC3676_DVB1A:
+ case LTC3676_DVB1B:
+ case LTC3676_DVB2A:
+ case LTC3676_DVB2B:
+ case LTC3676_DVB3A:
+ case LTC3676_DVB3B:
+ case LTC3676_DVB4A:
+ case LTC3676_DVB4B:
+ case LTC3676_MSKIRQ:
+ case LTC3676_MSKPG:
+ case LTC3676_USER:
+ case LTC3676_HRST:
+ case LTC3676_CLIRQ:
+ return true;
+ }
+ return false;
+}
+
+static bool ltc3676_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LTC3676_IRQSTAT:
+ case LTC3676_BUCK1:
+ case LTC3676_BUCK2:
+ case LTC3676_BUCK3:
+ case LTC3676_BUCK4:
+ case LTC3676_LDOA:
+ case LTC3676_LDOB:
+ case LTC3676_SQD1:
+ case LTC3676_SQD2:
+ case LTC3676_CNTRL:
+ case LTC3676_DVB1A:
+ case LTC3676_DVB1B:
+ case LTC3676_DVB2A:
+ case LTC3676_DVB2B:
+ case LTC3676_DVB3A:
+ case LTC3676_DVB3B:
+ case LTC3676_DVB4A:
+ case LTC3676_DVB4B:
+ case LTC3676_MSKIRQ:
+ case LTC3676_MSKPG:
+ case LTC3676_USER:
+ case LTC3676_HRST:
+ case LTC3676_CLIRQ:
+ return true;
+ }
+ return false;
+}
+
+static bool ltc3676_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case LTC3676_IRQSTAT:
+ case LTC3676_PGSTATL:
+ case LTC3676_PGSTATRT:
+ return true;
+ }
+ return false;
+}
+
+static const struct regmap_config ltc3676_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = ltc3676_writeable_reg,
+ .readable_reg = ltc3676_readable_reg,
+ .volatile_reg = ltc3676_volatile_reg,
+ .max_register = LTC3676_CLIRQ,
+ .use_single_rw = true,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static irqreturn_t ltc3676_isr(int irq, void *dev_id)
+{
+ struct ltc3676 *ltc3676 = dev_id;
+ struct device *dev = ltc3676->dev;
+ unsigned int i, irqstat, event;
+
+ regmap_read(ltc3676->regmap, LTC3676_IRQSTAT, &irqstat);
+
+ dev_dbg(dev, "irq%d irqstat=0x%02x\n", irq, irqstat);
+ if (irqstat & LTC3676_IRQSTAT_THERMAL_WARN) {
+ dev_warn(dev, "Over-temperature Warning\n");
+ event = REGULATOR_EVENT_OVER_TEMP;
+ for (i = 0; i < LTC3676_NUM_REGULATORS; i++)
+ regulator_notifier_call_chain(ltc3676->regulators[i],
+ event, NULL);
+ }
+
+ if (irqstat & LTC3676_IRQSTAT_UNDERVOLT_WARN) {
+ dev_info(dev, "Undervoltage Warning\n");
+ event = REGULATOR_EVENT_UNDER_VOLTAGE;
+ for (i = 0; i < LTC3676_NUM_REGULATORS; i++)
+ regulator_notifier_call_chain(ltc3676->regulators[i],
+ event, NULL);
+ }
+
+ /* Clear warning condition */
+ regmap_write(ltc3676->regmap, LTC3676_CLIRQ, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int ltc3676_regulator_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct regulator_init_data *init_data = dev_get_platdata(dev);
+ struct regulator_desc *descs;
+ struct ltc3676 *ltc3676;
+ int i, ret;
+
+ ltc3676 = devm_kzalloc(dev, sizeof(*ltc3676), GFP_KERNEL);
+ if (!ltc3676)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, ltc3676);
+ ltc3676->dev = dev;
+
+ descs = ltc3676->regulator_descs;
+ memcpy(descs, ltc3676_regulators, sizeof(ltc3676_regulators));
+ descs[LTC3676_LDO3].fixed_uV = 1800000; /* LDO3 is fixed 1.8V */
+
+ ltc3676->regmap = devm_regmap_init_i2c(client, &ltc3676_regmap_config);
+ if (IS_ERR(ltc3676->regmap)) {
+ ret = PTR_ERR(ltc3676->regmap);
+ dev_err(dev, "failed to initialize regmap: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < LTC3676_NUM_REGULATORS; i++) {
+ struct regulator_desc *desc = &ltc3676->regulator_descs[i];
+ struct regulator_config config = { };
+
+ if (init_data)
+ config.init_data = &init_data[i];
+
+ config.dev = dev;
+ config.driver_data = ltc3676;
+
+ ltc3676->regulators[i] = devm_regulator_register(dev, desc,
+ &config);
+ if (IS_ERR(ltc3676->regulators[i])) {
+ ret = PTR_ERR(ltc3676->regulators[i]);
+ dev_err(dev, "failed to register regulator %s: %d\n",
+ desc->name, ret);
+ return ret;
+ }
+ }
+
+ regmap_write(ltc3676->regmap, LTC3676_CLIRQ, 0);
+ if (client->irq) {
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ ltc3676_isr,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ client->name, ltc3676);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id ltc3676_i2c_id[] = {
+ { "ltc3676" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc3676_i2c_id);
+
+static struct i2c_driver ltc3676_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = ltc3676_regulator_probe,
+ .id_table = ltc3676_i2c_id,
+};
+module_i2c_driver(ltc3676_driver);
+
+MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>");
+MODULE_DESCRIPTION("Regulator driver for Linear Technology LTC1376");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c
index b2daa6641417..c9ff26199711 100644
--- a/drivers/regulator/max14577-regulator.c
+++ b/drivers/regulator/max14577-regulator.c
@@ -2,7 +2,7 @@
* max14577.c - Regulator driver for the Maxim 14577/77836
*
* Copyright (C) 2013,2014 Samsung Electronics
- * Krzysztof Kozlowski <k.kozlowski@samsung.com>
+ * Krzysztof Kozlowski <krzk@kernel.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -331,7 +331,7 @@ static void __exit max14577_regulator_exit(void)
}
module_exit(max14577_regulator_exit);
-MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:max14577-regulator");
diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c
index 321e804aeab0..a1b49a6d538f 100644
--- a/drivers/regulator/max77620-regulator.c
+++ b/drivers/regulator/max77620-regulator.c
@@ -123,6 +123,9 @@ static int max77620_regulator_set_fps_src(struct max77620_regulator *pmic,
unsigned int val;
int ret;
+ if (!rinfo)
+ return 0;
+
switch (fps_src) {
case MAX77620_FPS_SRC_0:
case MAX77620_FPS_SRC_1:
@@ -171,6 +174,9 @@ static int max77620_regulator_set_fps_slots(struct max77620_regulator *pmic,
int pd = rpdata->active_fps_pd_slot;
int ret = 0;
+ if (!rinfo)
+ return 0;
+
if (is_suspend) {
pu = rpdata->suspend_fps_pu_slot;
pd = rpdata->suspend_fps_pd_slot;
@@ -680,7 +686,6 @@ static struct max77620_regulator_info max77620_regs_info[MAX77620_NUM_REGS] = {
RAIL_SD(SD1, sd1, "in-sd1", SD1, 600000, 1550000, 12500, 0x22, SD1),
RAIL_SD(SD2, sd2, "in-sd2", SDX, 600000, 3787500, 12500, 0xFF, NONE),
RAIL_SD(SD3, sd3, "in-sd3", SDX, 600000, 3787500, 12500, 0xFF, NONE),
- RAIL_SD(SD4, sd4, "in-sd4", SDX, 600000, 3787500, 12500, 0xFF, NONE),
RAIL_LDO(LDO0, ldo0, "in-ldo0-1", N, 800000, 2375000, 25000),
RAIL_LDO(LDO1, ldo1, "in-ldo0-1", N, 800000, 2375000, 25000),
diff --git a/drivers/regulator/max77693-regulator.c b/drivers/regulator/max77693-regulator.c
index de730fd3f8a5..cfbb9512e486 100644
--- a/drivers/regulator/max77693-regulator.c
+++ b/drivers/regulator/max77693-regulator.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2013-2015 Samsung Electronics
* Jonghwa Lee <jonghwa3.lee@samsung.com>
- * Krzysztof Kozlowski <k.kozlowski.k@gmail.com>
+ * Krzysztof Kozlowski <krzk@kernel.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -314,5 +314,5 @@ module_exit(max77693_pmic_cleanup);
MODULE_DESCRIPTION("MAXIM 77693/77843 regulator driver");
MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
-MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski.k@gmail.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index 08d2f13eca00..e0c747aa9f85 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -271,22 +271,18 @@ static int max8973_set_ramp_delay(struct regulator_dev *rdev,
struct max8973_chip *max = rdev_get_drvdata(rdev);
unsigned int control;
int ret;
- int ret_val;
/* Set ramp delay */
- if (ramp_delay < 25000) {
+ if (ramp_delay <= 12000)
control = MAX8973_RAMP_12mV_PER_US;
- ret_val = 12000;
- } else if (ramp_delay < 50000) {
+ else if (ramp_delay <= 25000)
control = MAX8973_RAMP_25mV_PER_US;
- ret_val = 25000;
- } else if (ramp_delay < 200000) {
+ else if (ramp_delay <= 50000)
control = MAX8973_RAMP_50mV_PER_US;
- ret_val = 50000;
- } else {
+ else if (ramp_delay <= 200000)
control = MAX8973_RAMP_200mV_PER_US;
- ret_val = 200000;
- }
+ else
+ return -EINVAL;
ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1,
MAX8973_RAMP_MASK, control);
@@ -499,7 +495,8 @@ static irqreturn_t max8973_thermal_irq(int irq, void *data)
{
struct max8973_chip *mchip = data;
- thermal_zone_device_update(mchip->tz_device);
+ thermal_zone_device_update(mchip->tz_device,
+ THERMAL_EVENT_UNSPECIFIED);
return IRQ_HANDLED;
}
diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c
new file mode 100644
index 000000000000..b7b9670f0979
--- /dev/null
+++ b/drivers/regulator/mt6323-regulator.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Chen Zhong <chen.zhong@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6323/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6323-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6323_LDO_MODE_NORMAL 0
+#define MT6323_LDO_MODE_LP 1
+
+/*
+ * MT6323 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ * @vselon_reg: Register sections for hardware control mode of bucks
+ * @vselctrl_reg: Register for controlling the buck control mode.
+ * @vselctrl_mask: Mask for query buck's voltage control mode.
+ */
+struct mt6323_regulator_info {
+ struct regulator_desc desc;
+ u32 qi;
+ u32 vselon_reg;
+ u32 vselctrl_reg;
+ u32 vselctrl_mask;
+ u32 modeset_reg;
+ u32 modeset_mask;
+};
+
+#define MT6323_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \
+ vosel, vosel_mask, voselon, vosel_ctrl) \
+[MT6323_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6323_volt_range_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6323_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = (max - min)/step + 1, \
+ .linear_ranges = volt_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(volt_ranges), \
+ .vsel_reg = vosel, \
+ .vsel_mask = vosel_mask, \
+ .enable_reg = enreg, \
+ .enable_mask = BIT(0), \
+ }, \
+ .qi = BIT(13), \
+ .vselon_reg = voselon, \
+ .vselctrl_reg = vosel_ctrl, \
+ .vselctrl_mask = BIT(1), \
+}
+
+#define MT6323_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \
+ vosel_mask, _modeset_reg, _modeset_mask) \
+[MT6323_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6323_volt_table_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6323_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(ldo_volt_table), \
+ .volt_table = ldo_volt_table, \
+ .vsel_reg = vosel, \
+ .vsel_mask = vosel_mask, \
+ .enable_reg = enreg, \
+ .enable_mask = BIT(enbit), \
+ }, \
+ .qi = BIT(15), \
+ .modeset_reg = _modeset_reg, \
+ .modeset_mask = _modeset_mask, \
+}
+
+#define MT6323_REG_FIXED(match, vreg, enreg, enbit, volt, \
+ _modeset_reg, _modeset_mask) \
+[MT6323_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6323_volt_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6323_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = 1, \
+ .enable_reg = enreg, \
+ .enable_mask = BIT(enbit), \
+ .min_uV = volt, \
+ }, \
+ .qi = BIT(15), \
+ .modeset_reg = _modeset_reg, \
+ .modeset_mask = _modeset_mask, \
+}
+
+static const struct regulator_linear_range buck_volt_range1[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range2[] = {
+ REGULATOR_LINEAR_RANGE(1400000, 0, 0x7f, 12500),
+};
+
+static const struct regulator_linear_range buck_volt_range3[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000),
+};
+
+static const u32 ldo_volt_table1[] = {
+ 3300000, 3400000, 3500000, 3600000,
+};
+
+static const u32 ldo_volt_table2[] = {
+ 1500000, 1800000, 2500000, 2800000,
+};
+
+static const u32 ldo_volt_table3[] = {
+ 1800000, 3300000,
+};
+
+static const u32 ldo_volt_table4[] = {
+ 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5[] = {
+ 1200000, 1300000, 1500000, 1800000, 2000000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table6[] = {
+ 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000,
+};
+
+static const u32 ldo_volt_table7[] = {
+ 1200000, 1300000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table8[] = {
+ 1800000, 3000000,
+};
+
+static const u32 ldo_volt_table9[] = {
+ 1200000, 1350000, 1500000, 1800000,
+};
+
+static const u32 ldo_volt_table10[] = {
+ 1200000, 1300000, 1500000, 1800000,
+};
+
+static int mt6323_get_status(struct regulator_dev *rdev)
+{
+ int ret;
+ u32 regval;
+ struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+ ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
+ if (ret != 0) {
+ dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+ return ret;
+ }
+
+ return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static int mt6323_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ int ret, val = 0;
+ struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (!info->modeset_mask) {
+ dev_err(&rdev->dev, "regulator %s doesn't support set_mode\n",
+ info->desc.name);
+ return -EINVAL;
+ }
+
+ switch (mode) {
+ case REGULATOR_MODE_STANDBY:
+ val = MT6323_LDO_MODE_LP;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = MT6323_LDO_MODE_NORMAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val <<= ffs(info->modeset_mask) - 1;
+
+ ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+ info->modeset_mask, val);
+
+ return ret;
+}
+
+static unsigned int mt6323_ldo_get_mode(struct regulator_dev *rdev)
+{
+ unsigned int val;
+ unsigned int mode;
+ int ret;
+ struct mt6323_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (!info->modeset_mask) {
+ dev_err(&rdev->dev, "regulator %s doesn't support get_mode\n",
+ info->desc.name);
+ return -EINVAL;
+ }
+
+ ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+ if (ret < 0)
+ return ret;
+
+ val &= info->modeset_mask;
+ val >>= ffs(info->modeset_mask) - 1;
+
+ if (val & 0x1)
+ mode = REGULATOR_MODE_STANDBY;
+ else
+ mode = REGULATOR_MODE_NORMAL;
+
+ return mode;
+}
+
+static const struct regulator_ops mt6323_volt_range_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_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,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6323_get_status,
+};
+
+static const struct regulator_ops mt6323_volt_table_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+ .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,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6323_get_status,
+ .set_mode = mt6323_ldo_set_mode,
+ .get_mode = mt6323_ldo_get_mode,
+};
+
+static const struct regulator_ops mt6323_volt_fixed_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6323_get_status,
+ .set_mode = mt6323_ldo_set_mode,
+ .get_mode = mt6323_ldo_get_mode,
+};
+
+/* The array is indexed by id(MT6323_ID_XXX) */
+static struct mt6323_regulator_info mt6323_regulators[] = {
+ MT6323_BUCK("buck_vproc", VPROC, 700000, 1493750, 6250,
+ buck_volt_range1, MT6323_VPROC_CON7, MT6323_VPROC_CON9, 0x7f,
+ MT6323_VPROC_CON10, MT6323_VPROC_CON5),
+ MT6323_BUCK("buck_vsys", VSYS, 1400000, 2987500, 12500,
+ buck_volt_range2, MT6323_VSYS_CON7, MT6323_VSYS_CON9, 0x7f,
+ MT6323_VSYS_CON10, MT6323_VSYS_CON5),
+ MT6323_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+ buck_volt_range3, MT6323_VPA_CON7, MT6323_VPA_CON9,
+ 0x3f, MT6323_VPA_CON10, MT6323_VPA_CON5),
+ MT6323_REG_FIXED("ldo_vtcxo", VTCXO, MT6323_ANALDO_CON1, 10, 2800000,
+ MT6323_ANALDO_CON1, 0x2),
+ MT6323_REG_FIXED("ldo_vcn28", VCN28, MT6323_ANALDO_CON19, 12, 2800000,
+ MT6323_ANALDO_CON20, 0x2),
+ MT6323_LDO("ldo_vcn33_bt", VCN33_BT, ldo_volt_table1,
+ MT6323_ANALDO_CON16, 7, MT6323_ANALDO_CON16, 0xC,
+ MT6323_ANALDO_CON21, 0x2),
+ MT6323_LDO("ldo_vcn33_wifi", VCN33_WIFI, ldo_volt_table1,
+ MT6323_ANALDO_CON17, 12, MT6323_ANALDO_CON16, 0xC,
+ MT6323_ANALDO_CON21, 0x2),
+ MT6323_REG_FIXED("ldo_va", VA, MT6323_ANALDO_CON2, 14, 2800000,
+ MT6323_ANALDO_CON2, 0x2),
+ MT6323_LDO("ldo_vcama", VCAMA, ldo_volt_table2,
+ MT6323_ANALDO_CON4, 15, MT6323_ANALDO_CON10, 0x60, -1, 0),
+ MT6323_REG_FIXED("ldo_vio28", VIO28, MT6323_DIGLDO_CON0, 14, 2800000,
+ MT6323_DIGLDO_CON0, 0x2),
+ MT6323_REG_FIXED("ldo_vusb", VUSB, MT6323_DIGLDO_CON2, 14, 3300000,
+ MT6323_DIGLDO_CON2, 0x2),
+ MT6323_LDO("ldo_vmc", VMC, ldo_volt_table3,
+ MT6323_DIGLDO_CON3, 12, MT6323_DIGLDO_CON24, 0x10,
+ MT6323_DIGLDO_CON3, 0x2),
+ MT6323_LDO("ldo_vmch", VMCH, ldo_volt_table4,
+ MT6323_DIGLDO_CON5, 14, MT6323_DIGLDO_CON26, 0x80,
+ MT6323_DIGLDO_CON5, 0x2),
+ MT6323_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table4,
+ MT6323_DIGLDO_CON6, 14, MT6323_DIGLDO_CON27, 0x80,
+ MT6323_DIGLDO_CON6, 0x2),
+ MT6323_LDO("ldo_vgp1", VGP1, ldo_volt_table5,
+ MT6323_DIGLDO_CON7, 15, MT6323_DIGLDO_CON28, 0xE0,
+ MT6323_DIGLDO_CON7, 0x2),
+ MT6323_LDO("ldo_vgp2", VGP2, ldo_volt_table6,
+ MT6323_DIGLDO_CON8, 15, MT6323_DIGLDO_CON29, 0xE0,
+ MT6323_DIGLDO_CON8, 0x2),
+ MT6323_LDO("ldo_vgp3", VGP3, ldo_volt_table7,
+ MT6323_DIGLDO_CON9, 15, MT6323_DIGLDO_CON30, 0x60,
+ MT6323_DIGLDO_CON9, 0x2),
+ MT6323_REG_FIXED("ldo_vcn18", VCN18, MT6323_DIGLDO_CON11, 14, 1800000,
+ MT6323_DIGLDO_CON11, 0x2),
+ MT6323_LDO("ldo_vsim1", VSIM1, ldo_volt_table8,
+ MT6323_DIGLDO_CON13, 15, MT6323_DIGLDO_CON34, 0x20,
+ MT6323_DIGLDO_CON13, 0x2),
+ MT6323_LDO("ldo_vsim2", VSIM2, ldo_volt_table8,
+ MT6323_DIGLDO_CON14, 15, MT6323_DIGLDO_CON35, 0x20,
+ MT6323_DIGLDO_CON14, 0x2),
+ MT6323_REG_FIXED("ldo_vrtc", VRTC, MT6323_DIGLDO_CON15, 8, 2800000,
+ -1, 0),
+ MT6323_LDO("ldo_vcamaf", VCAMAF, ldo_volt_table5,
+ MT6323_DIGLDO_CON31, 15, MT6323_DIGLDO_CON32, 0xE0,
+ MT6323_DIGLDO_CON31, 0x2),
+ MT6323_LDO("ldo_vibr", VIBR, ldo_volt_table5,
+ MT6323_DIGLDO_CON39, 15, MT6323_DIGLDO_CON40, 0xE0,
+ MT6323_DIGLDO_CON39, 0x2),
+ MT6323_REG_FIXED("ldo_vrf18", VRF18, MT6323_DIGLDO_CON45, 15, 1825000,
+ MT6323_DIGLDO_CON45, 0x2),
+ MT6323_LDO("ldo_vm", VM, ldo_volt_table9,
+ MT6323_DIGLDO_CON47, 14, MT6323_DIGLDO_CON48, 0x30,
+ MT6323_DIGLDO_CON47, 0x2),
+ MT6323_REG_FIXED("ldo_vio18", VIO18, MT6323_DIGLDO_CON49, 14, 1800000,
+ MT6323_DIGLDO_CON49, 0x2),
+ MT6323_LDO("ldo_vcamd", VCAMD, ldo_volt_table10,
+ MT6323_DIGLDO_CON51, 14, MT6323_DIGLDO_CON52, 0x60,
+ MT6323_DIGLDO_CON51, 0x2),
+ MT6323_REG_FIXED("ldo_vcamio", VCAMIO, MT6323_DIGLDO_CON53, 14, 1800000,
+ MT6323_DIGLDO_CON53, 0x2),
+};
+
+static int mt6323_set_buck_vosel_reg(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+ int i;
+ u32 regval;
+
+ for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+ if (mt6323_regulators[i].vselctrl_reg) {
+ if (regmap_read(mt6323->regmap,
+ mt6323_regulators[i].vselctrl_reg,
+ &regval) < 0) {
+ dev_err(&pdev->dev,
+ "Failed to read buck ctrl\n");
+ return -EIO;
+ }
+
+ if (regval & mt6323_regulators[i].vselctrl_mask) {
+ mt6323_regulators[i].desc.vsel_reg =
+ mt6323_regulators[i].vselon_reg;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int mt6323_regulator_probe(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6323 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = {};
+ struct regulator_dev *rdev;
+ int i;
+ u32 reg_value;
+
+ /* Query buck controller to select activated voltage register part */
+ if (mt6323_set_buck_vosel_reg(pdev))
+ return -EIO;
+
+ /* Read PMIC chip revision to update constraints and voltage table */
+ if (regmap_read(mt6323->regmap, MT6323_CID, &reg_value) < 0) {
+ dev_err(&pdev->dev, "Failed to read Chip ID\n");
+ return -EIO;
+ }
+ dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
+
+ for (i = 0; i < MT6323_MAX_REGULATOR; i++) {
+ config.dev = &pdev->dev;
+ config.driver_data = &mt6323_regulators[i];
+ config.regmap = mt6323->regmap;
+ rdev = devm_regulator_register(&pdev->dev,
+ &mt6323_regulators[i].desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register %s\n",
+ mt6323_regulators[i].desc.name);
+ return PTR_ERR(rdev);
+ }
+ }
+ return 0;
+}
+
+static const struct platform_device_id mt6323_platform_ids[] = {
+ {"mt6323-regulator", 0},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, mt6323_platform_ids);
+
+static struct platform_driver mt6323_regulator_driver = {
+ .driver = {
+ .name = "mt6323-regulator",
+ },
+ .probe = mt6323_regulator_probe,
+ .id_table = mt6323_platform_ids,
+};
+
+module_platform_driver(mt6323_regulator_driver);
+
+MODULE_AUTHOR("Chen Zhong <chen.zhong@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6323 PMIC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c
index 17a5b6c2d6a9..c6c6aa85e4e8 100644
--- a/drivers/regulator/mt6397-regulator.c
+++ b/drivers/regulator/mt6397-regulator.c
@@ -23,6 +23,9 @@
#include <linux/regulator/mt6397-regulator.h>
#include <linux/regulator/of_regulator.h>
+#define MT6397_BUCK_MODE_AUTO 0
+#define MT6397_BUCK_MODE_FORCE_PWM 1
+
/*
* MT6397 regulators' information
*
@@ -38,10 +41,14 @@ struct mt6397_regulator_info {
u32 vselon_reg;
u32 vselctrl_reg;
u32 vselctrl_mask;
+ u32 modeset_reg;
+ u32 modeset_mask;
+ u32 modeset_shift;
};
#define MT6397_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \
- vosel, vosel_mask, voselon, vosel_ctrl) \
+ vosel, vosel_mask, voselon, vosel_ctrl, _modeset_reg, \
+ _modeset_shift) \
[MT6397_ID_##vreg] = { \
.desc = { \
.name = #vreg, \
@@ -62,6 +69,9 @@ struct mt6397_regulator_info {
.vselon_reg = voselon, \
.vselctrl_reg = vosel_ctrl, \
.vselctrl_mask = BIT(1), \
+ .modeset_reg = _modeset_reg, \
+ .modeset_mask = BIT(_modeset_shift), \
+ .modeset_shift = _modeset_shift \
}
#define MT6397_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \
@@ -145,6 +155,63 @@ static const u32 ldo_volt_table7[] = {
1300000, 1500000, 1800000, 2000000, 2500000, 2800000, 3000000, 3300000,
};
+static int mt6397_regulator_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct mt6397_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret, val;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ val = MT6397_BUCK_MODE_FORCE_PWM;
+ break;
+ case REGULATOR_MODE_NORMAL:
+ val = MT6397_BUCK_MODE_AUTO;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_mode;
+ }
+
+ dev_dbg(&rdev->dev, "mt6397 buck set_mode %#x, %#x, %#x, %#x\n",
+ info->modeset_reg, info->modeset_mask,
+ info->modeset_shift, val);
+
+ val <<= info->modeset_shift;
+ ret = regmap_update_bits(rdev->regmap, info->modeset_reg,
+ info->modeset_mask, val);
+err_mode:
+ if (ret != 0) {
+ dev_err(&rdev->dev,
+ "Failed to set mt6397 buck mode: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static unsigned int mt6397_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct mt6397_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret, regval;
+
+ ret = regmap_read(rdev->regmap, info->modeset_reg, &regval);
+ if (ret != 0) {
+ dev_err(&rdev->dev,
+ "Failed to get mt6397 buck mode: %d\n", ret);
+ return ret;
+ }
+
+ switch ((regval & info->modeset_mask) >> info->modeset_shift) {
+ case MT6397_BUCK_MODE_AUTO:
+ return REGULATOR_MODE_NORMAL;
+ case MT6397_BUCK_MODE_FORCE_PWM:
+ return REGULATOR_MODE_FAST;
+ default:
+ return -EINVAL;
+ }
+}
+
static int mt6397_get_status(struct regulator_dev *rdev)
{
int ret;
@@ -160,7 +227,7 @@ static int mt6397_get_status(struct regulator_dev *rdev)
return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
}
-static struct regulator_ops mt6397_volt_range_ops = {
+static const struct regulator_ops mt6397_volt_range_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
@@ -170,9 +237,11 @@ static struct regulator_ops mt6397_volt_range_ops = {
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.get_status = mt6397_get_status,
+ .set_mode = mt6397_regulator_set_mode,
+ .get_mode = mt6397_regulator_get_mode,
};
-static struct regulator_ops mt6397_volt_table_ops = {
+static const struct regulator_ops mt6397_volt_table_ops = {
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_iterate,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
@@ -184,7 +253,7 @@ static struct regulator_ops mt6397_volt_table_ops = {
.get_status = mt6397_get_status,
};
-static struct regulator_ops mt6397_volt_fixed_ops = {
+static const struct regulator_ops mt6397_volt_fixed_ops = {
.list_voltage = regulator_list_voltage_linear,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -196,28 +265,30 @@ static struct regulator_ops mt6397_volt_fixed_ops = {
static struct mt6397_regulator_info mt6397_regulators[] = {
MT6397_BUCK("buck_vpca15", VPCA15, 700000, 1493750, 6250,
buck_volt_range1, MT6397_VCA15_CON7, MT6397_VCA15_CON9, 0x7f,
- MT6397_VCA15_CON10, MT6397_VCA15_CON5),
+ MT6397_VCA15_CON10, MT6397_VCA15_CON5, MT6397_VCA15_CON2, 11),
MT6397_BUCK("buck_vpca7", VPCA7, 700000, 1493750, 6250,
buck_volt_range1, MT6397_VPCA7_CON7, MT6397_VPCA7_CON9, 0x7f,
- MT6397_VPCA7_CON10, MT6397_VPCA7_CON5),
+ MT6397_VPCA7_CON10, MT6397_VPCA7_CON5, MT6397_VPCA7_CON2, 8),
MT6397_BUCK("buck_vsramca15", VSRAMCA15, 700000, 1493750, 6250,
buck_volt_range1, MT6397_VSRMCA15_CON7, MT6397_VSRMCA15_CON9,
- 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5),
+ 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5,
+ MT6397_VSRMCA15_CON2, 8),
MT6397_BUCK("buck_vsramca7", VSRAMCA7, 700000, 1493750, 6250,
buck_volt_range1, MT6397_VSRMCA7_CON7, MT6397_VSRMCA7_CON9,
- 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5),
+ 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5,
+ MT6397_VSRMCA7_CON2, 8),
MT6397_BUCK("buck_vcore", VCORE, 700000, 1493750, 6250,
buck_volt_range1, MT6397_VCORE_CON7, MT6397_VCORE_CON9, 0x7f,
- MT6397_VCORE_CON10, MT6397_VCORE_CON5),
+ MT6397_VCORE_CON10, MT6397_VCORE_CON5, MT6397_VCORE_CON2, 8),
MT6397_BUCK("buck_vgpu", VGPU, 700000, 1493750, 6250, buck_volt_range1,
MT6397_VGPU_CON7, MT6397_VGPU_CON9, 0x7f,
- MT6397_VGPU_CON10, MT6397_VGPU_CON5),
+ MT6397_VGPU_CON10, MT6397_VGPU_CON5, MT6397_VGPU_CON2, 8),
MT6397_BUCK("buck_vdrm", VDRM, 800000, 1593750, 6250, buck_volt_range2,
MT6397_VDRM_CON7, MT6397_VDRM_CON9, 0x7f,
- MT6397_VDRM_CON10, MT6397_VDRM_CON5),
+ MT6397_VDRM_CON10, MT6397_VDRM_CON5, MT6397_VDRM_CON2, 8),
MT6397_BUCK("buck_vio18", VIO18, 1500000, 2120000, 20000,
buck_volt_range3, MT6397_VIO18_CON7, MT6397_VIO18_CON9, 0x1f,
- MT6397_VIO18_CON10, MT6397_VIO18_CON5),
+ MT6397_VIO18_CON10, MT6397_VIO18_CON5, MT6397_VIO18_CON2, 8),
MT6397_REG_FIXED("ldo_vtcxo", VTCXO, MT6397_ANALDO_CON0, 10, 2800000),
MT6397_REG_FIXED("ldo_va28", VA28, MT6397_ANALDO_CON1, 14, 2800000),
MT6397_LDO("ldo_vcama", VCAMA, ldo_volt_table1,
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index cd828dbf9d52..4f613ec99500 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -163,6 +163,9 @@ static void of_get_regulation_constraints(struct device_node *np,
"regulator-suspend-microvolt", &pval))
suspend_state->uV = pval;
+ if (i == PM_SUSPEND_MEM)
+ constraints->initial_state = PM_SUSPEND_MEM;
+
of_node_put(suspend_np);
suspend_state = NULL;
suspend_np = NULL;
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 2a44e5dd9c2a..cb18b5c4f2db 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -70,6 +70,7 @@ struct pfuze_chip {
struct device *dev;
struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
+ struct pfuze_regulator *pfuze_regulators;
};
static const int pfuze100_swbst[] = {
@@ -334,8 +335,6 @@ static struct pfuze_regulator pfuze3000_regulators[] = {
PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
};
-static struct pfuze_regulator *pfuze_regulators;
-
#ifdef CONFIG_OF
/* PFUZE100 */
static struct of_regulator_match pfuze100_matches[] = {
@@ -563,21 +562,21 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
/* use the right regulators after identify the right device */
switch (pfuze_chip->chip_id) {
case PFUZE3000:
- pfuze_regulators = pfuze3000_regulators;
+ pfuze_chip->pfuze_regulators = pfuze3000_regulators;
regulator_num = ARRAY_SIZE(pfuze3000_regulators);
sw_check_start = PFUZE3000_SW2;
sw_check_end = PFUZE3000_SW2;
sw_hi = 1 << 3;
break;
case PFUZE200:
- pfuze_regulators = pfuze200_regulators;
+ pfuze_chip->pfuze_regulators = pfuze200_regulators;
regulator_num = ARRAY_SIZE(pfuze200_regulators);
sw_check_start = PFUZE200_SW2;
sw_check_end = PFUZE200_SW3B;
break;
case PFUZE100:
default:
- pfuze_regulators = pfuze100_regulators;
+ pfuze_chip->pfuze_regulators = pfuze100_regulators;
regulator_num = ARRAY_SIZE(pfuze100_regulators);
sw_check_start = PFUZE100_SW2;
sw_check_end = PFUZE100_SW4;
@@ -587,7 +586,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
(pfuze_chip->chip_id == PFUZE100) ? "100" :
((pfuze_chip->chip_id == PFUZE200) ? "200" : "3000"));
- memcpy(pfuze_chip->regulator_descs, pfuze_regulators,
+ memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators,
sizeof(pfuze_chip->regulator_descs));
ret = pfuze_parse_regulators_dt(pfuze_chip);
@@ -631,7 +630,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
devm_regulator_register(&client->dev, desc, &config);
if (IS_ERR(pfuze_chip->regulators[i])) {
dev_err(&client->dev, "register regulator%s failed\n",
- pfuze_regulators[i].desc.name);
+ pfuze_chip->pfuze_regulators[i].desc.name);
return PTR_ERR(pfuze_chip->regulators[i]);
}
}
@@ -650,5 +649,5 @@ static struct i2c_driver pfuze_driver = {
module_i2c_driver(pfuze_driver);
MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
-MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC");
+MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000 PMIC");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c
index c448b727f5f8..6c4afc73ecac 100644
--- a/drivers/regulator/pv88060-regulator.c
+++ b/drivers/regulator/pv88060-regulator.c
@@ -14,7 +14,6 @@
*/
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -25,8 +24,6 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/regulator/of_regulator.h>
-#include <linux/proc_fs.h>
-#include <linux/uaccess.h>
#include "pv88060-regulator.h"
#define PV88060_MAX_REGULATORS 14
diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c
index d7107566c429..954a20eeb26f 100644
--- a/drivers/regulator/pv88080-regulator.c
+++ b/drivers/regulator/pv88080-regulator.c
@@ -14,9 +14,9 @@
*/
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/regulator/driver.h>
@@ -25,11 +25,9 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/regulator/of_regulator.h>
-#include <linux/proc_fs.h>
-#include <linux/uaccess.h>
#include "pv88080-regulator.h"
-#define PV88080_MAX_REGULATORS 3
+#define PV88080_MAX_REGULATORS 4
/* PV88080 REGULATOR IDs */
enum {
@@ -37,6 +35,12 @@ enum {
PV88080_ID_BUCK1,
PV88080_ID_BUCK2,
PV88080_ID_BUCK3,
+ PV88080_ID_HVBUCK,
+};
+
+enum pv88080_types {
+ TYPE_PV88080_AA,
+ TYPE_PV88080_BA,
};
struct pv88080_regulator {
@@ -45,7 +49,8 @@ struct pv88080_regulator {
unsigned int n_current_limits;
const int *current_limits;
unsigned int limit_mask;
- unsigned int conf;
+ unsigned int mode_reg;
+ unsigned int limit_reg;
unsigned int conf2;
unsigned int conf5;
};
@@ -54,6 +59,8 @@ struct pv88080 {
struct device *dev;
struct regmap *regmap;
struct regulator_dev *rdev[PV88080_MAX_REGULATORS];
+ unsigned long type;
+ const struct pv88080_compatible_regmap *regmap_config;
};
struct pv88080_buck_voltage {
@@ -62,6 +69,30 @@ struct pv88080_buck_voltage {
int uV_step;
};
+struct pv88080_buck_regmap {
+ /* REGS */
+ int buck_enable_reg;
+ int buck_vsel_reg;
+ int buck_mode_reg;
+ int buck_limit_reg;
+ int buck_vdac_range_reg;
+ int buck_vrange_gain_reg;
+ /* MASKS */
+ int buck_enable_mask;
+ int buck_vsel_mask;
+ int buck_limit_mask;
+};
+
+struct pv88080_compatible_regmap {
+ /* BUCK1, 2, 3 */
+ struct pv88080_buck_regmap buck_regmap[PV88080_MAX_REGULATORS-1];
+ /* HVBUCK */
+ int hvbuck_enable_reg;
+ int hvbuck_vsel_reg;
+ int hvbuck_enable_mask;
+ int hvbuck_vsel_mask;
+};
+
static const struct regmap_config pv88080_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -92,13 +123,111 @@ static const struct pv88080_buck_voltage pv88080_buck_vol[2] = {
},
};
+static const struct pv88080_compatible_regmap pv88080_aa_regs = {
+ /* BUCK1 */
+ .buck_regmap[0] = {
+ .buck_enable_reg = PV88080AA_REG_BUCK1_CONF0,
+ .buck_vsel_reg = PV88080AA_REG_BUCK1_CONF0,
+ .buck_mode_reg = PV88080AA_REG_BUCK1_CONF1,
+ .buck_limit_reg = PV88080AA_REG_BUCK1_CONF1,
+ .buck_vdac_range_reg = PV88080AA_REG_BUCK1_CONF2,
+ .buck_vrange_gain_reg = PV88080AA_REG_BUCK1_CONF5,
+ .buck_enable_mask = PV88080_BUCK1_EN,
+ .buck_vsel_mask = PV88080_VBUCK1_MASK,
+ .buck_limit_mask = PV88080_BUCK1_ILIM_MASK,
+ },
+ /* BUCK2 */
+ .buck_regmap[1] = {
+ .buck_enable_reg = PV88080AA_REG_BUCK2_CONF0,
+ .buck_vsel_reg = PV88080AA_REG_BUCK2_CONF0,
+ .buck_mode_reg = PV88080AA_REG_BUCK2_CONF1,
+ .buck_limit_reg = PV88080AA_REG_BUCK2_CONF1,
+ .buck_vdac_range_reg = PV88080AA_REG_BUCK2_CONF2,
+ .buck_vrange_gain_reg = PV88080AA_REG_BUCK2_CONF5,
+ .buck_enable_mask = PV88080_BUCK2_EN,
+ .buck_vsel_mask = PV88080_VBUCK2_MASK,
+ .buck_limit_mask = PV88080_BUCK2_ILIM_MASK,
+ },
+ /* BUCK3 */
+ .buck_regmap[2] = {
+ .buck_enable_reg = PV88080AA_REG_BUCK3_CONF0,
+ .buck_vsel_reg = PV88080AA_REG_BUCK3_CONF0,
+ .buck_mode_reg = PV88080AA_REG_BUCK3_CONF1,
+ .buck_limit_reg = PV88080AA_REG_BUCK3_CONF1,
+ .buck_vdac_range_reg = PV88080AA_REG_BUCK3_CONF2,
+ .buck_vrange_gain_reg = PV88080AA_REG_BUCK3_CONF5,
+ .buck_enable_mask = PV88080_BUCK3_EN,
+ .buck_vsel_mask = PV88080_VBUCK3_MASK,
+ .buck_limit_mask = PV88080_BUCK3_ILIM_MASK,
+ },
+ /* HVBUCK */
+ .hvbuck_enable_reg = PV88080AA_REG_HVBUCK_CONF2,
+ .hvbuck_vsel_reg = PV88080AA_REG_HVBUCK_CONF1,
+ .hvbuck_enable_mask = PV88080_HVBUCK_EN,
+ .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK,
+};
+
+static const struct pv88080_compatible_regmap pv88080_ba_regs = {
+ /* BUCK1 */
+ .buck_regmap[0] = {
+ .buck_enable_reg = PV88080BA_REG_BUCK1_CONF0,
+ .buck_vsel_reg = PV88080BA_REG_BUCK1_CONF0,
+ .buck_mode_reg = PV88080BA_REG_BUCK1_CONF1,
+ .buck_limit_reg = PV88080BA_REG_BUCK1_CONF1,
+ .buck_vdac_range_reg = PV88080BA_REG_BUCK1_CONF2,
+ .buck_vrange_gain_reg = PV88080BA_REG_BUCK1_CONF5,
+ .buck_enable_mask = PV88080_BUCK1_EN,
+ .buck_vsel_mask = PV88080_VBUCK1_MASK,
+ .buck_limit_mask = PV88080_BUCK1_ILIM_MASK,
+ },
+ /* BUCK2 */
+ .buck_regmap[1] = {
+ .buck_enable_reg = PV88080BA_REG_BUCK2_CONF0,
+ .buck_vsel_reg = PV88080BA_REG_BUCK2_CONF0,
+ .buck_mode_reg = PV88080BA_REG_BUCK2_CONF1,
+ .buck_limit_reg = PV88080BA_REG_BUCK2_CONF1,
+ .buck_vdac_range_reg = PV88080BA_REG_BUCK2_CONF2,
+ .buck_vrange_gain_reg = PV88080BA_REG_BUCK2_CONF5,
+ .buck_enable_mask = PV88080_BUCK2_EN,
+ .buck_vsel_mask = PV88080_VBUCK2_MASK,
+ .buck_limit_mask = PV88080_BUCK2_ILIM_MASK,
+ },
+ /* BUCK3 */
+ .buck_regmap[2] = {
+ .buck_enable_reg = PV88080BA_REG_BUCK3_CONF0,
+ .buck_vsel_reg = PV88080BA_REG_BUCK3_CONF0,
+ .buck_mode_reg = PV88080BA_REG_BUCK3_CONF1,
+ .buck_limit_reg = PV88080BA_REG_BUCK3_CONF1,
+ .buck_vdac_range_reg = PV88080BA_REG_BUCK3_CONF2,
+ .buck_vrange_gain_reg = PV88080BA_REG_BUCK3_CONF5,
+ .buck_enable_mask = PV88080_BUCK3_EN,
+ .buck_vsel_mask = PV88080_VBUCK3_MASK,
+ .buck_limit_mask = PV88080_BUCK3_ILIM_MASK,
+ },
+ /* HVBUCK */
+ .hvbuck_enable_reg = PV88080BA_REG_HVBUCK_CONF2,
+ .hvbuck_vsel_reg = PV88080BA_REG_HVBUCK_CONF1,
+ .hvbuck_enable_mask = PV88080_HVBUCK_EN,
+ .hvbuck_vsel_mask = PV88080_VHVBUCK_MASK,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pv88080_dt_ids[] = {
+ { .compatible = "pvs,pv88080", .data = (void *)TYPE_PV88080_AA },
+ { .compatible = "pvs,pv88080-aa", .data = (void *)TYPE_PV88080_AA },
+ { .compatible = "pvs,pv88080-ba", .data = (void *)TYPE_PV88080_BA },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pv88080_dt_ids);
+#endif
+
static unsigned int pv88080_buck_get_mode(struct regulator_dev *rdev)
{
struct pv88080_regulator *info = rdev_get_drvdata(rdev);
unsigned int data;
int ret, mode = 0;
- ret = regmap_read(rdev->regmap, info->conf, &data);
+ ret = regmap_read(rdev->regmap, info->mode_reg, &data);
if (ret < 0)
return ret;
@@ -139,7 +268,7 @@ static int pv88080_buck_set_mode(struct regulator_dev *rdev,
return -EINVAL;
}
- return regmap_update_bits(rdev->regmap, info->conf,
+ return regmap_update_bits(rdev->regmap, info->mode_reg,
PV88080_BUCK1_MODE_MASK, val);
}
@@ -154,7 +283,7 @@ static int pv88080_set_current_limit(struct regulator_dev *rdev, int min,
if (min <= info->current_limits[i]
&& max >= info->current_limits[i]) {
return regmap_update_bits(rdev->regmap,
- info->conf,
+ info->limit_reg,
info->limit_mask,
i << PV88080_BUCK1_ILIM_SHIFT);
}
@@ -169,7 +298,7 @@ static int pv88080_get_current_limit(struct regulator_dev *rdev)
unsigned int data;
int ret;
- ret = regmap_read(rdev->regmap, info->conf, &data);
+ ret = regmap_read(rdev->regmap, info->limit_reg, &data);
if (ret < 0)
return ret;
@@ -190,6 +319,15 @@ static struct regulator_ops pv88080_buck_ops = {
.get_current_limit = pv88080_get_current_limit,
};
+static struct regulator_ops pv88080_hvbuck_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
#define PV88080_BUCK(chip, regl_name, min, step, max, limits_array) \
{\
.desc = {\
@@ -203,17 +341,25 @@ static struct regulator_ops pv88080_buck_ops = {
.min_uV = min, \
.uV_step = step, \
.n_voltages = ((max) - (min))/(step) + 1, \
- .enable_reg = PV88080_REG_##regl_name##_CONF0, \
- .enable_mask = PV88080_##regl_name##_EN, \
- .vsel_reg = PV88080_REG_##regl_name##_CONF0, \
- .vsel_mask = PV88080_V##regl_name##_MASK, \
},\
.current_limits = limits_array, \
.n_current_limits = ARRAY_SIZE(limits_array), \
- .limit_mask = PV88080_##regl_name##_ILIM_MASK, \
- .conf = PV88080_REG_##regl_name##_CONF1, \
- .conf2 = PV88080_REG_##regl_name##_CONF2, \
- .conf5 = PV88080_REG_##regl_name##_CONF5, \
+}
+
+#define PV88080_HVBUCK(chip, regl_name, min, step, max) \
+{\
+ .desc = {\
+ .id = chip##_ID_##regl_name,\
+ .name = __stringify(chip##_##regl_name),\
+ .of_match = of_match_ptr(#regl_name),\
+ .regulators_node = of_match_ptr("regulators"),\
+ .type = REGULATOR_VOLTAGE,\
+ .owner = THIS_MODULE,\
+ .ops = &pv88080_hvbuck_ops,\
+ .min_uV = min, \
+ .uV_step = step, \
+ .n_voltages = ((max) - (min))/(step) + 1, \
+ },\
}
static struct pv88080_regulator pv88080_regulator_info[] = {
@@ -223,6 +369,7 @@ static struct pv88080_regulator pv88080_regulator_info[] = {
pv88080_buck23_limits),
PV88080_BUCK(PV88080, BUCK3, 600000, 6250, 1393750,
pv88080_buck23_limits),
+ PV88080_HVBUCK(PV88080, HVBUCK, 0, 5000, 1275000),
};
static irqreturn_t pv88080_irq_handler(int irq, void *data)
@@ -283,6 +430,8 @@ static int pv88080_i2c_probe(struct i2c_client *i2c,
{
struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev);
struct pv88080 *chip;
+ const struct pv88080_compatible_regmap *regmap_config;
+ const struct of_device_id *match;
struct regulator_config config = { };
int i, error, ret;
unsigned int conf2, conf5;
@@ -300,6 +449,17 @@ static int pv88080_i2c_probe(struct i2c_client *i2c,
return error;
}
+ if (i2c->dev.of_node) {
+ match = of_match_node(pv88080_dt_ids, i2c->dev.of_node);
+ if (!match) {
+ dev_err(chip->dev, "Failed to get of_match_node\n");
+ return -EINVAL;
+ }
+ chip->type = (unsigned long)match->data;
+ } else {
+ chip->type = id->driver_data;
+ }
+
i2c_set_clientdata(i2c, chip);
if (i2c->irq != 0) {
@@ -339,31 +499,58 @@ static int pv88080_i2c_probe(struct i2c_client *i2c,
"Failed to update mask reg: %d\n", ret);
return ret;
}
-
} else {
dev_warn(chip->dev, "No IRQ configured\n");
}
+ switch (chip->type) {
+ case TYPE_PV88080_AA:
+ chip->regmap_config = &pv88080_aa_regs;
+ break;
+ case TYPE_PV88080_BA:
+ chip->regmap_config = &pv88080_ba_regs;
+ break;
+ }
+
+ regmap_config = chip->regmap_config;
config.dev = chip->dev;
config.regmap = chip->regmap;
- for (i = 0; i < PV88080_MAX_REGULATORS; i++) {
+ /* Registeration for BUCK1, 2, 3 */
+ for (i = 0; i < PV88080_MAX_REGULATORS-1; i++) {
if (init_data)
config.init_data = &init_data[i];
+ pv88080_regulator_info[i].limit_reg
+ = regmap_config->buck_regmap[i].buck_limit_reg;
+ pv88080_regulator_info[i].limit_mask
+ = regmap_config->buck_regmap[i].buck_limit_mask;
+ pv88080_regulator_info[i].mode_reg
+ = regmap_config->buck_regmap[i].buck_mode_reg;
+ pv88080_regulator_info[i].conf2
+ = regmap_config->buck_regmap[i].buck_vdac_range_reg;
+ pv88080_regulator_info[i].conf5
+ = regmap_config->buck_regmap[i].buck_vrange_gain_reg;
+ pv88080_regulator_info[i].desc.enable_reg
+ = regmap_config->buck_regmap[i].buck_enable_reg;
+ pv88080_regulator_info[i].desc.enable_mask
+ = regmap_config->buck_regmap[i].buck_enable_mask;
+ pv88080_regulator_info[i].desc.vsel_reg
+ = regmap_config->buck_regmap[i].buck_vsel_reg;
+ pv88080_regulator_info[i].desc.vsel_mask
+ = regmap_config->buck_regmap[i].buck_vsel_mask;
+
ret = regmap_read(chip->regmap,
- pv88080_regulator_info[i].conf2, &conf2);
+ pv88080_regulator_info[i].conf2, &conf2);
if (ret < 0)
return ret;
-
conf2 = ((conf2 >> PV88080_BUCK_VDAC_RANGE_SHIFT) &
PV88080_BUCK_VDAC_RANGE_MASK);
ret = regmap_read(chip->regmap,
- pv88080_regulator_info[i].conf5, &conf5);
+ pv88080_regulator_info[i].conf5, &conf5);
if (ret < 0)
return ret;
-
conf5 = ((conf5 >> PV88080_BUCK_VRANGE_GAIN_SHIFT) &
PV88080_BUCK_VRANGE_GAIN_MASK);
@@ -386,23 +573,38 @@ static int pv88080_i2c_probe(struct i2c_client *i2c,
}
}
+ pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_reg
+ = regmap_config->hvbuck_enable_reg;
+ pv88080_regulator_info[PV88080_ID_HVBUCK].desc.enable_mask
+ = regmap_config->hvbuck_enable_mask;
+ pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_reg
+ = regmap_config->hvbuck_vsel_reg;
+ pv88080_regulator_info[PV88080_ID_HVBUCK].desc.vsel_mask
+ = regmap_config->hvbuck_vsel_mask;
+
+ /* Registeration for HVBUCK */
+ if (init_data)
+ config.init_data = &init_data[PV88080_ID_HVBUCK];
+
+ config.driver_data = (void *)&pv88080_regulator_info[PV88080_ID_HVBUCK];
+ chip->rdev[PV88080_ID_HVBUCK] = devm_regulator_register(chip->dev,
+ &pv88080_regulator_info[PV88080_ID_HVBUCK].desc, &config);
+ if (IS_ERR(chip->rdev[PV88080_ID_HVBUCK])) {
+ dev_err(chip->dev, "Failed to register PV88080 regulator\n");
+ return PTR_ERR(chip->rdev[PV88080_ID_HVBUCK]);
+ }
+
return 0;
}
static const struct i2c_device_id pv88080_i2c_id[] = {
- {"pv88080", 0},
+ { "pv88080", TYPE_PV88080_AA },
+ { "pv88080-aa", TYPE_PV88080_AA },
+ { "pv88080-ba", TYPE_PV88080_BA },
{},
};
MODULE_DEVICE_TABLE(i2c, pv88080_i2c_id);
-#ifdef CONFIG_OF
-static const struct of_device_id pv88080_dt_ids[] = {
- { .compatible = "pvs,pv88080", .data = &pv88080_i2c_id[0] },
- {},
-};
-MODULE_DEVICE_TABLE(of, pv88080_dt_ids);
-#endif
-
static struct i2c_driver pv88080_regulator_driver = {
.driver = {
.name = "pv88080",
diff --git a/drivers/regulator/pv88080-regulator.h b/drivers/regulator/pv88080-regulator.h
index 5e9afde606f4..ae25ff360e3d 100644
--- a/drivers/regulator/pv88080-regulator.h
+++ b/drivers/regulator/pv88080-regulator.h
@@ -17,55 +17,75 @@
#define __PV88080_REGISTERS_H__
/* System Control and Event Registers */
-#define PV88080_REG_EVENT_A 0x04
-#define PV88080_REG_MASK_A 0x09
-#define PV88080_REG_MASK_B 0x0a
-#define PV88080_REG_MASK_C 0x0b
-
-/* Regulator Registers */
-#define PV88080_REG_BUCK1_CONF0 0x27
-#define PV88080_REG_BUCK1_CONF1 0x28
-#define PV88080_REG_BUCK1_CONF2 0x59
-#define PV88080_REG_BUCK1_CONF5 0x5c
-#define PV88080_REG_BUCK2_CONF0 0x29
-#define PV88080_REG_BUCK2_CONF1 0x2a
-#define PV88080_REG_BUCK2_CONF2 0x61
-#define PV88080_REG_BUCK2_CONF5 0x64
-#define PV88080_REG_BUCK3_CONF0 0x2b
-#define PV88080_REG_BUCK3_CONF1 0x2c
-#define PV88080_REG_BUCK3_CONF2 0x69
-#define PV88080_REG_BUCK3_CONF5 0x6c
+#define PV88080_REG_EVENT_A 0x04
+#define PV88080_REG_MASK_A 0x09
+#define PV88080_REG_MASK_B 0x0A
+#define PV88080_REG_MASK_C 0x0B
+
+/* Regulator Registers - rev. AA */
+#define PV88080AA_REG_HVBUCK_CONF1 0x2D
+#define PV88080AA_REG_HVBUCK_CONF2 0x2E
+#define PV88080AA_REG_BUCK1_CONF0 0x27
+#define PV88080AA_REG_BUCK1_CONF1 0x28
+#define PV88080AA_REG_BUCK1_CONF2 0x59
+#define PV88080AA_REG_BUCK1_CONF5 0x5C
+#define PV88080AA_REG_BUCK2_CONF0 0x29
+#define PV88080AA_REG_BUCK2_CONF1 0x2A
+#define PV88080AA_REG_BUCK2_CONF2 0x61
+#define PV88080AA_REG_BUCK2_CONF5 0x64
+#define PV88080AA_REG_BUCK3_CONF0 0x2B
+#define PV88080AA_REG_BUCK3_CONF1 0x2C
+#define PV88080AA_REG_BUCK3_CONF2 0x69
+#define PV88080AA_REG_BUCK3_CONF5 0x6C
+
+/* Regulator Registers - rev. BA */
+#define PV88080BA_REG_HVBUCK_CONF1 0x33
+#define PV88080BA_REG_HVBUCK_CONF2 0x34
+#define PV88080BA_REG_BUCK1_CONF0 0x2A
+#define PV88080BA_REG_BUCK1_CONF1 0x2C
+#define PV88080BA_REG_BUCK1_CONF2 0x5A
+#define PV88080BA_REG_BUCK1_CONF5 0x5D
+#define PV88080BA_REG_BUCK2_CONF0 0x2D
+#define PV88080BA_REG_BUCK2_CONF1 0x2F
+#define PV88080BA_REG_BUCK2_CONF2 0x63
+#define PV88080BA_REG_BUCK2_CONF5 0x66
+#define PV88080BA_REG_BUCK3_CONF0 0x30
+#define PV88080BA_REG_BUCK3_CONF1 0x32
+#define PV88080BA_REG_BUCK3_CONF2 0x6C
+#define PV88080BA_REG_BUCK3_CONF5 0x6F
/* PV88080_REG_EVENT_A (addr=0x04) */
#define PV88080_E_VDD_FLT 0x01
-#define PV88080_E_OVER_TEMP 0x02
+#define PV88080_E_OVER_TEMP 0x02
/* PV88080_REG_MASK_A (addr=0x09) */
#define PV88080_M_VDD_FLT 0x01
-#define PV88080_M_OVER_TEMP 0x02
+#define PV88080_M_OVER_TEMP 0x02
-/* PV88080_REG_BUCK1_CONF0 (addr=0x27) */
+/* PV88080_REG_BUCK1_CONF0 (addr=0x27|0x2A) */
#define PV88080_BUCK1_EN 0x80
-#define PV88080_VBUCK1_MASK 0x7F
-/* PV88080_REG_BUCK2_CONF0 (addr=0x29) */
+#define PV88080_VBUCK1_MASK 0x7F
+
+/* PV88080_REG_BUCK2_CONF0 (addr=0x29|0x2D) */
#define PV88080_BUCK2_EN 0x80
-#define PV88080_VBUCK2_MASK 0x7F
-/* PV88080_REG_BUCK3_CONF0 (addr=0x2b) */
+#define PV88080_VBUCK2_MASK 0x7F
+
+/* PV88080_REG_BUCK3_CONF0 (addr=0x2B|0x30) */
#define PV88080_BUCK3_EN 0x80
-#define PV88080_VBUCK3_MASK 0x7F
+#define PV88080_VBUCK3_MASK 0x7F
-/* PV88080_REG_BUCK1_CONF1 (addr=0x28) */
-#define PV88080_BUCK1_ILIM_SHIFT 2
+/* PV88080_REG_BUCK1_CONF1 (addr=0x28|0x2C) */
+#define PV88080_BUCK1_ILIM_SHIFT 2
#define PV88080_BUCK1_ILIM_MASK 0x0C
#define PV88080_BUCK1_MODE_MASK 0x03
-/* PV88080_REG_BUCK2_CONF1 (addr=0x2a) */
-#define PV88080_BUCK2_ILIM_SHIFT 2
+/* PV88080_REG_BUCK2_CONF1 (addr=0x2A|0x2F) */
+#define PV88080_BUCK2_ILIM_SHIFT 2
#define PV88080_BUCK2_ILIM_MASK 0x0C
#define PV88080_BUCK2_MODE_MASK 0x03
-/* PV88080_REG_BUCK3_CONF1 (addr=0x2c) */
-#define PV88080_BUCK3_ILIM_SHIFT 2
+/* PV88080_REG_BUCK3_CONF1 (addr=0x2C|0x32) */
+#define PV88080_BUCK3_ILIM_SHIFT 2
#define PV88080_BUCK3_ILIM_MASK 0x0C
#define PV88080_BUCK3_MODE_MASK 0x03
@@ -73,20 +93,26 @@
#define PV88080_BUCK_MODE_AUTO 0x01
#define PV88080_BUCK_MODE_SYNC 0x02
-/* PV88080_REG_BUCK2_CONF2 (addr=0x61) */
-/* PV88080_REG_BUCK3_CONF2 (addr=0x69) */
-#define PV88080_BUCK_VDAC_RANGE_SHIFT 7
-#define PV88080_BUCK_VDAC_RANGE_MASK 0x01
+/* PV88080_REG_HVBUCK_CONF1 (addr=0x2D|0x33) */
+#define PV88080_VHVBUCK_MASK 0xFF
+
+/* PV88080_REG_HVBUCK_CONF1 (addr=0x2E|0x34) */
+#define PV88080_HVBUCK_EN 0x01
+
+/* PV88080_REG_BUCK2_CONF2 (addr=0x61|0x63) */
+/* PV88080_REG_BUCK3_CONF2 (addr=0x69|0x6C) */
+#define PV88080_BUCK_VDAC_RANGE_SHIFT 7
+#define PV88080_BUCK_VDAC_RANGE_MASK 0x01
-#define PV88080_BUCK_VDAC_RANGE_1 0x00
-#define PV88080_BUCK_VDAC_RANGE_2 0x01
+#define PV88080_BUCK_VDAC_RANGE_1 0x00
+#define PV88080_BUCK_VDAC_RANGE_2 0x01
-/* PV88080_REG_BUCK2_CONF5 (addr=0x64) */
-/* PV88080_REG_BUCK3_CONF5 (addr=0x6c) */
-#define PV88080_BUCK_VRANGE_GAIN_SHIFT 0
-#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01
+/* PV88080_REG_BUCK2_CONF5 (addr=0x64|0x66) */
+/* PV88080_REG_BUCK3_CONF5 (addr=0x6C|0x6F) */
+#define PV88080_BUCK_VRANGE_GAIN_SHIFT 0
+#define PV88080_BUCK_VRANGE_GAIN_MASK 0x01
-#define PV88080_BUCK_VRANGE_GAIN_1 0x00
-#define PV88080_BUCK_VRANGE_GAIN_2 0x01
+#define PV88080_BUCK_VRANGE_GAIN_1 0x00
+#define PV88080_BUCK_VRANGE_GAIN_2 0x01
#endif /* __PV88080_REGISTERS_H__ */
diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c
index 0057c6740d6f..421641175352 100644
--- a/drivers/regulator/pv88090-regulator.c
+++ b/drivers/regulator/pv88090-regulator.c
@@ -14,7 +14,6 @@
*/
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -25,8 +24,6 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/regulator/of_regulator.h>
-#include <linux/proc_fs.h>
-#include <linux/uaccess.h>
#include "pv88090-regulator.h"
#define PV88090_MAX_REGULATORS 5
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index fafa3488e960..1b88e0e15a70 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -10,7 +10,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
@@ -20,6 +19,13 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pwm.h>
+#include <linux/gpio/consumer.h>
+
+struct pwm_continuous_reg_data {
+ unsigned int min_uV_dutycycle;
+ unsigned int max_uV_dutycycle;
+ unsigned int dutycycle_unit;
+};
struct pwm_regulator_data {
/* Shared */
@@ -28,6 +34,9 @@ struct pwm_regulator_data {
/* Voltage table */
struct pwm_voltages *duty_cycle_table;
+ /* Continuous mode info */
+ struct pwm_continuous_reg_data continuous;
+
/* regulator descriptor */
struct regulator_desc desc;
@@ -36,8 +45,8 @@ struct pwm_regulator_data {
int state;
- /* Continuous voltage */
- int volt_uV;
+ /* Enable GPIO */
+ struct gpio_desc *enb_gpio;
};
struct pwm_voltages {
@@ -48,10 +57,31 @@ struct pwm_voltages {
/**
* Voltage table call-backs
*/
+static void pwm_regulator_init_state(struct regulator_dev *rdev)
+{
+ struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
+ struct pwm_state pwm_state;
+ unsigned int dutycycle;
+ int i;
+
+ pwm_get_state(drvdata->pwm, &pwm_state);
+ dutycycle = pwm_get_relative_duty_cycle(&pwm_state, 100);
+
+ for (i = 0; i < rdev->desc->n_voltages; i++) {
+ if (dutycycle == drvdata->duty_cycle_table[i].dutycycle) {
+ drvdata->state = i;
+ return;
+ }
+ }
+}
+
static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
+ if (drvdata->state < 0)
+ pwm_regulator_init_state(rdev);
+
return drvdata->state;
}
@@ -59,16 +89,14 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
unsigned selector)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
- struct pwm_args pargs;
- int dutycycle;
+ struct pwm_state pstate;
int ret;
- pwm_get_args(drvdata->pwm, &pargs);
-
- dutycycle = (pargs.period *
- drvdata->duty_cycle_table[selector].dutycycle) / 100;
+ pwm_init_state(drvdata->pwm, &pstate);
+ pwm_set_relative_duty_cycle(&pstate,
+ drvdata->duty_cycle_table[selector].dutycycle, 100);
- ret = pwm_config(drvdata->pwm, dutycycle, pargs.period);
+ ret = pwm_apply_state(drvdata->pwm, &pstate);
if (ret) {
dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
return ret;
@@ -94,6 +122,9 @@ static int pwm_regulator_enable(struct regulator_dev *dev)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+ if (drvdata->enb_gpio)
+ gpiod_set_value_cansleep(drvdata->enb_gpio, 1);
+
return pwm_enable(drvdata->pwm);
}
@@ -103,6 +134,9 @@ static int pwm_regulator_disable(struct regulator_dev *dev)
pwm_disable(drvdata->pwm);
+ if (drvdata->enb_gpio)
+ gpiod_set_value_cansleep(drvdata->enb_gpio, 0);
+
return 0;
}
@@ -110,64 +144,91 @@ static int pwm_regulator_is_enabled(struct regulator_dev *dev)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+ if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio))
+ return false;
+
return pwm_is_enabled(drvdata->pwm);
}
static int pwm_regulator_get_voltage(struct regulator_dev *rdev)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
+ unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;
+ unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;
+ unsigned int duty_unit = drvdata->continuous.dutycycle_unit;
+ int min_uV = rdev->constraints->min_uV;
+ int max_uV = rdev->constraints->max_uV;
+ int diff_uV = max_uV - min_uV;
+ struct pwm_state pstate;
+ unsigned int diff_duty;
+ unsigned int voltage;
+
+ pwm_get_state(drvdata->pwm, &pstate);
- return drvdata->volt_uV;
+ voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit);
+
+ /*
+ * The dutycycle for min_uV might be greater than the one for max_uV.
+ * This is happening when the user needs an inversed polarity, but the
+ * PWM device does not support inversing it in hardware.
+ */
+ if (max_uV_duty < min_uV_duty) {
+ voltage = min_uV_duty - voltage;
+ diff_duty = min_uV_duty - max_uV_duty;
+ } else {
+ voltage = voltage - min_uV_duty;
+ diff_duty = max_uV_duty - min_uV_duty;
+ }
+
+ voltage = DIV_ROUND_CLOSEST_ULL((u64)voltage * diff_uV, diff_duty);
+
+ return voltage + min_uV;
}
static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- unsigned *selector)
+ int req_min_uV, int req_max_uV,
+ unsigned int *selector)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
- unsigned int ramp_delay = rdev->constraints->ramp_delay;
- struct pwm_args pargs;
- unsigned int req_diff = min_uV - rdev->constraints->min_uV;
- unsigned int diff;
- unsigned int duty_pulse;
- u64 req_period;
- u32 rem;
+ unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;
+ unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;
+ unsigned int duty_unit = drvdata->continuous.dutycycle_unit;
+ int min_uV = rdev->constraints->min_uV;
+ int max_uV = rdev->constraints->max_uV;
+ int diff_uV = max_uV - min_uV;
+ struct pwm_state pstate;
+ unsigned int diff_duty;
+ unsigned int dutycycle;
int ret;
- pwm_get_args(drvdata->pwm, &pargs);
- diff = rdev->constraints->max_uV - rdev->constraints->min_uV;
+ pwm_init_state(drvdata->pwm, &pstate);
- /* First try to find out if we get the iduty cycle time which is
- * factor of PWM period time. If (request_diff_to_min * pwm_period)
- * is perfect divided by voltage_range_diff then it is possible to
- * get duty cycle time which is factor of PWM period. This will help
- * to get output voltage nearer to requested value as there is no
- * calculation loss.
+ /*
+ * The dutycycle for min_uV might be greater than the one for max_uV.
+ * This is happening when the user needs an inversed polarity, but the
+ * PWM device does not support inversing it in hardware.
*/
- req_period = req_diff * pargs.period;
- div_u64_rem(req_period, diff, &rem);
- if (!rem) {
- do_div(req_period, diff);
- duty_pulse = (unsigned int)req_period;
- } else {
- duty_pulse = (pargs.period / 100) * ((req_diff * 100) / diff);
- }
+ if (max_uV_duty < min_uV_duty)
+ diff_duty = min_uV_duty - max_uV_duty;
+ else
+ diff_duty = max_uV_duty - min_uV_duty;
- ret = pwm_config(drvdata->pwm, duty_pulse, pargs.period);
- if (ret) {
- dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
- return ret;
- }
+ dutycycle = DIV_ROUND_CLOSEST_ULL((u64)(req_min_uV - min_uV) *
+ diff_duty,
+ diff_uV);
- ret = pwm_enable(drvdata->pwm);
+ if (max_uV_duty < min_uV_duty)
+ dutycycle = min_uV_duty - dutycycle;
+ else
+ dutycycle = min_uV_duty + dutycycle;
+
+ pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit);
+
+ ret = pwm_apply_state(drvdata->pwm, &pstate);
if (ret) {
- dev_err(&rdev->dev, "Failed to enable PWM: %d\n", ret);
+ dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
return ret;
}
- drvdata->volt_uV = min_uV;
-
- /* Delay required by PWM regulator to settle to the new voltage */
- usleep_range(ramp_delay, ramp_delay + 1000);
return 0;
}
@@ -226,6 +287,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
return ret;
}
+ drvdata->state = -EINVAL;
drvdata->duty_cycle_table = duty_cycle_table;
memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops,
sizeof(drvdata->ops));
@@ -238,11 +300,28 @@ static int pwm_regulator_init_table(struct platform_device *pdev,
static int pwm_regulator_init_continuous(struct platform_device *pdev,
struct pwm_regulator_data *drvdata)
{
+ u32 dutycycle_range[2] = { 0, 100 };
+ u32 dutycycle_unit = 100;
+
memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops,
sizeof(drvdata->ops));
drvdata->desc.ops = &drvdata->ops;
drvdata->desc.continuous_voltage_range = true;
+ of_property_read_u32_array(pdev->dev.of_node,
+ "pwm-dutycycle-range",
+ dutycycle_range, 2);
+ of_property_read_u32(pdev->dev.of_node, "pwm-dutycycle-unit",
+ &dutycycle_unit);
+
+ if (dutycycle_range[0] > dutycycle_unit ||
+ dutycycle_range[1] > dutycycle_unit)
+ return -EINVAL;
+
+ drvdata->continuous.dutycycle_unit = dutycycle_unit;
+ drvdata->continuous.min_uV_dutycycle = dutycycle_range[0];
+ drvdata->continuous.max_uV_dutycycle = dutycycle_range[1];
+
return 0;
}
@@ -253,6 +332,7 @@ static int pwm_regulator_probe(struct platform_device *pdev)
struct regulator_dev *regulator;
struct regulator_config config = { };
struct device_node *np = pdev->dev.of_node;
+ enum gpiod_flags gpio_flags;
int ret;
if (!np) {
@@ -290,11 +370,21 @@ static int pwm_regulator_probe(struct platform_device *pdev)
return ret;
}
- /*
- * FIXME: pwm_apply_args() should be removed when switching to the
- * atomic PWM API.
- */
- pwm_apply_args(drvdata->pwm);
+ if (init_data->constraints.boot_on || init_data->constraints.always_on)
+ gpio_flags = GPIOD_OUT_HIGH;
+ else
+ gpio_flags = GPIOD_OUT_LOW;
+ drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
+ gpio_flags);
+ if (IS_ERR(drvdata->enb_gpio)) {
+ ret = PTR_ERR(drvdata->enb_gpio);
+ dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", ret);
+ return ret;
+ }
+
+ ret = pwm_adjust_config(drvdata->pwm);
+ if (ret)
+ return ret;
regulator = devm_regulator_register(&pdev->dev,
&drvdata->desc, &config);
diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c
index e254272585b2..1b2acc43fea1 100644
--- a/drivers/regulator/qcom_rpm-regulator.c
+++ b/drivers/regulator/qcom_rpm-regulator.c
@@ -448,6 +448,44 @@ static struct regulator_ops switch_ops = {
};
/*
+ * PM8018 regulators
+ */
+static const struct qcom_rpm_reg pm8018_pldo = {
+ .desc.linear_ranges = pldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
+ .desc.n_voltages = 161,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_ldo_parts,
+ .supports_force_mode_auto = false,
+ .supports_force_mode_bypass = false,
+};
+
+static const struct qcom_rpm_reg pm8018_nldo = {
+ .desc.linear_ranges = nldo_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
+ .desc.n_voltages = 64,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_ldo_parts,
+ .supports_force_mode_auto = false,
+ .supports_force_mode_bypass = false,
+};
+
+static const struct qcom_rpm_reg pm8018_smps = {
+ .desc.linear_ranges = smps_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
+ .desc.n_voltages = 154,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_smps_parts,
+ .supports_force_mode_auto = false,
+ .supports_force_mode_bypass = false,
+};
+
+static const struct qcom_rpm_reg pm8018_switch = {
+ .desc.ops = &switch_ops,
+ .parts = &rpm8960_switch_parts,
+};
+
+/*
* PM8058 regulators
*/
static const struct qcom_rpm_reg pm8058_pldo = {
@@ -755,6 +793,32 @@ struct rpm_regulator_data {
const char *supply;
};
+static const struct rpm_regulator_data rpm_pm8018_regulators[] = {
+ { "s1", QCOM_RPM_PM8018_SMPS1, &pm8018_smps, "vdd_s1" },
+ { "s2", QCOM_RPM_PM8018_SMPS2, &pm8018_smps, "vdd_s2" },
+ { "s3", QCOM_RPM_PM8018_SMPS3, &pm8018_smps, "vdd_s3" },
+ { "s4", QCOM_RPM_PM8018_SMPS4, &pm8018_smps, "vdd_s4" },
+ { "s5", QCOM_RPM_PM8018_SMPS5, &pm8018_smps, "vdd_s5" },
+
+ { "l2", QCOM_RPM_PM8018_LDO2, &pm8018_pldo, "vdd_l2" },
+ { "l3", QCOM_RPM_PM8018_LDO3, &pm8018_pldo, "vdd_l3" },
+ { "l4", QCOM_RPM_PM8018_LDO4, &pm8018_pldo, "vdd_l4" },
+ { "l5", QCOM_RPM_PM8018_LDO5, &pm8018_pldo, "vdd_l5" },
+ { "l6", QCOM_RPM_PM8018_LDO6, &pm8018_pldo, "vdd_l7" },
+ { "l7", QCOM_RPM_PM8018_LDO7, &pm8018_pldo, "vdd_l7" },
+ { "l8", QCOM_RPM_PM8018_LDO8, &pm8018_nldo, "vdd_l8" },
+ { "l9", QCOM_RPM_PM8018_LDO9, &pm8921_nldo1200,
+ "vdd_l9_l10_l11_l12" },
+ { "l10", QCOM_RPM_PM8018_LDO10, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
+ { "l11", QCOM_RPM_PM8018_LDO11, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
+ { "l12", QCOM_RPM_PM8018_LDO12, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
+ { "l14", QCOM_RPM_PM8018_LDO14, &pm8018_pldo, "vdd_l14" },
+
+ { "lvs1", QCOM_RPM_PM8018_LVS1, &pm8018_switch, "lvs1_in" },
+
+ { }
+};
+
static const struct rpm_regulator_data rpm_pm8058_regulators[] = {
{ "l0", QCOM_RPM_PM8058_LDO0, &pm8058_nldo, "vdd_l0_l1_lvs" },
{ "l1", QCOM_RPM_PM8058_LDO1, &pm8058_nldo, "vdd_l0_l1_lvs" },
@@ -870,6 +934,8 @@ static const struct rpm_regulator_data rpm_pm8921_regulators[] = {
};
static const struct of_device_id rpm_of_match[] = {
+ { .compatible = "qcom,rpm-pm8018-regulators",
+ .data = &rpm_pm8018_regulators },
{ .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators },
{ .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators },
{ .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators },
diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c
index 56a17ec5b5ef..8ed46a9a55c8 100644
--- a/drivers/regulator/qcom_smd-regulator.c
+++ b/drivers/regulator/qcom_smd-regulator.c
@@ -140,6 +140,18 @@ static const struct regulator_ops rpm_smps_ldo_ops = {
.enable = rpm_reg_enable,
.disable = rpm_reg_disable,
.is_enabled = rpm_reg_is_enabled,
+ .list_voltage = regulator_list_voltage_linear_range,
+
+ .get_voltage = rpm_reg_get_voltage,
+ .set_voltage = rpm_reg_set_voltage,
+
+ .set_load = rpm_reg_set_load,
+};
+
+static const struct regulator_ops rpm_smps_ldo_ops_fixed = {
+ .enable = rpm_reg_enable,
+ .disable = rpm_reg_disable,
+ .is_enabled = rpm_reg_is_enabled,
.get_voltage = rpm_reg_get_voltage,
.set_voltage = rpm_reg_set_voltage,
@@ -166,20 +178,21 @@ static const struct regulator_desc pma8084_hfsmps = {
static const struct regulator_desc pma8084_ftsmps = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000),
- REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000),
+ REGULATOR_LINEAR_RANGE(1280000, 185, 261, 10000),
},
.n_linear_ranges = 2,
- .n_voltages = 340,
+ .n_voltages = 262,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pma8084_pldo = {
.linear_ranges = (struct regulator_linear_range[]) {
- REGULATOR_LINEAR_RANGE(750000, 0, 30, 25000),
- REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000),
+ REGULATOR_LINEAR_RANGE( 750000, 0, 63, 12500),
+ REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000),
+ REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000),
},
- .n_linear_ranges = 2,
- .n_voltages = 100,
+ .n_linear_ranges = 3,
+ .n_voltages = 164,
.ops = &rpm_smps_ldo_ops,
};
@@ -199,7 +212,7 @@ static const struct regulator_desc pma8084_switch = {
static const struct regulator_desc pm8x41_hfsmps = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500),
- REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000),
+ REGULATOR_LINEAR_RANGE(1575000, 96, 158, 25000),
},
.n_linear_ranges = 2,
.n_voltages = 159,
@@ -209,29 +222,30 @@ static const struct regulator_desc pm8x41_hfsmps = {
static const struct regulator_desc pm8841_ftsmps = {
.linear_ranges = (struct regulator_linear_range[]) {
REGULATOR_LINEAR_RANGE(350000, 0, 184, 5000),
- REGULATOR_LINEAR_RANGE(700000, 185, 339, 10000),
+ REGULATOR_LINEAR_RANGE(1280000, 185, 261, 10000),
},
.n_linear_ranges = 2,
- .n_voltages = 340,
+ .n_voltages = 262,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pm8941_boost = {
.linear_ranges = (struct regulator_linear_range[]) {
- REGULATOR_LINEAR_RANGE(4000000, 0, 15, 100000),
+ REGULATOR_LINEAR_RANGE(4000000, 0, 30, 50000),
},
.n_linear_ranges = 1,
- .n_voltages = 16,
+ .n_voltages = 31,
.ops = &rpm_smps_ldo_ops,
};
static const struct regulator_desc pm8941_pldo = {
.linear_ranges = (struct regulator_linear_range[]) {
- REGULATOR_LINEAR_RANGE( 750000, 0, 30, 25000),
- REGULATOR_LINEAR_RANGE(1500000, 31, 99, 50000),
+ REGULATOR_LINEAR_RANGE( 750000, 0, 63, 12500),
+ REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000),
+ REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000),
},
- .n_linear_ranges = 2,
- .n_voltages = 100,
+ .n_linear_ranges = 3,
+ .n_voltages = 164,
.ops = &rpm_smps_ldo_ops,
};
@@ -247,7 +261,7 @@ static const struct regulator_desc pm8941_nldo = {
static const struct regulator_desc pm8941_lnldo = {
.fixed_uV = 1740000,
.n_voltages = 1,
- .ops = &rpm_smps_ldo_ops,
+ .ops = &rpm_smps_ldo_ops_fixed,
};
static const struct regulator_desc pm8941_switch = {
diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c
index 84cce21e98cd..16c5f84e06a7 100644
--- a/drivers/regulator/qcom_spmi-regulator.c
+++ b/drivers/regulator/qcom_spmi-regulator.c
@@ -1085,6 +1085,8 @@ static struct regulator_ops spmi_vs_ops = {
.set_pull_down = spmi_regulator_common_set_pull_down,
.set_soft_start = spmi_regulator_common_set_soft_start,
.set_over_current_protection = spmi_regulator_vs_ocp,
+ .set_mode = spmi_regulator_common_set_mode,
+ .get_mode = spmi_regulator_common_get_mode,
};
static struct regulator_ops spmi_boost_ops = {
@@ -1496,6 +1498,7 @@ static const struct spmi_regulator_data pm8941_regulators[] = {
{ "s1", 0x1400, "vdd_s1", },
{ "s2", 0x1700, "vdd_s2", },
{ "s3", 0x1a00, "vdd_s3", },
+ { "s4", 0xa000, },
{ "l1", 0x4000, "vdd_l1_l3", },
{ "l2", 0x4100, "vdd_l2_lvs_1_2_3", },
{ "l3", 0x4200, "vdd_l1_l3", },
@@ -1523,8 +1526,8 @@ static const struct spmi_regulator_data pm8941_regulators[] = {
{ "lvs1", 0x8000, "vdd_l2_lvs_1_2_3", },
{ "lvs2", 0x8100, "vdd_l2_lvs_1_2_3", },
{ "lvs3", 0x8200, "vdd_l2_lvs_1_2_3", },
- { "mvs1", 0x8300, "vin_5vs", },
- { "mvs2", 0x8400, "vin_5vs", },
+ { "5vs1", 0x8300, "vin_5vs", "ocp-5vs1", },
+ { "5vs2", 0x8400, "vin_5vs", "ocp-5vs2", },
{ }
};
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index 40d07ba036e7..3314bf299a51 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -1,11 +1,15 @@
/*
- * Regulator driver for Rockchip RK808
+ * Regulator driver for Rockchip RK808/RK818
*
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
*
* Author: Chris Zhong <zyw@rock-chips.com>
* Author: Zhang Qing <zhangqing@rock-chips.com>
*
+ * Copyright (C) 2016 PHYTEC Messtechnik GmbH
+ *
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
@@ -32,6 +36,12 @@
#define RK808_BUCK4_VSEL_MASK 0xf
#define RK808_LDO_VSEL_MASK 0x1f
+#define RK818_BUCK_VSEL_MASK 0x3f
+#define RK818_BUCK4_VSEL_MASK 0x1f
+#define RK818_LDO_VSEL_MASK 0x1f
+#define RK818_LDO3_ON_VSEL_MASK 0xf
+#define RK818_BOOST_ON_VSEL_MASK 0xe0
+
/* Ramp rate definitions for buck1 / buck2 only */
#define RK808_RAMP_RATE_OFFSET 3
#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET)
@@ -454,6 +464,108 @@ static const struct regulator_desc rk808_reg[] = {
RK808_DCDC_EN_REG, BIT(6)),
};
+static const struct regulator_desc rk818_reg[] = {
+ {
+ .name = "DCDC_REG1",
+ .supply_name = "vcc1",
+ .of_match = of_match_ptr("DCDC_REG1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK818_ID_DCDC1,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .min_uV = 712500,
+ .uV_step = 12500,
+ .n_voltages = 64,
+ .vsel_reg = RK818_BUCK1_ON_VSEL_REG,
+ .vsel_mask = RK818_BUCK_VSEL_MASK,
+ .enable_reg = RK818_DCDC_EN_REG,
+ .enable_mask = BIT(0),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG2",
+ .supply_name = "vcc2",
+ .of_match = of_match_ptr("DCDC_REG2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK818_ID_DCDC2,
+ .ops = &rk808_reg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .min_uV = 712500,
+ .uV_step = 12500,
+ .n_voltages = 64,
+ .vsel_reg = RK818_BUCK2_ON_VSEL_REG,
+ .vsel_mask = RK818_BUCK_VSEL_MASK,
+ .enable_reg = RK818_DCDC_EN_REG,
+ .enable_mask = BIT(1),
+ .owner = THIS_MODULE,
+ }, {
+ .name = "DCDC_REG3",
+ .supply_name = "vcc3",
+ .of_match = of_match_ptr("DCDC_REG3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK818_ID_DCDC3,
+ .ops = &rk808_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 1,
+ .enable_reg = RK818_DCDC_EN_REG,
+ .enable_mask = BIT(2),
+ .owner = THIS_MODULE,
+ },
+ RK8XX_DESC(RK818_ID_DCDC4, "DCDC_REG4", "vcc4", 1800, 3600, 100,
+ RK818_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK,
+ RK818_DCDC_EN_REG, BIT(3), 0),
+ RK8XX_DESC(RK818_ID_BOOST, "DCDC_BOOST", "boost", 4700, 5400, 100,
+ RK818_BOOST_LDO9_ON_VSEL_REG, RK818_BOOST_ON_VSEL_MASK,
+ RK818_DCDC_EN_REG, BIT(4), 0),
+ RK8XX_DESC(RK818_ID_LDO1, "LDO_REG1", "vcc6", 1800, 3400, 100,
+ RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(0), 400),
+ RK8XX_DESC(RK818_ID_LDO2, "LDO_REG2", "vcc6", 1800, 3400, 100,
+ RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(1), 400),
+ {
+ .name = "LDO_REG3",
+ .supply_name = "vcc7",
+ .of_match = of_match_ptr("LDO_REG3"),
+ .regulators_node = of_match_ptr("regulators"),
+ .id = RK818_ID_LDO3,
+ .ops = &rk808_reg_ops_ranges,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 16,
+ .linear_ranges = rk808_ldo3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges),
+ .vsel_reg = RK818_LDO3_ON_VSEL_REG,
+ .vsel_mask = RK818_LDO3_ON_VSEL_MASK,
+ .enable_reg = RK818_LDO_EN_REG,
+ .enable_mask = BIT(2),
+ .enable_time = 400,
+ .owner = THIS_MODULE,
+ },
+ RK8XX_DESC(RK818_ID_LDO4, "LDO_REG4", "vcc8", 1800, 3400, 100,
+ RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(3), 400),
+ RK8XX_DESC(RK818_ID_LDO5, "LDO_REG5", "vcc7", 1800, 3400, 100,
+ RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(4), 400),
+ RK8XX_DESC(RK818_ID_LDO6, "LDO_REG6", "vcc8", 800, 2500, 100,
+ RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(5), 400),
+ RK8XX_DESC(RK818_ID_LDO7, "LDO_REG7", "vcc7", 800, 2500, 100,
+ RK818_LDO7_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(6), 400),
+ RK8XX_DESC(RK818_ID_LDO8, "LDO_REG8", "vcc8", 1800, 3400, 100,
+ RK818_LDO8_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+ BIT(7), 400),
+ RK8XX_DESC(RK818_ID_LDO9, "LDO_REG9", "vcc9", 1800, 3400, 100,
+ RK818_BOOST_LDO9_ON_VSEL_REG, RK818_LDO_VSEL_MASK,
+ RK818_DCDC_EN_REG, BIT(5), 400),
+ RK8XX_DESC_SWITCH(RK818_ID_SWITCH, "SWITCH_REG", "vcc9",
+ RK818_DCDC_EN_REG, BIT(6)),
+ RK8XX_DESC_SWITCH(RK818_ID_HDMI_SWITCH, "HDMI_SWITCH", "h_5v",
+ RK818_H5V_EN_REG, BIT(0)),
+ RK8XX_DESC_SWITCH(RK818_ID_OTG_SWITCH, "OTG_SWITCH", "usb",
+ RK818_DCDC_EN_REG, BIT(7)),
+};
+
static int rk808_regulator_dt_parse_pdata(struct device *dev,
struct device *client_dev,
struct regmap *map,
@@ -499,7 +611,8 @@ static int rk808_regulator_probe(struct platform_device *pdev)
struct regulator_config config = {};
struct regulator_dev *rk808_rdev;
struct rk808_regulator_data *pdata;
- int ret, i;
+ const struct regulator_desc *regulators;
+ int ret, i, nregulators;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -512,14 +625,29 @@ static int rk808_regulator_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pdata);
+ switch (rk808->variant) {
+ case RK808_ID:
+ regulators = rk808_reg;
+ nregulators = RK808_NUM_REGULATORS;
+ break;
+ case RK818_ID:
+ regulators = rk818_reg;
+ nregulators = RK818_NUM_REGULATORS;
+ break;
+ default:
+ dev_err(&client->dev, "unsupported RK8XX ID %lu\n",
+ rk808->variant);
+ return -EINVAL;
+ }
+
config.dev = &client->dev;
config.driver_data = pdata;
config.regmap = rk808->regmap;
/* Instantiate the regulators */
- for (i = 0; i < RK808_NUM_REGULATORS; i++) {
+ for (i = 0; i < nregulators; i++) {
rk808_rdev = devm_regulator_register(&pdev->dev,
- &rk808_reg[i], &config);
+ &regulators[i], &config);
if (IS_ERR(rk808_rdev)) {
dev_err(&client->dev,
"failed to register %d regulator\n", i);
@@ -533,15 +661,15 @@ static int rk808_regulator_probe(struct platform_device *pdev)
static struct platform_driver rk808_regulator_driver = {
.probe = rk808_regulator_probe,
.driver = {
- .name = "rk808-regulator",
- .owner = THIS_MODULE,
+ .name = "rk808-regulator"
},
};
module_platform_driver(rk808_regulator_driver);
-MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs");
-MODULE_AUTHOR("Chris Zhong<zyw@rock-chips.com>");
-MODULE_AUTHOR("Zhang Qing<zhangqing@rock-chips.com>");
+MODULE_DESCRIPTION("regulator driver for the RK808/RK818 series PMICs");
+MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
+MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
+MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:rk808-regulator");
diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c
index b85ceb8ff911..9c930eb68cda 100644
--- a/drivers/regulator/rn5t618-regulator.c
+++ b/drivers/regulator/rn5t618-regulator.c
@@ -46,6 +46,23 @@ static struct regulator_ops rn5t618_reg_ops = {
.vsel_mask = (vmask), \
}
+static struct regulator_desc rn5t567_regulators[] = {
+ /* DCDC */
+ REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500),
+ REG(DCDC2, DC2CTL, BIT(0), DC2DAC, 0xff, 600000, 3500000, 12500),
+ REG(DCDC3, DC3CTL, BIT(0), DC3DAC, 0xff, 600000, 3500000, 12500),
+ REG(DCDC4, DC4CTL, BIT(0), DC4DAC, 0xff, 600000, 3500000, 12500),
+ /* LDO */
+ REG(LDO1, LDOEN1, BIT(0), LDO1DAC, 0x7f, 900000, 3500000, 25000),
+ REG(LDO2, LDOEN1, BIT(1), LDO2DAC, 0x7f, 900000, 3500000, 25000),
+ REG(LDO3, LDOEN1, BIT(2), LDO3DAC, 0x7f, 600000, 3500000, 25000),
+ REG(LDO4, LDOEN1, BIT(3), LDO4DAC, 0x7f, 900000, 3500000, 25000),
+ REG(LDO5, LDOEN1, BIT(4), LDO5DAC, 0x7f, 900000, 3500000, 25000),
+ /* LDO RTC */
+ REG(LDORTC1, LDOEN2, BIT(4), LDORTCDAC, 0x7f, 1200000, 3500000, 25000),
+ REG(LDORTC2, LDOEN2, BIT(5), LDORTC2DAC, 0x7f, 900000, 3500000, 25000),
+};
+
static struct regulator_desc rn5t618_regulators[] = {
/* DCDC */
REG(DCDC1, DC1CTL, BIT(0), DC1DAC, 0xff, 600000, 3500000, 12500),
@@ -67,18 +84,33 @@ static int rn5t618_regulator_probe(struct platform_device *pdev)
struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
struct regulator_config config = { };
struct regulator_dev *rdev;
+ struct regulator_desc *regulators;
int i;
+ switch (rn5t618->variant) {
+ case RN5T567:
+ regulators = rn5t567_regulators;
+ break;
+ case RN5T618:
+ regulators = rn5t618_regulators;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ config.dev = pdev->dev.parent;
+ config.regmap = rn5t618->regmap;
+
for (i = 0; i < RN5T618_REG_NUM; i++) {
- config.dev = pdev->dev.parent;
- config.regmap = rn5t618->regmap;
+ if (!regulators[i].name)
+ continue;
rdev = devm_regulator_register(&pdev->dev,
- &rn5t618_regulators[i],
+ &regulators[i],
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s regulator\n",
- rn5t618_regulators[i].name);
+ regulators[i].name);
return PTR_ERR(rdev);
}
}
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index 02fb6b4ea820..d838e77dd947 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -750,7 +750,7 @@ static const struct regulator_linear_range s2mps15_ldo_voltage_ranges3[] = {
/* voltage range for s2mps15 LDO 7, 8, 9 and 10 */
static const struct regulator_linear_range s2mps15_ldo_voltage_ranges4[] = {
- REGULATOR_LINEAR_RANGE(700000, 0xc, 0x18, 25000),
+ REGULATOR_LINEAR_RANGE(700000, 0x10, 0x20, 25000),
};
/* voltage range for s2mps15 LDO 1 */
@@ -760,12 +760,12 @@ static const struct regulator_linear_range s2mps15_ldo_voltage_ranges5[] = {
/* voltage range for s2mps15 BUCK 1, 2, 3, 4, 5, 6 and 7 */
static const struct regulator_linear_range s2mps15_buck_voltage_ranges1[] = {
- REGULATOR_LINEAR_RANGE(500000, 0x20, 0xb0, 6250),
+ REGULATOR_LINEAR_RANGE(500000, 0x20, 0xc0, 6250),
};
/* voltage range for s2mps15 BUCK 8, 9 and 10 */
static const struct regulator_linear_range s2mps15_buck_voltage_ranges2[] = {
- REGULATOR_LINEAR_RANGE(1000000, 0x20, 0xc0, 12500),
+ REGULATOR_LINEAR_RANGE(1000000, 0x20, 0x78, 12500),
};
static const struct regulator_desc s2mps15_regulators[] = {
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c
index 572816e30095..c139890c1514 100644
--- a/drivers/regulator/tps51632-regulator.c
+++ b/drivers/regulator/tps51632-regulator.c
@@ -94,11 +94,14 @@ static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev,
int ramp_delay)
{
struct tps51632_chip *tps = rdev_get_drvdata(rdev);
- int bit = ramp_delay/6000;
+ int bit;
int ret;
- if (bit)
- bit--;
+ if (ramp_delay == 0)
+ bit = 0;
+ else
+ bit = DIV_ROUND_UP(ramp_delay, 6000) - 1;
+
ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, BIT(bit));
if (ret < 0)
dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret);
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index adbe4fc5cf07..2d12b9af3540 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -28,7 +28,7 @@
#include <linux/mfd/tps65217.h>
#define TPS65217_REGULATOR(_name, _id, _of_match, _ops, _n, _vr, _vm, _em, \
- _t, _lr, _nlr) \
+ _t, _lr, _nlr, _sr, _sm) \
{ \
.name = _name, \
.id = _id, \
@@ -45,6 +45,8 @@
.volt_table = _t, \
.linear_ranges = _lr, \
.n_linear_ranges = _nlr, \
+ .bypass_reg = _sr, \
+ .bypass_mask = _sm, \
} \
static const unsigned int LDO1_VSEL_table[] = {
@@ -118,6 +120,35 @@ static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev,
return ret;
}
+static int tps65217_pmic_set_suspend_enable(struct regulator_dev *dev)
+{
+ struct tps65217 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
+ return -EINVAL;
+
+ return tps65217_clear_bits(tps, dev->desc->bypass_reg,
+ dev->desc->bypass_mask,
+ TPS65217_PROTECT_L1);
+}
+
+static int tps65217_pmic_set_suspend_disable(struct regulator_dev *dev)
+{
+ struct tps65217 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
+ return -EINVAL;
+
+ if (!tps->strobes[rid])
+ return -EINVAL;
+
+ return tps65217_set_bits(tps, dev->desc->bypass_reg,
+ dev->desc->bypass_mask,
+ tps->strobes[rid], TPS65217_PROTECT_L1);
+}
+
/* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */
static struct regulator_ops tps65217_pmic_ops = {
.is_enabled = regulator_is_enabled_regmap,
@@ -127,6 +158,8 @@ static struct regulator_ops tps65217_pmic_ops = {
.set_voltage_sel = tps65217_pmic_set_voltage_sel,
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
+ .set_suspend_enable = tps65217_pmic_set_suspend_enable,
+ .set_suspend_disable = tps65217_pmic_set_suspend_disable,
};
/* Operations permitted on LDO1 */
@@ -138,41 +171,50 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = {
.set_voltage_sel = tps65217_pmic_set_voltage_sel,
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
+ .set_suspend_enable = tps65217_pmic_set_suspend_enable,
+ .set_suspend_disable = tps65217_pmic_set_suspend_disable,
};
static const struct regulator_desc regulators[] = {
TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, "dcdc1",
tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC1,
TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC1_EN,
- NULL, tps65217_uv1_ranges, 2),
+ NULL, tps65217_uv1_ranges, 2, TPS65217_REG_SEQ1,
+ TPS65217_SEQ1_DC1_SEQ_MASK),
TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, "dcdc2",
tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC2,
TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC2_EN,
NULL, tps65217_uv1_ranges,
- ARRAY_SIZE(tps65217_uv1_ranges)),
+ ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ1,
+ TPS65217_SEQ1_DC2_SEQ_MASK),
TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, "dcdc3",
tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC3,
TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC3_EN,
- NULL, tps65217_uv1_ranges, 1),
+ NULL, tps65217_uv1_ranges, 1, TPS65217_REG_SEQ2,
+ TPS65217_SEQ2_DC3_SEQ_MASK),
TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, "ldo1",
tps65217_pmic_ldo1_ops, 16, TPS65217_REG_DEFLDO1,
TPS65217_DEFLDO1_LDO1_MASK, TPS65217_ENABLE_LDO1_EN,
- LDO1_VSEL_table, NULL, 0),
+ LDO1_VSEL_table, NULL, 0, TPS65217_REG_SEQ2,
+ TPS65217_SEQ2_LDO1_SEQ_MASK),
TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, "ldo2", tps65217_pmic_ops,
64, TPS65217_REG_DEFLDO2,
TPS65217_DEFLDO2_LDO2_MASK, TPS65217_ENABLE_LDO2_EN,
NULL, tps65217_uv1_ranges,
- ARRAY_SIZE(tps65217_uv1_ranges)),
+ ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ3,
+ TPS65217_SEQ3_LDO2_SEQ_MASK),
TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, "ldo3", tps65217_pmic_ops,
32, TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK,
TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
NULL, tps65217_uv2_ranges,
- ARRAY_SIZE(tps65217_uv2_ranges)),
+ ARRAY_SIZE(tps65217_uv2_ranges), TPS65217_REG_SEQ3,
+ TPS65217_SEQ3_LDO3_SEQ_MASK),
TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, "ldo4", tps65217_pmic_ops,
32, TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK,
TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
NULL, tps65217_uv2_ranges,
- ARRAY_SIZE(tps65217_uv2_ranges)),
+ ARRAY_SIZE(tps65217_uv2_ranges), TPS65217_REG_SEQ4,
+ TPS65217_SEQ4_LDO4_SEQ_MASK),
};
static int tps65217_regulator_probe(struct platform_device *pdev)
@@ -181,13 +223,18 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
struct tps65217_board *pdata = dev_get_platdata(tps->dev);
struct regulator_dev *rdev;
struct regulator_config config = { };
- int i;
+ int i, ret;
+ unsigned int val;
if (tps65217_chip_id(tps) != TPS65217) {
dev_err(&pdev->dev, "Invalid tps chip version\n");
return -ENODEV;
}
+ /* Allocate memory for strobes */
+ tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) *
+ TPS65217_NUM_REGULATOR, GFP_KERNEL);
+
platform_set_drvdata(pdev, tps);
for (i = 0; i < TPS65217_NUM_REGULATOR; i++) {
@@ -205,6 +252,10 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
pdev->name);
return PTR_ERR(rdev);
}
+
+ /* Store default strobe info */
+ ret = tps65217_reg_read(tps, regulators[i].bypass_reg, &val);
+ tps->strobes[i] = val & regulators[i].bypass_mask;
}
return 0;
diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c
index a5e5634eeb9e..eb0f5b13841a 100644
--- a/drivers/regulator/tps65218-regulator.c
+++ b/drivers/regulator/tps65218-regulator.c
@@ -31,7 +31,7 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
DCDC5, DCDC6, LDO1, LS3 };
#define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \
- _cr, _cm, _lr, _nlr, _delay, _fuv) \
+ _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \
{ \
.name = _name, \
.id = _id, \
@@ -49,7 +49,9 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
.linear_ranges = _lr, \
.n_linear_ranges = _nlr, \
.ramp_delay = _delay, \
- .fixed_uV = _fuv \
+ .fixed_uV = _fuv, \
+ .bypass_reg = _sr, \
+ .bypass_mask = _sm, \
} \
#define TPS65218_INFO(_id, _nm, _min, _max) \
@@ -157,6 +159,48 @@ static int tps65218_pmic_disable(struct regulator_dev *dev)
dev->desc->enable_mask, TPS65218_PROTECT_L1);
}
+static int tps65218_pmic_set_suspend_enable(struct regulator_dev *dev)
+{
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1)
+ return -EINVAL;
+
+ return tps65218_clear_bits(tps, dev->desc->bypass_reg,
+ dev->desc->bypass_mask,
+ TPS65218_PROTECT_L1);
+}
+
+static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev)
+{
+ struct tps65218 *tps = rdev_get_drvdata(dev);
+ unsigned int rid = rdev_get_id(dev);
+
+ if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1)
+ return -EINVAL;
+
+ /*
+ * Certain revisions of TPS65218 will need to have DCDC3 regulator
+ * enabled always, otherwise an immediate system reboot will occur
+ * during poweroff.
+ */
+ if (rid == TPS65218_DCDC_3 && tps->rev == TPS65218_REV_2_1)
+ return 0;
+
+ if (!tps->info[rid]->strobe) {
+ if (rid == TPS65218_DCDC_3)
+ tps->info[rid]->strobe = 3;
+ else
+ return -EINVAL;
+ }
+
+ return tps65218_set_bits(tps, dev->desc->bypass_reg,
+ dev->desc->bypass_mask,
+ tps->info[rid]->strobe,
+ TPS65218_PROTECT_L1);
+}
+
/* Operations permitted on DCDC1, DCDC2 */
static struct regulator_ops tps65218_dcdc12_ops = {
.is_enabled = regulator_is_enabled_regmap,
@@ -167,6 +211,8 @@ static struct regulator_ops tps65218_dcdc12_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_suspend_enable = tps65218_pmic_set_suspend_enable,
+ .set_suspend_disable = tps65218_pmic_set_suspend_disable,
};
/* Operations permitted on DCDC3, DCDC4 and LDO1 */
@@ -178,6 +224,8 @@ static struct regulator_ops tps65218_ldo1_dcdc34_ops = {
.set_voltage_sel = tps65218_pmic_set_voltage_sel,
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
+ .set_suspend_enable = tps65218_pmic_set_suspend_enable,
+ .set_suspend_disable = tps65218_pmic_set_suspend_disable,
};
static const int ls3_currents[] = { 100, 200, 500, 1000 };
@@ -247,6 +295,8 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = tps65218_pmic_enable,
.disable = tps65218_pmic_disable,
+ .set_suspend_enable = tps65218_pmic_set_suspend_enable,
+ .set_suspend_disable = tps65218_pmic_set_suspend_disable,
};
static const struct regulator_desc regulators[] = {
@@ -254,42 +304,47 @@ static const struct regulator_desc regulators[] = {
tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1,
TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges,
- 2, 4000, 0),
+ 2, 4000, 0, TPS65218_REG_SEQ3,
+ TPS65218_SEQ3_DC1_SEQ_MASK),
TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE,
tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2,
TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges,
- 2, 4000, 0),
+ 2, 4000, 0, TPS65218_REG_SEQ3,
+ TPS65218_SEQ3_DC2_SEQ_MASK),
TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE,
tps65218_ldo1_dcdc34_ops, 64,
TPS65218_REG_CONTROL_DCDC3,
TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2,
- 0, 0),
+ 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC3_SEQ_MASK),
TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE,
tps65218_ldo1_dcdc34_ops, 53,
TPS65218_REG_CONTROL_DCDC4,
TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1,
TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2,
- 0, 0),
+ 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC4_SEQ_MASK),
TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE,
tps65218_dcdc56_pmic_ops, 1, -1, -1,
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0,
- NULL, 0, 0, 1000000),
+ NULL, 0, 0, 1000000, TPS65218_REG_SEQ5,
+ TPS65218_SEQ5_DC5_SEQ_MASK),
TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE,
tps65218_dcdc56_pmic_ops, 1, -1, -1,
TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0,
- NULL, 0, 0, 1800000),
+ NULL, 0, 0, 1800000, TPS65218_REG_SEQ5,
+ TPS65218_SEQ5_DC6_SEQ_MASK),
TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE,
tps65218_ldo1_dcdc34_ops, 64,
TPS65218_REG_CONTROL_LDO1,
TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2,
TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges,
- 2, 0, 0),
+ 2, 0, 0, TPS65218_REG_SEQ6,
+ TPS65218_SEQ6_LDO1_SEQ_MASK),
TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT,
tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2,
TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2,
- TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0),
+ TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0, 0, 0),
};
static int tps65218_regulator_probe(struct platform_device *pdev)
@@ -300,7 +355,8 @@ static int tps65218_regulator_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
const struct of_device_id *match;
struct regulator_config config = { };
- int id;
+ int id, ret;
+ unsigned int val;
match = of_match_device(tps65218_of_match, &pdev->dev);
if (!match)
@@ -327,6 +383,12 @@ static int tps65218_regulator_probe(struct platform_device *pdev)
return PTR_ERR(rdev);
}
+ ret = tps65218_reg_read(tps, regulators[id].bypass_reg, &val);
+ if (ret)
+ return ret;
+
+ tps->info[id]->strobe = val & regulators[id].bypass_mask;
+
return 0;
}
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index fb991ec76423..696116ebdf50 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -1111,6 +1111,12 @@ static int tps65910_probe(struct platform_device *pdev)
pmic->num_regulators = ARRAY_SIZE(tps65910_regs);
pmic->ext_sleep_control = tps65910_ext_sleep_control;
info = tps65910_regs;
+ /* Work around silicon erratum SWCZ010: output programmed
+ * voltage level can go higher than expected or crash
+ * Workaround: use no synchronization of DCDC clocks
+ */
+ tps65910_reg_clear_bits(pmic->mfd, TPS65910_DCDCCTRL,
+ DCDCCTRL_DCDCCKSYNC_MASK);
break;
case TPS65911:
pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index faeb5ee92c9e..210681d6b743 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -905,7 +905,7 @@ static struct regulator_ops twlsmps_ops = {
twl4030reg_map_mode)
#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \
TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \
- 0x0, TWL6030, twl6030fixed_ops, 0x0)
+ 0x0, TWL6030, twl6030fixed_ops, NULL)
#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
static const struct twlreg_info TWL4030_INFO_##label = { \