[PATCH] regulator: Add SPMI regulator driver
Frank Rowand
frowand.list at gmail.com
Fri May 15 18:50:46 PDT 2015
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 at codeaurora.org>
> Cc: <devicetree at vger.kernel.org>
> Signed-off-by: Stephen Boyd <sboyd at codeaurora.org>
> ---
> .../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
More information about the linux-arm-kernel
mailing list