diff options
author | Mark Brown <broonie@kernel.org> | 2016-11-04 12:16:38 -0600 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-11-04 12:16:38 -0600 |
commit | cc9b94029e9ef51787af908e9856b1eed314bc00 (patch) | |
tree | 9675310b89d0f6fb1f7bd9423f0638c4ee5226fd /drivers/regulator | |
parent | 13bed58ce8748d430a26e353a09b89f9d613a71f (diff) | |
parent | 1b5b42216469b05ef4b5916cb40b127dfab1da88 (diff) | |
download | linux-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')
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, ®); + + 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 = <c3676->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 = <c3676_ ## _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, <c3676_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 = <c3676->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, ®val); + 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, + ®val) < 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, ®_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, ®val); + 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); + ®ulators[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], + ®ulators[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 = { \ |