aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlia Lin <ilialin@codeaurora.org>2018-05-21 07:25:30 -0400
committerMark Brown <broonie@kernel.org>2018-05-24 15:23:43 -0400
commit0caecaa87202b667591d57e8ca233ee1b548ba13 (patch)
tree34a0ba248c814f4e1e947d51785198bb39a6735f
parent3012e81446d011c1bd99812e562e2292f21060fb (diff)
regulator: qcom_spmi: Add support for SAW
Add support for SAW controlled regulators. The regulators defined as SAW controlled in the device tree will be controlled through special CPU registers instead of direct SPMI accesses. This is required especially for CPU supply regulators to synchronize with clock scaling and for Automatic Voltage Switching. Signed-off-by: Ilia Lin <ilialin@codeaurora.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/regulator/qcom_spmi-regulator.c133
1 files changed, 130 insertions, 3 deletions
diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c
index 63c7a0c17777..9817f1a75342 100644
--- a/drivers/regulator/qcom_spmi-regulator.c
+++ b/drivers/regulator/qcom_spmi-regulator.c
@@ -25,6 +25,8 @@
25#include <linux/regulator/driver.h> 25#include <linux/regulator/driver.h>
26#include <linux/regmap.h> 26#include <linux/regmap.h>
27#include <linux/list.h> 27#include <linux/list.h>
28#include <linux/mfd/syscon.h>
29#include <linux/io.h>
28 30
29/* Pin control enable input pins. */ 31/* Pin control enable input pins. */
30#define SPMI_REGULATOR_PIN_CTRL_ENABLE_NONE 0x00 32#define SPMI_REGULATOR_PIN_CTRL_ENABLE_NONE 0x00
@@ -181,6 +183,23 @@ enum spmi_boost_byp_registers {
181 SPMI_BOOST_BYP_REG_CURRENT_LIMIT = 0x4b, 183 SPMI_BOOST_BYP_REG_CURRENT_LIMIT = 0x4b,
182}; 184};
183 185
186enum spmi_saw3_registers {
187 SAW3_SECURE = 0x00,
188 SAW3_ID = 0x04,
189 SAW3_SPM_STS = 0x0C,
190 SAW3_AVS_STS = 0x10,
191 SAW3_PMIC_STS = 0x14,
192 SAW3_RST = 0x18,
193 SAW3_VCTL = 0x1C,
194 SAW3_AVS_CTL = 0x20,
195 SAW3_AVS_LIMIT = 0x24,
196 SAW3_AVS_DLY = 0x28,
197 SAW3_AVS_HYSTERESIS = 0x2C,
198 SAW3_SPM_STS2 = 0x38,
199 SAW3_SPM_PMIC_DATA_3 = 0x4C,
200 SAW3_VERSION = 0xFD0,
201};
202
184/* Used for indexing into ctrl_reg. These are offets from 0x40 */ 203/* Used for indexing into ctrl_reg. These are offets from 0x40 */
185enum spmi_common_control_register_index { 204enum spmi_common_control_register_index {
186 SPMI_COMMON_IDX_VOLTAGE_RANGE = 0, 205 SPMI_COMMON_IDX_VOLTAGE_RANGE = 0,
@@ -1035,6 +1054,89 @@ static irqreturn_t spmi_regulator_vs_ocp_isr(int irq, void *data)
1035 return IRQ_HANDLED; 1054 return IRQ_HANDLED;
1036} 1055}
1037 1056
1057#define SAW3_VCTL_DATA_MASK 0xFF
1058#define SAW3_VCTL_CLEAR_MASK 0x700FF
1059#define SAW3_AVS_CTL_EN_MASK 0x1
1060#define SAW3_AVS_CTL_TGGL_MASK 0x8000000
1061#define SAW3_AVS_CTL_CLEAR_MASK 0x7efc00
1062
1063static struct regmap *saw_regmap = NULL;
1064
1065static void spmi_saw_set_vdd(void *data)
1066{
1067 u32 vctl, data3, avs_ctl, pmic_sts;
1068 bool avs_enabled = false;
1069 unsigned long timeout;
1070 u8 voltage_sel = *(u8 *)data;
1071
1072 regmap_read(saw_regmap, SAW3_AVS_CTL, &avs_ctl);
1073 regmap_read(saw_regmap, SAW3_VCTL, &vctl);
1074 regmap_read(saw_regmap, SAW3_SPM_PMIC_DATA_3, &data3);
1075
1076 /* select the band */
1077 vctl &= ~SAW3_VCTL_CLEAR_MASK;
1078 vctl |= (u32)voltage_sel;
1079
1080 data3 &= ~SAW3_VCTL_CLEAR_MASK;
1081 data3 |= (u32)voltage_sel;
1082
1083 /* If AVS is enabled, switch it off during the voltage change */
1084 avs_enabled = SAW3_AVS_CTL_EN_MASK & avs_ctl;
1085 if (avs_enabled) {
1086 avs_ctl &= ~SAW3_AVS_CTL_TGGL_MASK;
1087 regmap_write(saw_regmap, SAW3_AVS_CTL, avs_ctl);
1088 }
1089
1090 regmap_write(saw_regmap, SAW3_RST, 1);
1091 regmap_write(saw_regmap, SAW3_VCTL, vctl);
1092 regmap_write(saw_regmap, SAW3_SPM_PMIC_DATA_3, data3);
1093
1094 timeout = jiffies + usecs_to_jiffies(100);
1095 do {
1096 regmap_read(saw_regmap, SAW3_PMIC_STS, &pmic_sts);
1097 pmic_sts &= SAW3_VCTL_DATA_MASK;
1098 if (pmic_sts == (u32)voltage_sel)
1099 break;
1100
1101 cpu_relax();
1102
1103 } while (time_before(jiffies, timeout));
1104
1105 /* After successful voltage change, switch the AVS back on */
1106 if (avs_enabled) {
1107 pmic_sts &= 0x3f;
1108 avs_ctl &= ~SAW3_AVS_CTL_CLEAR_MASK;
1109 avs_ctl |= ((pmic_sts - 4) << 10);
1110 avs_ctl |= (pmic_sts << 17);
1111 avs_ctl |= SAW3_AVS_CTL_TGGL_MASK;
1112 regmap_write(saw_regmap, SAW3_AVS_CTL, avs_ctl);
1113 }
1114}
1115
1116static int
1117spmi_regulator_saw_set_voltage(struct regulator_dev *rdev, unsigned selector)
1118{
1119 struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
1120 int ret;
1121 u8 range_sel, voltage_sel;
1122
1123 ret = spmi_sw_selector_to_hw(vreg, selector, &range_sel, &voltage_sel);
1124 if (ret)
1125 return ret;
1126
1127 if (0 != range_sel) {
1128 dev_dbg(&rdev->dev, "range_sel = %02X voltage_sel = %02X", \
1129 range_sel, voltage_sel);
1130 return -EINVAL;
1131 }
1132
1133 /* Always do the SAW register writes on the first CPU */
1134 return smp_call_function_single(0, spmi_saw_set_vdd, \
1135 &voltage_sel, true);
1136}
1137
1138static struct regulator_ops spmi_saw_ops = {};
1139
1038static struct regulator_ops spmi_smps_ops = { 1140static struct regulator_ops spmi_smps_ops = {
1039 .enable = regulator_enable_regmap, 1141 .enable = regulator_enable_regmap,
1040 .disable = regulator_disable_regmap, 1142 .disable = regulator_disable_regmap,
@@ -1250,6 +1352,7 @@ static int spmi_regulator_match(struct spmi_regulator *vreg, u16 force_type)
1250 } 1352 }
1251 dig_major_rev = version[SPMI_COMMON_REG_DIG_MAJOR_REV 1353 dig_major_rev = version[SPMI_COMMON_REG_DIG_MAJOR_REV
1252 - SPMI_COMMON_REG_DIG_MAJOR_REV]; 1354 - SPMI_COMMON_REG_DIG_MAJOR_REV];
1355
1253 if (!force_type) { 1356 if (!force_type) {
1254 type = version[SPMI_COMMON_REG_TYPE - 1357 type = version[SPMI_COMMON_REG_TYPE -
1255 SPMI_COMMON_REG_DIG_MAJOR_REV]; 1358 SPMI_COMMON_REG_DIG_MAJOR_REV];
@@ -1648,7 +1751,9 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
1648 struct regmap *regmap; 1751 struct regmap *regmap;
1649 const char *name; 1752 const char *name;
1650 struct device *dev = &pdev->dev; 1753 struct device *dev = &pdev->dev;
1651 int ret; 1754 struct device_node *node = pdev->dev.of_node;
1755 struct device_node *syscon;
1756 int ret, lenp;
1652 struct list_head *vreg_list; 1757 struct list_head *vreg_list;
1653 1758
1654 vreg_list = devm_kzalloc(dev, sizeof(*vreg_list), GFP_KERNEL); 1759 vreg_list = devm_kzalloc(dev, sizeof(*vreg_list), GFP_KERNEL);
@@ -1665,7 +1770,22 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
1665 if (!match) 1770 if (!match)
1666 return -ENODEV; 1771 return -ENODEV;
1667 1772
1773 if (of_find_property(node, "qcom,saw-reg", &lenp)) {
1774 syscon = of_parse_phandle(node, "qcom,saw-reg", 0);
1775 saw_regmap = syscon_node_to_regmap(syscon);
1776 of_node_put(syscon);
1777 if (IS_ERR(regmap))
1778 dev_err(dev, "ERROR reading SAW regmap\n");
1779 }
1780
1668 for (reg = match->data; reg->name; reg++) { 1781 for (reg = match->data; reg->name; reg++) {
1782
1783 if (saw_regmap && \
1784 of_find_property(of_find_node_by_name(node, reg->name), \
1785 "qcom,saw-slave", &lenp)) {
1786 continue;
1787 }
1788
1669 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); 1789 vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
1670 if (!vreg) 1790 if (!vreg)
1671 return -ENOMEM; 1791 return -ENOMEM;
@@ -1673,7 +1793,6 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
1673 vreg->dev = dev; 1793 vreg->dev = dev;
1674 vreg->base = reg->base; 1794 vreg->base = reg->base;
1675 vreg->regmap = regmap; 1795 vreg->regmap = regmap;
1676
1677 if (reg->ocp) { 1796 if (reg->ocp) {
1678 vreg->ocp_irq = platform_get_irq_byname(pdev, reg->ocp); 1797 vreg->ocp_irq = platform_get_irq_byname(pdev, reg->ocp);
1679 if (vreg->ocp_irq < 0) { 1798 if (vreg->ocp_irq < 0) {
@@ -1681,7 +1800,6 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
1681 goto err; 1800 goto err;
1682 } 1801 }
1683 } 1802 }
1684
1685 vreg->desc.id = -1; 1803 vreg->desc.id = -1;
1686 vreg->desc.owner = THIS_MODULE; 1804 vreg->desc.owner = THIS_MODULE;
1687 vreg->desc.type = REGULATOR_VOLTAGE; 1805 vreg->desc.type = REGULATOR_VOLTAGE;
@@ -1698,6 +1816,15 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
1698 if (ret) 1816 if (ret)
1699 continue; 1817 continue;
1700 1818
1819 if (saw_regmap && \
1820 of_find_property(of_find_node_by_name(node, reg->name), \
1821 "qcom,saw-leader", &lenp)) {
1822 spmi_saw_ops = *(vreg->desc.ops);
1823 spmi_saw_ops.set_voltage_sel = \
1824 spmi_regulator_saw_set_voltage;
1825 vreg->desc.ops = &spmi_saw_ops;
1826 }
1827
1701 config.dev = dev; 1828 config.dev = dev;
1702 config.driver_data = vreg; 1829 config.driver_data = vreg;
1703 config.regmap = regmap; 1830 config.regmap = regmap;