On 5/12/2015 2:39 PM, Stephen Boyd wrote: > Add an SPMI regulator driver for Qualcomm's PM8941 and PM8916 > PMICs. This driver is based largely on code from > codeaurora.org[1]. > > [1] https://www.codeaurora.org/cgit/quic/la/kernel/msm-3.10/tree/drivers/regulator/qpnp-regulator.c?h=msm-3.10 > Cc: David Collins <collinsd@xxxxxxxxxxxxxx> > Cc: <devicetree@xxxxxxxxxxxxxxx> > Signed-off-by: Stephen Boyd <sboyd@xxxxxxxxxxxxxx> > --- > .../bindings/regulator/qcom,spmi-regulator.txt | 225 +++ > drivers/regulator/Kconfig | 11 + > drivers/regulator/Makefile | 1 + > drivers/regulator/qcom_spmi-regulator.c | 1750 ++++++++++++++++++++ > 4 files changed, 1987 insertions(+) > create mode 100644 Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt > create mode 100644 drivers/regulator/qcom_spmi-regulator.c > > diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt > new file mode 100644 > index 000000000000..b89744da62d0 > --- /dev/null > +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt > @@ -0,0 +1,225 @@ > +Qualcomm SPMI Regulators > + > +- compatible: > + Usage: required > + Value type: <string> > + Definition: must be one of: > + "qcom,pm8841-regulators" > + "qcom,pm8916-regulators" > + "qcom,pm8941-regulators" > + > +- interrupts: > + Usage: optional > + Value type: <prop-encoded-array> > + Definition: List of OCP interrupts. > + > +- interrupt-names: > + Usage: required if 'interrupts' property present > + Value type: <string-array> > + Definition: List of strings defining the names of the > + interrupts in the 'interrupts' property 1-to-1. > + Supported values are "ocp-<regulator_name>", where > + <regulator_name> corresponds to a voltage switch > + type regulator. > + > +- vdd_s1-supply: > +- vdd_s2-supply: > +- vdd_s3-supply: > +- vdd_s4-supply: > +- vdd_s5-supply: > +- vdd_s6-supply: > +- vdd_s7-supply: > +- vdd_s8-supply: > + Usage: optional (pm8841 only) > + Value type: <phandle> > + Definition: Reference to regulator supplying the input pin, as > + described in the data sheet. > + > +- vdd_s1-supply: > +- vdd_s2-supply: > +- vdd_s3-supply: > +- vdd_s4-supply: > +- vdd_l1_l3-supply: > +- vdd_l2-supply: > +- vdd_l4_l5_l6-supply: > +- vdd_l7-supply: > +- vdd_l8_l11_l14_l15_l16-supply: > +- vdd_l9_l10_l12_l13_l17_l18-supply: > + Usage: optional (pm8916 only) > + Value type: <phandle> > + Definition: Reference to regulator supplying the input pin, as > + described in the data sheet. > + > +- vdd_s1-supply: > +- vdd_s2-supply: > +- vdd_s3-supply: > +- vdd_l1_l3-supply: > +- vdd_l2_lvs_1_2_3-supply: > +- vdd_l4_l11-supply: > +- vdd_l5_l7-supply: > +- vdd_l6_l12_l14_l15-supply: > +- vdd_l8_l16_l18_19-supply: > +- vdd_l9_l10_l17_l22-supply: > +- vdd_l13_l20_l23_l24-supply: > +- vdd_l21-supply: > +- vin_5vs-supply: > + Usage: optional (pm8941 only) > + Value type: <phandle> > + Definition: Reference to regulator supplying the input pin, as > + described in the data sheet. > + > + > +The regulator node houses sub-nodes for each regulator within the device. Each > +sub-node is identified using the node's name, with valid values listed for each > +of the PMICs below. > + > +pm8841: > + s1, s2, s3, s4, s5, s6, s7, s8 > + > +pm8916: > + s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, > + l14, l15, l16, l17, l18 > + > +pm8941: > + s1, s2, s3, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, > + l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3, > + mvs1, mvs2 > + > +The content of each sub-node is defined by the standard binding for regulators - > +see regulator.txt - with additional custom properties described below: > + > +- qcom,system-load: > + Usage: optional > + Value type: <u32> > + Description: Load in uA present on regulator that is not captured by > + any consumer request. > + > +- qcom,auto-mode-enable: > + Usage: optional > + Value type: <u32> > + Description: 1 = Enable automatic hardware selection of regulator > + mode (HPM vs LPM); not available on boost type > + regulators. 0 = Disable auto mode selection. > + > +- qcom,bypass-mode-enable: > + Usage: optional > + Value type: <u32> > + Description: 1 = Enable bypass mode for an LDO type regulator so that > + it acts like a switch and simply outputs its input > + voltage. 0 = Do not enable bypass mode. > + > +- qcom,ocp-enable: > + Usage: optional > + Value type: <u32> > + Description: 1 = Allow over current protection (OCP) to be enabled for > + voltage switch type regulators so that they latch off > + automatically when over current is detected. OCP is > + enabled when in HPM or auto mode. 0 = Disable OCP. > + > +- qcom,ocp-max-retries: > + Usage: optional > + Value type: <u32> > + Description: Maximum number of times to try toggling a voltage switch > + off and back on as a result of consecutive over current > + events. > + > +- qcom,ocp-retry-delay: > + Usage: optional > + Value type: <u32> > + Description: Time to delay in milliseconds between each voltage switch > + toggle after an over current event takes place. > + > +- qcom,pull-down-enable: > + Usage: optional > + Value type: <u32> > + Description: 1 = Enable output pull down resistor when the regulator > + is disabled. 0 = Disable pull down resistor > + > +- qcom,soft-start-enable: > + Usage: optional > + Value type: <u32> > + Description: 1 = Enable soft start for LDO and voltage switch type > + regulators so that output voltage slowly ramps up when the > + regulator is enabled. 0 = Disable soft start > + > +- qcom,boost-current-limit: > + Usage: optional > + Value type: <u32> > + Description: This property sets the current limit of boost type > + regulators; supported values are: > + 0 = 300 mA > + 1 = 600 mA > + 2 = 900 mA > + 3 = 1200 mA > + 4 = 1500 mA > + 5 = 1800 mA > + 6 = 2100 mA > + 7 = 2400 mA > + > +- qcom,pin-ctrl-enable: > + Usage: optional > + Value type: <u32> > + Description: Bit mask specifying which hardware pins should be used to > + enable the regulator, if any; supported bits are: > + 0 = ignore all hardware enable signals > + BIT(0) = follow HW0_EN signal > + BIT(1) = follow HW1_EN signal > + BIT(2) = follow HW2_EN signal > + BIT(3) = follow HW3_EN signal > + > +- qcom,pin-ctrl-hpm: > + Usage: optional > + Value type: <u32> > + Description: Bit mask specifying which hardware pins should be used to > + force the regulator into high power mode, if any; > + supported bits are: > + 0 = ignore all hardware enable signals > + BIT(0) = follow HW0_EN signal > + BIT(1) = follow HW1_EN signal > + BIT(2) = follow HW2_EN signal > + BIT(3) = follow HW3_EN signal > + BIT(4) = follow PMIC awake state > + > +- qcom,vs-soft-start-strength: > + Usage: optional > + Value type: <u32> > + Description: This property sets the soft start strength for voltage > + switch type regulators; supported values are: > + 0 = 0.05 uA > + 1 = 0.25 uA > + 2 = 0.55 uA > + 3 = 0.75 uA > + > +- qcom,hpm-enable: > + Usage: optional > + Value type: <u32> > + Description: 1 = Enable high power mode (HPM), also referred > + to as NPM. HPM consumes more ground current than LPM, but > + it can source significantly higher load current. HPM is > + not available on boost type regulators. For voltage > + switch type regulators, HPM implies that over current > + protection and soft start are active all the time. This > + configuration can be overwritten by changing the > + regulator's mode dynamically. 0 = Do not enable HPM. > + > +Example: > + > + regulators { > + compatible = "qcom,pm8941-regulators"; > + vdd_l1_l3-supply = <&s1>; > + > + s1: s1 { > + regulator-min-microvolt = <1300000>; > + regulator-max-microvolt = <1400000>; > + }; > + > + ... > + > + l1: l1 { > + regulator-min-microvolt = <1225000>; > + regulator-max-microvolt = <1300000>; > + qcom,pull-down-enable = <1>; > + }; > + > + .... > + }; > diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig > index a6f116aa5235..53b3e25a98a1 100644 > --- a/drivers/regulator/Kconfig > +++ b/drivers/regulator/Kconfig > @@ -512,6 +512,17 @@ config REGULATOR_QCOM_RPM > Qualcomm RPM as a module. The module will be named > "qcom_rpm-regulator". > > +config REGULATOR_QCOM_SPMI > + tristate "Qualcomm SPMI regulator driver" > + depends on SPMI || COMPILE_TEST > + help > + If you say yes to this option, support will be included for the > + regulators found in Qualcomm SPMI PMICs. > + > + Say M here if you want to include support for the regulators on the > + Qualcomm SPMI PMICs as a module. The module will be named > + "qcom_spmi-regulator". > + > config REGULATOR_RC5T583 > tristate "RICOH RC5T583 Power regulators" > depends on MFD_RC5T583 > diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile > index 2c4da15e1545..7152c979c935 100644 > --- a/drivers/regulator/Makefile > +++ b/drivers/regulator/Makefile > @@ -61,6 +61,7 @@ obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o > obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o > obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o > obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o > +obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o > obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o > obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o > obj-$(CONFIG_REGULATOR_PWM) += pwm-regulator.o > diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c > new file mode 100644 > index 000000000000..f80d6fd940ff > --- /dev/null > +++ b/drivers/regulator/qcom_spmi-regulator.c > @@ -0,0 +1,1750 @@ > +/* > + * Copyright (c) 2012-2015, The Linux Foundation. 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 and > + * only 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/module.h> > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/kernel.h> > +#include <linux/init.h> > +#include <linux/interrupt.h> > +#include <linux/bitops.h> > +#include <linux/slab.h> > +#include <linux/of.h> > +#include <linux/of_device.h> > +#include <linux/platform_device.h> > +#include <linux/ktime.h> > +#include <linux/regulator/driver.h> > +#include <linux/regulator/of_regulator.h> > +#include <linux/regmap.h> > +#include <linux/list.h> > + > +/* Pin control enable input pins. */ > +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_NONE 0x00 > +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN0 0x01 > +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN1 0x02 > +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN2 0x04 > +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN3 0x08 > +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT 0x10 > + > +/* Pin control high power mode input pins. */ > +#define SPMI_REGULATOR_PIN_CTRL_HPM_NONE 0x00 > +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN0 0x01 > +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN1 0x02 > +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN2 0x04 > +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN3 0x08 > +#define SPMI_REGULATOR_PIN_CTRL_HPM_SLEEP_B 0x10 > +#define SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT 0x20 > + > +/* > + * Used with enable parameters to specify that hardware default register values > + * should be left unaltered. > + */ > +#define SPMI_REGULATOR_DISABLE 0 > +#define SPMI_REGULATOR_ENABLE 1 > +#define SPMI_REGULATOR_USE_HW_DEFAULT 2 > + > +/* Soft start strength of a voltage switch type regulator */ > +enum spmi_vs_soft_start_str { > + SPMI_VS_SOFT_START_STR_0P05_UA = 0, > + SPMI_VS_SOFT_START_STR_0P25_UA, > + SPMI_VS_SOFT_START_STR_0P55_UA, > + SPMI_VS_SOFT_START_STR_0P75_UA, > + SPMI_VS_SOFT_START_STR_HW_DEFAULT, > +}; > + > +/* Current limit of a boost type regulator */ > +enum spmi_boost_current_limit { > + SPMI_BOOST_CURRENT_LIMIT_300_MA = 0, > + SPMI_BOOST_CURRENT_LIMIT_600_MA, > + SPMI_BOOST_CURRENT_LIMIT_900_MA, > + SPMI_BOOST_CURRENT_LIMIT_1200_MA, > + SPMI_BOOST_CURRENT_LIMIT_1500_MA, > + SPMI_BOOST_CURRENT_LIMIT_1800_MA, > + SPMI_BOOST_CURRENT_LIMIT_2100_MA, > + SPMI_BOOST_CURRENT_LIMIT_2400_MA, > + SPMI_BOOST_CURRENT_LIMIT_HW_DEFAULT, > +}; > + > +/** > + * struct spmi_regulator_init_data - spmi-regulator initialization data > + * @pull_down_enable: 1 = Enable output pull down resistor when the > + * regulator is disabled > + * 0 = Disable pull down resistor > + * SPMI_REGULATOR_USE_HW_DEFAULT = do not modify > + * pull down state > + * @pin_ctrl_enable: Bit mask specifying which hardware pins should be > + * used to enable the regulator, if any > + * Value should be an ORing of > + * SPMI_REGULATOR_PIN_CTRL_ENABLE_* constants. If > + * the bit specified by > + * SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT is > + * set, then pin control enable hardware registers > + * will not be modified. > + * @pin_ctrl_hpm: Bit mask specifying which hardware pins should be > + * used to force the regulator into high power > + * mode, if any > + * Value should be an ORing of > + * SPMI_REGULATOR_PIN_CTRL_HPM_* constants. If > + * the bit specified by > + * SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT is > + * set, then pin control mode hardware registers > + * will not be modified. > + * @system_load: Load in uA present on regulator that is not captured > + * by any consumer request > + * @boost_current_limit: This parameter sets the current limit of boost type > + * regulators. Its value should be one of > + * SPMI_BOOST_CURRENT_LIMIT_*. If its value is > + * SPMI_BOOST_CURRENT_LIMIT_HW_DEFAULT, then the > + * boost current limit will be left at its default > + * hardware value. > + * @soft_start_enable: 1 = Enable soft start for LDO and voltage switch > + * type regulators so that output voltage slowly > + * ramps up when the regulator is enabled > + * 0 = Disable soft start > + * SPMI_REGULATOR_USE_HW_DEFAULT = do not modify > + * soft start state > + * @vs_soft_start_strength: This parameter sets the soft start strength for > + * voltage switch type regulators. Its value > + * should be one of SPMI_VS_SOFT_START_STR_*. If > + * its value is SPMI_VS_SOFT_START_STR_HW_DEFAULT, > + * then the soft start strength will be left at its > + * default hardware value. > + * @auto_mode_enable: 1 = Enable automatic hardware selection of regulator > + * mode (HPM vs LPM). Auto mode is not available > + * on boost type regulators > + * 0 = Disable auto mode selection > + * SPMI_REGULATOR_USE_HW_DEFAULT = do not modify > + * auto mode state > + * @bypass_mode_enable: 1 = Enable bypass mode for an LDO type regulator so > + * that it acts like a switch and simply outputs > + * its input voltage > + * 0 = Do not enable bypass mode > + * SPMI_REGULATOR_USE_HW_DEFAULT = do not modify > + * bypass mode state > + * @hpm_enable: 1 = Enable high power mode (HPM), also referred to > + * as NPM. HPM consumes more ground current than > + * LPM, but it can source significantly higher load > + * current. HPM is not available on boost type > + * regulators. For voltage switch type regulators, > + * HPM implies that over current protection and > + * soft start are active all the time. This > + * configuration can be overwritten by changing the > + * regulator's mode dynamically. > + * 0 = Do not enable HPM > + * SPMI_REGULATOR_USE_HW_DEFAULT = do not modify > + * HPM state > + */ > +struct spmi_regulator_init_data { > + int pull_down_enable; > + unsigned pin_ctrl_enable; > + unsigned pin_ctrl_hpm; > + int system_load; > + enum spmi_boost_current_limit boost_current_limit; > + int soft_start_enable; > + enum spmi_vs_soft_start_str vs_soft_start_strength; > + int auto_mode_enable; > + int bypass_mode_enable; > + int hpm_enable; > +}; > + > +/* These types correspond to unique register layouts. */ > +enum spmi_regulator_logical_type { > + SPMI_REGULATOR_LOGICAL_TYPE_SMPS, > + SPMI_REGULATOR_LOGICAL_TYPE_LDO, > + SPMI_REGULATOR_LOGICAL_TYPE_VS, > + SPMI_REGULATOR_LOGICAL_TYPE_BOOST, > + SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS, > + SPMI_REGULATOR_LOGICAL_TYPE_BOOST_BYP, > + SPMI_REGULATOR_LOGICAL_TYPE_LN_LDO, > + SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS, > + SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS, > + SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO, > +}; > + > +enum spmi_regulator_type { > + SPMI_REGULATOR_TYPE_BUCK = 0x03, > + SPMI_REGULATOR_TYPE_LDO = 0x04, > + SPMI_REGULATOR_TYPE_VS = 0x05, > + SPMI_REGULATOR_TYPE_BOOST = 0x1b, > + SPMI_REGULATOR_TYPE_FTS = 0x1c, > + SPMI_REGULATOR_TYPE_BOOST_BYP = 0x1f, > + SPMI_REGULATOR_TYPE_ULT_LDO = 0x21, > + SPMI_REGULATOR_TYPE_ULT_BUCK = 0x22, > +}; > + > +enum spmi_regulator_subtype { > + SPMI_REGULATOR_SUBTYPE_GP_CTL = 0x08, > + SPMI_REGULATOR_SUBTYPE_RF_CTL = 0x09, > + SPMI_REGULATOR_SUBTYPE_N50 = 0x01, > + SPMI_REGULATOR_SUBTYPE_N150 = 0x02, > + SPMI_REGULATOR_SUBTYPE_N300 = 0x03, > + SPMI_REGULATOR_SUBTYPE_N600 = 0x04, > + SPMI_REGULATOR_SUBTYPE_N1200 = 0x05, > + SPMI_REGULATOR_SUBTYPE_N600_ST = 0x06, > + SPMI_REGULATOR_SUBTYPE_N1200_ST = 0x07, > + SPMI_REGULATOR_SUBTYPE_N300_ST = 0x15, > + SPMI_REGULATOR_SUBTYPE_P50 = 0x08, > + SPMI_REGULATOR_SUBTYPE_P150 = 0x09, > + SPMI_REGULATOR_SUBTYPE_P300 = 0x0a, > + SPMI_REGULATOR_SUBTYPE_P600 = 0x0b, > + SPMI_REGULATOR_SUBTYPE_P1200 = 0x0c, > + SPMI_REGULATOR_SUBTYPE_LN = 0x10, > + SPMI_REGULATOR_SUBTYPE_LV_P50 = 0x28, > + SPMI_REGULATOR_SUBTYPE_LV_P150 = 0x29, > + SPMI_REGULATOR_SUBTYPE_LV_P300 = 0x2a, > + SPMI_REGULATOR_SUBTYPE_LV_P600 = 0x2b, > + SPMI_REGULATOR_SUBTYPE_LV_P1200 = 0x2c, > + SPMI_REGULATOR_SUBTYPE_LV100 = 0x01, > + SPMI_REGULATOR_SUBTYPE_LV300 = 0x02, > + SPMI_REGULATOR_SUBTYPE_MV300 = 0x08, > + SPMI_REGULATOR_SUBTYPE_MV500 = 0x09, > + SPMI_REGULATOR_SUBTYPE_HDMI = 0x10, > + SPMI_REGULATOR_SUBTYPE_OTG = 0x11, > + SPMI_REGULATOR_SUBTYPE_5V_BOOST = 0x01, > + SPMI_REGULATOR_SUBTYPE_FTS_CTL = 0x08, > + SPMI_REGULATOR_SUBTYPE_FTS2p5_CTL = 0x09, > + SPMI_REGULATOR_SUBTYPE_BB_2A = 0x01, > + SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL1 = 0x0d, > + SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL2 = 0x0e, > + SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL3 = 0x0f, > + SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL4 = 0x10, > +}; > + > +enum spmi_common_regulator_registers { > + SPMI_COMMON_REG_DIG_MAJOR_REV = 0x01, > + SPMI_COMMON_REG_TYPE = 0x04, > + SPMI_COMMON_REG_SUBTYPE = 0x05, > + SPMI_COMMON_REG_VOLTAGE_RANGE = 0x40, > + SPMI_COMMON_REG_VOLTAGE_SET = 0x41, > + SPMI_COMMON_REG_MODE = 0x45, > + SPMI_COMMON_REG_ENABLE = 0x46, > + SPMI_COMMON_REG_PULL_DOWN = 0x48, > + SPMI_COMMON_REG_STEP_CTRL = 0x61, > +}; > + > +enum spmi_ldo_registers { > + SPMI_LDO_REG_SOFT_START = 0x4c, > +}; > + > +enum spmi_vs_registers { > + SPMI_VS_REG_OCP = 0x4a, > + SPMI_VS_REG_SOFT_START = 0x4c, > +}; > + > +enum spmi_boost_registers { > + SPMI_BOOST_REG_CURRENT_LIMIT = 0x4a, > +}; > + > +enum spmi_boost_byp_registers { > + SPMI_BOOST_BYP_REG_CURRENT_LIMIT = 0x4b, > +}; > + > +/* Used for indexing into ctrl_reg. These are offets from 0x40 */ > +enum spmi_common_control_register_index { > + SPMI_COMMON_IDX_VOLTAGE_RANGE = 0, > + SPMI_COMMON_IDX_VOLTAGE_SET = 1, > + SPMI_COMMON_IDX_MODE = 5, > + SPMI_COMMON_IDX_ENABLE = 6, > +}; > + > +/* Common regulator control register layout */ > +#define SPMI_COMMON_ENABLE_MASK 0x80 > +#define SPMI_COMMON_ENABLE 0x80 > +#define SPMI_COMMON_DISABLE 0x00 > +#define SPMI_COMMON_ENABLE_FOLLOW_HW_EN3_MASK 0x08 > +#define SPMI_COMMON_ENABLE_FOLLOW_HW_EN2_MASK 0x04 > +#define SPMI_COMMON_ENABLE_FOLLOW_HW_EN1_MASK 0x02 > +#define SPMI_COMMON_ENABLE_FOLLOW_HW_EN0_MASK 0x01 > +#define SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK 0x0f > + > +/* Common regulator mode register layout */ > +#define SPMI_COMMON_MODE_HPM_MASK 0x80 > +#define SPMI_COMMON_MODE_AUTO_MASK 0x40 > +#define SPMI_COMMON_MODE_BYPASS_MASK 0x20 > +#define SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK 0x10 > +#define SPMI_COMMON_MODE_FOLLOW_HW_EN3_MASK 0x08 > +#define SPMI_COMMON_MODE_FOLLOW_HW_EN2_MASK 0x04 > +#define SPMI_COMMON_MODE_FOLLOW_HW_EN1_MASK 0x02 > +#define SPMI_COMMON_MODE_FOLLOW_HW_EN0_MASK 0x01 > +#define SPMI_COMMON_MODE_FOLLOW_ALL_MASK 0x1f > + > +/* Common regulator pull down control register layout */ > +#define SPMI_COMMON_PULL_DOWN_ENABLE_MASK 0x80 > + > +/* LDO regulator current limit control register layout */ > +#define SPMI_LDO_CURRENT_LIMIT_ENABLE_MASK 0x80 > + > +/* LDO regulator soft start control register layout */ > +#define SPMI_LDO_SOFT_START_ENABLE_MASK 0x80 > + > +/* VS regulator over current protection control register layout */ > +#define SPMI_VS_OCP_OVERRIDE 0x01 > +#define SPMI_VS_OCP_NO_OVERRIDE 0x00 > + > +/* VS regulator soft start control register layout */ > +#define SPMI_VS_SOFT_START_ENABLE_MASK 0x80 > +#define SPMI_VS_SOFT_START_SEL_MASK 0x03 > + > +/* Boost regulator current limit control register layout */ > +#define SPMI_BOOST_CURRENT_LIMIT_ENABLE_MASK 0x80 > +#define SPMI_BOOST_CURRENT_LIMIT_MASK 0x07 > + > +#define SPMI_VS_OCP_DEFAULT_MAX_RETRIES 10 > +#define SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS 30 > +#define SPMI_VS_OCP_FALL_DELAY_US 90 > +#define SPMI_VS_OCP_FAULT_DELAY_US 20000 > + > +#define SPMI_FTSMPS_STEP_CTRL_STEP_MASK 0x18 > +#define SPMI_FTSMPS_STEP_CTRL_STEP_SHIFT 3 > +#define SPMI_FTSMPS_STEP_CTRL_DELAY_MASK 0x07 > +#define SPMI_FTSMPS_STEP_CTRL_DELAY_SHIFT 0 > + > +/* Clock rate in kHz of the FTSMPS regulator reference clock. */ > +#define SPMI_FTSMPS_CLOCK_RATE 19200 > + > +/* Minimum voltage stepper delay for each step. */ > +#define SPMI_FTSMPS_STEP_DELAY 8 > + > +/* > + * The ratio SPMI_FTSMPS_STEP_MARGIN_NUM/SPMI_FTSMPS_STEP_MARGIN_DEN is used to > + * adjust the step rate in order to account for oscillator variance. > + */ > +#define SPMI_FTSMPS_STEP_MARGIN_NUM 4 > +#define SPMI_FTSMPS_STEP_MARGIN_DEN 5 > + > +/* > + * This voltage in uV is returned by get_voltage functions when there is no way > + * to determine the current voltage level. It is needed because the regulator > + * framework treats a 0 uV voltage as an error. > + */ > +#define VOLTAGE_UNKNOWN 1 > + > +/* VSET value to decide the range of ULT SMPS */ > +#define ULT_SMPS_RANGE_SPLIT 0x60 > + > +/** > + * struct spmi_voltage_range - regulator set point voltage mapping description > + * @min_uV: Minimum programmable output voltage resulting from > + * set point register value 0x00 > + * @max_uV: Maximum programmable output voltage > + * @step_uV: Output voltage increase resulting from the set point > + * register value increasing by 1 > + * @set_point_min_uV: Minimum allowed voltage > + * @set_point_max_uV: Maximum allowed voltage. This may be tweaked in order > + * to pick which range should be used in the case of > + * overlapping set points. > + * @n_voltages: Number of preferred voltage set points present in this > + * range > + * @range_sel: Voltage range register value corresponding to this range > + * > + * The following relationships must be true for the values used in this struct: > + * (max_uV - min_uV) % step_uV == 0 > + * (set_point_min_uV - min_uV) % step_uV == 0* > + * (set_point_max_uV - min_uV) % step_uV == 0* > + * n_voltages = (set_point_max_uV - set_point_min_uV) / step_uV + 1 > + * > + * *Note, set_point_min_uV == set_point_max_uV == 0 is allowed in order to > + * specify that the voltage range has meaning, but is not preferred. > + */ > +struct spmi_voltage_range { > + int min_uV; > + int max_uV; > + int step_uV; > + int set_point_min_uV; > + int set_point_max_uV; > + unsigned n_voltages; > + u8 range_sel; > +}; > + > +/* > + * The ranges specified in the spmi_voltage_set_points struct must be listed > + * so that range[i].set_point_max_uV < range[i+1].set_point_min_uV. > + */ > +struct spmi_voltage_set_points { > + struct spmi_voltage_range *range; > + int count; > + unsigned n_voltages; > +}; > + > +struct spmi_regulator { > + struct regulator_desc desc; > + struct device *dev; > + struct delayed_work ocp_work; > + struct regmap *regmap; > + struct spmi_voltage_set_points *set_points; > + enum spmi_regulator_logical_type logical_type; > + int ocp_enable; > + int ocp_irq; > + int ocp_count; > + int ocp_max_retries; > + int ocp_retry_delay_ms; > + int system_load; > + int hpm_min_load; > + int slew_rate; > + ktime_t vs_enable_time; > + u16 base; > + struct list_head node; > +}; > + > +struct spmi_regulator_mapping { > + enum spmi_regulator_type type; > + enum spmi_regulator_subtype subtype; > + enum spmi_regulator_logical_type logical_type; > + u32 revision_min; > + u32 revision_max; > + struct regulator_ops *ops; > + struct spmi_voltage_set_points *set_points; > + int hpm_min_load; > +}; > + > +struct spmi_regulator_data { > + const char *name; > + u16 base; > + const char *supply; > + const char *ocp; > + u16 force_type; > +}; > + > +#define VREG_MAP(_type, _subtype, _dig_major_min, _dig_major_max, \ > + _logical_type, _ops_val, _set_points_val, _hpm_min_load) \ > + { \ > + .type = SPMI_REGULATOR_TYPE_##_type, \ > + .subtype = SPMI_REGULATOR_SUBTYPE_##_subtype, \ > + .revision_min = _dig_major_min, \ > + .revision_max = _dig_major_max, \ > + .logical_type = SPMI_REGULATOR_LOGICAL_TYPE_##_logical_type, \ > + .ops = &spmi_##_ops_val##_ops, \ > + .set_points = &_set_points_val##_set_points, \ > + .hpm_min_load = _hpm_min_load, \ > + } > + > +#define VREG_MAP_VS(_subtype, _dig_major_min, _dig_major_max) \ > + { \ > + .type = SPMI_REGULATOR_TYPE_VS, \ > + .subtype = SPMI_REGULATOR_SUBTYPE_##_subtype, \ > + .revision_min = _dig_major_min, \ > + .revision_max = _dig_major_max, \ > + .logical_type = SPMI_REGULATOR_LOGICAL_TYPE_VS, \ > + .ops = &spmi_vs_ops, \ > + } > + > +#define VOLTAGE_RANGE(_range_sel, _min_uV, _set_point_min_uV, \ > + _set_point_max_uV, _max_uV, _step_uV) \ > + { \ > + .min_uV = _min_uV, \ > + .max_uV = _max_uV, \ > + .set_point_min_uV = _set_point_min_uV, \ > + .set_point_max_uV = _set_point_max_uV, \ > + .step_uV = _step_uV, \ > + .range_sel = _range_sel, \ > + } > + > +#define DEFINE_SET_POINTS(name) \ > +struct spmi_voltage_set_points name##_set_points = { \ > + .range = name##_ranges, \ > + .count = ARRAY_SIZE(name##_ranges), \ > +} > + > +/* > + * These tables contain the physically available PMIC regulator voltage setpoint > + * ranges. Where two ranges overlap in hardware, one of the ranges is trimmed > + * to ensure that the setpoints available to software are monotonically > + * increasing and unique. The set_voltage callback functions expect these > + * properties to hold. > + */ > +static struct spmi_voltage_range pldo_ranges[] = { > + VOLTAGE_RANGE(2, 750000, 750000, 1537500, 1537500, 12500), > + VOLTAGE_RANGE(3, 1500000, 1550000, 3075000, 3075000, 25000), > + VOLTAGE_RANGE(4, 1750000, 3100000, 4900000, 4900000, 50000), > +}; > + > +static struct spmi_voltage_range nldo1_ranges[] = { > + VOLTAGE_RANGE(2, 750000, 750000, 1537500, 1537500, 12500), > +}; > + > +static struct spmi_voltage_range nldo2_ranges[] = { > + VOLTAGE_RANGE(0, 375000, 0, 0, 1537500, 12500), > + VOLTAGE_RANGE(1, 375000, 375000, 768750, 768750, 6250), > + VOLTAGE_RANGE(2, 750000, 775000, 1537500, 1537500, 12500), > +}; > + > +static struct spmi_voltage_range nldo3_ranges[] = { > + VOLTAGE_RANGE(0, 375000, 375000, 1537500, 1537500, 12500), > + VOLTAGE_RANGE(1, 375000, 0, 0, 1537500, 12500), > + VOLTAGE_RANGE(2, 750000, 0, 0, 1537500, 12500), > +}; > + > +static struct spmi_voltage_range ln_ldo_ranges[] = { > + VOLTAGE_RANGE(1, 690000, 690000, 1110000, 1110000, 60000), > + VOLTAGE_RANGE(0, 1380000, 1380000, 2220000, 2220000, 120000), > +}; > + > +static struct spmi_voltage_range smps_ranges[] = { > + VOLTAGE_RANGE(0, 375000, 375000, 1562500, 1562500, 12500), > + VOLTAGE_RANGE(1, 1550000, 1575000, 3125000, 3125000, 25000), > +}; > + > +static struct spmi_voltage_range ftsmps_ranges[] = { > + VOLTAGE_RANGE(0, 0, 350000, 1275000, 1275000, 5000), > + VOLTAGE_RANGE(1, 0, 1280000, 2040000, 2040000, 10000), > +}; > + > +static struct spmi_voltage_range ftsmps2p5_ranges[] = { > + VOLTAGE_RANGE(0, 80000, 350000, 1355000, 1355000, 5000), > + VOLTAGE_RANGE(1, 160000, 1360000, 2200000, 2200000, 10000), > +}; > + > +static struct spmi_voltage_range boost_ranges[] = { > + VOLTAGE_RANGE(0, 4000000, 4000000, 5550000, 5550000, 50000), > +}; > + > +static struct spmi_voltage_range boost_byp_ranges[] = { > + VOLTAGE_RANGE(0, 2500000, 2500000, 5200000, 5650000, 50000), > +}; > + > +static struct spmi_voltage_range ult_lo_smps_ranges[] = { > + VOLTAGE_RANGE(0, 375000, 375000, 1562500, 1562500, 12500), > + VOLTAGE_RANGE(1, 750000, 0, 0, 1525000, 25000), > +}; > + > +static struct spmi_voltage_range ult_ho_smps_ranges[] = { > + VOLTAGE_RANGE(0, 1550000, 1550000, 2325000, 2325000, 25000), > +}; > + > +static struct spmi_voltage_range ult_nldo_ranges[] = { > + VOLTAGE_RANGE(0, 375000, 375000, 1537500, 1537500, 12500), > +}; > + > +static struct spmi_voltage_range ult_pldo_ranges[] = { > + VOLTAGE_RANGE(0, 1750000, 1750000, 3337500, 3337500, 12500), > +}; > + > +static DEFINE_SET_POINTS(pldo); > +static DEFINE_SET_POINTS(nldo1); > +static DEFINE_SET_POINTS(nldo2); > +static DEFINE_SET_POINTS(nldo3); > +static DEFINE_SET_POINTS(ln_ldo); > +static DEFINE_SET_POINTS(smps); > +static DEFINE_SET_POINTS(ftsmps); > +static DEFINE_SET_POINTS(ftsmps2p5); > +static DEFINE_SET_POINTS(boost); > +static DEFINE_SET_POINTS(boost_byp); > +static DEFINE_SET_POINTS(ult_lo_smps); > +static DEFINE_SET_POINTS(ult_ho_smps); > +static DEFINE_SET_POINTS(ult_nldo); > +static DEFINE_SET_POINTS(ult_pldo); > + > +static inline int spmi_vreg_read(struct spmi_regulator *vreg, u16 addr, u8 *buf, > + int len) > +{ > + return regmap_bulk_read(vreg->regmap, vreg->base + addr, buf, len); > +} > + > +static inline int spmi_vreg_write(struct spmi_regulator *vreg, u16 addr, > + u8 *buf, int len) > +{ > + return regmap_bulk_write(vreg->regmap, vreg->base + addr, buf, len); > +} > + > +static int spmi_vreg_update_bits(struct spmi_regulator *vreg, u16 addr, u8 val, > + u8 mask) > +{ > + return regmap_update_bits(vreg->regmap, vreg->base + addr, mask, val); > +} > + > +static int spmi_regulator_common_is_enabled(struct regulator_dev *rdev) > +{ > + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); > + u8 reg; > + > + reg = spmi_vreg_read(vreg, SPMI_COMMON_REG_ENABLE, ®, 1); ^^^ ^^^ You probably did not mean to use reg in both places. Most other places the return value of spmi_vreg_read() is ignored. > + > + return (reg & SPMI_COMMON_ENABLE_MASK) == SPMI_COMMON_ENABLE; > +} < snip > I did not read the driver in detail, just happened to notice the above detail. -Frank -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html