Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: palmas: add support for external control of rails

Palmas rails like LDOs, SMPSs, REGENs, SYSENs can be enable and disable
by register programming through I2C communication as well as it can be
enable/disable with the external control input ENABLE1, ENABLE2 and NSLEEP.

Add support for configuring these rails to be controlled by external control
inputs. This is require to configure the rail's control register as well as
configuration of resource register.

Provide the external input names through parameter "roof-floor". Updated the
DT binding document to details different value of the roof-floor.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Laxman Dewangan and committed by
Mark Brown
32b6d3f6 272b98c6

+167 -9
+9 -3
Documentation/devicetree/bindings/regulator/palmas-pmic.txt
··· 26 26 27 27 For ti,palmas-pmic - smps12, smps123, smps3 depending on OTP, 28 28 smps45, smps457, smps7 depending on variant, smps6, smps[8-9], 29 - smps10_out2, smps10_out1, do[1-9], ldoln, ldousb. 29 + smps10_out2, smps10_out1, ldo[1-9], ldoln, ldousb. 30 30 31 31 Optional sub-node properties: 32 32 ti,warm-reset - maintain voltage during warm reset(boolean) 33 - ti,roof-floor - control voltage selection by pin(boolean) 33 + ti,roof-floor - This takes as optional argument on platform supporting 34 + the rail from desired external control. If there is no argument then 35 + it will be assume that it is controlled by NSLEEP pin. 36 + The valid value for external pins are: 37 + ENABLE1 then 1, 38 + ENABLE2 then 2 or 39 + NSLEEP then 3. 34 40 ti,mode-sleep - mode to adopt in pmic sleep 0 - off, 1 - auto, 35 41 2 - eco, 3 - forced pwm 36 42 ti,smps-range - OTP has the wrong range set for the hardware so override ··· 67 61 regulator-always-on; 68 62 regulator-boot-on; 69 63 ti,warm-reset; 70 - ti,roof-floor; 64 + ti,roof-floor = <1>; /* ENABLE1 control */ 71 65 ti,mode-sleep = <0>; 72 66 ti,smps-range = <1>; 73 67 };
+158 -6
drivers/regulator/palmas-regulator.c
··· 33 33 u8 vsel_addr; 34 34 u8 ctrl_addr; 35 35 u8 tstep_addr; 36 + int sleep_id; 36 37 }; 37 38 38 39 static const struct regs_info palmas_regs_info[] = { ··· 43 42 .vsel_addr = PALMAS_SMPS12_VOLTAGE, 44 43 .ctrl_addr = PALMAS_SMPS12_CTRL, 45 44 .tstep_addr = PALMAS_SMPS12_TSTEP, 45 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS12, 46 46 }, 47 47 { 48 48 .name = "SMPS123", ··· 51 49 .vsel_addr = PALMAS_SMPS12_VOLTAGE, 52 50 .ctrl_addr = PALMAS_SMPS12_CTRL, 53 51 .tstep_addr = PALMAS_SMPS12_TSTEP, 52 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS12, 54 53 }, 55 54 { 56 55 .name = "SMPS3", 57 56 .sname = "smps3-in", 58 57 .vsel_addr = PALMAS_SMPS3_VOLTAGE, 59 58 .ctrl_addr = PALMAS_SMPS3_CTRL, 59 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS3, 60 60 }, 61 61 { 62 62 .name = "SMPS45", ··· 66 62 .vsel_addr = PALMAS_SMPS45_VOLTAGE, 67 63 .ctrl_addr = PALMAS_SMPS45_CTRL, 68 64 .tstep_addr = PALMAS_SMPS45_TSTEP, 65 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS45, 69 66 }, 70 67 { 71 68 .name = "SMPS457", ··· 74 69 .vsel_addr = PALMAS_SMPS45_VOLTAGE, 75 70 .ctrl_addr = PALMAS_SMPS45_CTRL, 76 71 .tstep_addr = PALMAS_SMPS45_TSTEP, 72 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS45, 77 73 }, 78 74 { 79 75 .name = "SMPS6", ··· 82 76 .vsel_addr = PALMAS_SMPS6_VOLTAGE, 83 77 .ctrl_addr = PALMAS_SMPS6_CTRL, 84 78 .tstep_addr = PALMAS_SMPS6_TSTEP, 79 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS6, 85 80 }, 86 81 { 87 82 .name = "SMPS7", 88 83 .sname = "smps7-in", 89 84 .vsel_addr = PALMAS_SMPS7_VOLTAGE, 90 85 .ctrl_addr = PALMAS_SMPS7_CTRL, 86 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS7, 91 87 }, 92 88 { 93 89 .name = "SMPS8", ··· 97 89 .vsel_addr = PALMAS_SMPS8_VOLTAGE, 98 90 .ctrl_addr = PALMAS_SMPS8_CTRL, 99 91 .tstep_addr = PALMAS_SMPS8_TSTEP, 92 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS8, 100 93 }, 101 94 { 102 95 .name = "SMPS9", 103 96 .sname = "smps9-in", 104 97 .vsel_addr = PALMAS_SMPS9_VOLTAGE, 105 98 .ctrl_addr = PALMAS_SMPS9_CTRL, 99 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS9, 106 100 }, 107 101 { 108 102 .name = "SMPS10_OUT2", 109 103 .sname = "smps10-in", 110 104 .ctrl_addr = PALMAS_SMPS10_CTRL, 105 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS10, 111 106 }, 112 107 { 113 108 .name = "SMPS10_OUT1", 114 109 .sname = "smps10-out2", 115 110 .ctrl_addr = PALMAS_SMPS10_CTRL, 111 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SMPS10, 116 112 }, 117 113 { 118 114 .name = "LDO1", 119 115 .sname = "ldo1-in", 120 116 .vsel_addr = PALMAS_LDO1_VOLTAGE, 121 117 .ctrl_addr = PALMAS_LDO1_CTRL, 118 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO1, 122 119 }, 123 120 { 124 121 .name = "LDO2", 125 122 .sname = "ldo2-in", 126 123 .vsel_addr = PALMAS_LDO2_VOLTAGE, 127 124 .ctrl_addr = PALMAS_LDO2_CTRL, 125 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO2, 128 126 }, 129 127 { 130 128 .name = "LDO3", 131 129 .sname = "ldo3-in", 132 130 .vsel_addr = PALMAS_LDO3_VOLTAGE, 133 131 .ctrl_addr = PALMAS_LDO3_CTRL, 132 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO3, 134 133 }, 135 134 { 136 135 .name = "LDO4", 137 136 .sname = "ldo4-in", 138 137 .vsel_addr = PALMAS_LDO4_VOLTAGE, 139 138 .ctrl_addr = PALMAS_LDO4_CTRL, 139 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO4, 140 140 }, 141 141 { 142 142 .name = "LDO5", 143 143 .sname = "ldo5-in", 144 144 .vsel_addr = PALMAS_LDO5_VOLTAGE, 145 145 .ctrl_addr = PALMAS_LDO5_CTRL, 146 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO5, 146 147 }, 147 148 { 148 149 .name = "LDO6", 149 150 .sname = "ldo6-in", 150 151 .vsel_addr = PALMAS_LDO6_VOLTAGE, 151 152 .ctrl_addr = PALMAS_LDO6_CTRL, 153 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO6, 152 154 }, 153 155 { 154 156 .name = "LDO7", 155 157 .sname = "ldo7-in", 156 158 .vsel_addr = PALMAS_LDO7_VOLTAGE, 157 159 .ctrl_addr = PALMAS_LDO7_CTRL, 160 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO7, 158 161 }, 159 162 { 160 163 .name = "LDO8", 161 164 .sname = "ldo8-in", 162 165 .vsel_addr = PALMAS_LDO8_VOLTAGE, 163 166 .ctrl_addr = PALMAS_LDO8_CTRL, 167 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO8, 164 168 }, 165 169 { 166 170 .name = "LDO9", 167 171 .sname = "ldo9-in", 168 172 .vsel_addr = PALMAS_LDO9_VOLTAGE, 169 173 .ctrl_addr = PALMAS_LDO9_CTRL, 174 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDO9, 170 175 }, 171 176 { 172 177 .name = "LDOLN", 173 178 .sname = "ldoln-in", 174 179 .vsel_addr = PALMAS_LDOLN_VOLTAGE, 175 180 .ctrl_addr = PALMAS_LDOLN_CTRL, 181 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDOLN, 176 182 }, 177 183 { 178 184 .name = "LDOUSB", 179 185 .sname = "ldousb-in", 180 186 .vsel_addr = PALMAS_LDOUSB_VOLTAGE, 181 187 .ctrl_addr = PALMAS_LDOUSB_CTRL, 188 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_LDOUSB, 182 189 }, 183 190 { 184 191 .name = "REGEN1", 185 192 .ctrl_addr = PALMAS_REGEN1_CTRL, 193 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_REGEN1, 186 194 }, 187 195 { 188 196 .name = "REGEN2", 189 197 .ctrl_addr = PALMAS_REGEN2_CTRL, 198 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_REGEN2, 190 199 }, 191 200 { 192 201 .name = "REGEN3", 193 202 .ctrl_addr = PALMAS_REGEN3_CTRL, 203 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_REGEN3, 194 204 }, 195 205 { 196 206 .name = "SYSEN1", 197 207 .ctrl_addr = PALMAS_SYSEN1_CTRL, 208 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SYSEN1, 198 209 }, 199 210 { 200 211 .name = "SYSEN2", 201 212 .ctrl_addr = PALMAS_SYSEN2_CTRL, 213 + .sleep_id = PALMAS_EXTERNAL_REQSTR_ID_SYSEN2, 202 214 }, 203 215 }; 204 216 ··· 512 484 .set_ramp_delay = palmas_smps_set_ramp_delay, 513 485 }; 514 486 487 + static struct regulator_ops palmas_ops_ext_control_smps = { 488 + .set_mode = palmas_set_mode_smps, 489 + .get_mode = palmas_get_mode_smps, 490 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 491 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 492 + .list_voltage = palmas_list_voltage_smps, 493 + .map_voltage = palmas_map_voltage_smps, 494 + .set_voltage_time_sel = palma_smps_set_voltage_smps_time_sel, 495 + .set_ramp_delay = palmas_smps_set_ramp_delay, 496 + }; 497 + 515 498 static struct regulator_ops palmas_ops_smps10 = { 516 499 .is_enabled = regulator_is_enabled_regmap, 517 500 .enable = regulator_enable_regmap, ··· 558 519 .map_voltage = regulator_map_voltage_linear, 559 520 }; 560 521 522 + static struct regulator_ops palmas_ops_ext_control_ldo = { 523 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 524 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 525 + .list_voltage = regulator_list_voltage_linear, 526 + .map_voltage = regulator_map_voltage_linear, 527 + }; 528 + 561 529 static struct regulator_ops palmas_ops_extreg = { 562 530 .is_enabled = regulator_is_enabled_regmap, 563 531 .enable = regulator_enable_regmap, 564 532 .disable = regulator_disable_regmap, 565 533 }; 534 + 535 + static struct regulator_ops palmas_ops_ext_control_extreg = { 536 + }; 537 + 538 + static int palmas_regulator_config_external(struct palmas *palmas, int id, 539 + struct palmas_reg_init *reg_init) 540 + { 541 + int sleep_id = palmas_regs_info[id].sleep_id; 542 + int ret; 543 + 544 + ret = palmas_ext_control_req_config(palmas, sleep_id, 545 + reg_init->roof_floor, true); 546 + if (ret < 0) 547 + dev_err(palmas->dev, 548 + "Ext control config for regulator %d failed %d\n", 549 + id, ret); 550 + return ret; 551 + } 566 552 567 553 /* 568 554 * setup the hardware based sleep configuration of the SMPS/LDO regulators ··· 647 583 return ret; 648 584 } 649 585 586 + if (reg_init->roof_floor && (id != PALMAS_REG_SMPS10_OUT1) && 587 + (id != PALMAS_REG_SMPS10_OUT2)) { 588 + /* Enable externally controlled regulator */ 589 + addr = palmas_regs_info[id].ctrl_addr; 590 + ret = palmas_smps_read(palmas, addr, &reg); 591 + if (ret < 0) 592 + return ret; 650 593 594 + if (!(reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK)) { 595 + reg |= SMPS_CTRL_MODE_ON; 596 + ret = palmas_smps_write(palmas, addr, reg); 597 + if (ret < 0) 598 + return ret; 599 + } 600 + return palmas_regulator_config_external(palmas, id, reg_init); 601 + } 651 602 return 0; 652 603 } 653 604 ··· 693 614 if (ret) 694 615 return ret; 695 616 617 + if (reg_init->roof_floor) { 618 + /* Enable externally controlled regulator */ 619 + addr = palmas_regs_info[id].ctrl_addr; 620 + ret = palmas_update_bits(palmas, PALMAS_LDO_BASE, 621 + addr, PALMAS_LDO1_CTRL_MODE_ACTIVE, 622 + PALMAS_LDO1_CTRL_MODE_ACTIVE); 623 + if (ret < 0) { 624 + dev_err(palmas->dev, 625 + "LDO Register 0x%02x update failed %d\n", 626 + addr, ret); 627 + return ret; 628 + } 629 + return palmas_regulator_config_external(palmas, id, reg_init); 630 + } 696 631 return 0; 697 632 } 698 633 ··· 728 635 dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n", 729 636 addr, ret); 730 637 return ret; 638 + } 639 + 640 + if (reg_init->roof_floor) { 641 + /* Enable externally controlled regulator */ 642 + addr = palmas_regs_info[id].ctrl_addr; 643 + ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, 644 + addr, PALMAS_REGEN1_CTRL_MODE_ACTIVE, 645 + PALMAS_REGEN1_CTRL_MODE_ACTIVE); 646 + if (ret < 0) { 647 + dev_err(palmas->dev, 648 + "Resource Register 0x%02x update failed %d\n", 649 + addr, ret); 650 + return ret; 651 + } 652 + return palmas_regulator_config_external(palmas, id, reg_init); 731 653 } 732 654 return 0; 733 655 } ··· 854 746 of_property_read_bool(palmas_matches[idx].of_node, 855 747 "ti,warm-reset"); 856 748 857 - pdata->reg_init[idx]->roof_floor = 858 - of_property_read_bool(palmas_matches[idx].of_node, 859 - "ti,roof-floor"); 749 + ret = of_property_read_u32(palmas_matches[idx].of_node, 750 + "ti,roof-floor", &prop); 751 + /* EINVAL: Property not found */ 752 + if (ret != -EINVAL) { 753 + int econtrol; 754 + 755 + /* use default value, when no value is specified */ 756 + econtrol = PALMAS_EXT_CONTROL_NSLEEP; 757 + if (!ret) { 758 + switch (prop) { 759 + case 1: 760 + econtrol = PALMAS_EXT_CONTROL_ENABLE1; 761 + break; 762 + case 2: 763 + econtrol = PALMAS_EXT_CONTROL_ENABLE2; 764 + break; 765 + case 3: 766 + econtrol = PALMAS_EXT_CONTROL_NSLEEP; 767 + break; 768 + default: 769 + WARN_ON(1); 770 + dev_warn(dev, 771 + "%s: Invalid roof-floor option: %u\n", 772 + palmas_matches[idx].name, prop); 773 + break; 774 + } 775 + } 776 + pdata->reg_init[idx]->roof_floor = econtrol; 777 + } 860 778 861 779 ret = of_property_read_u32(palmas_matches[idx].of_node, 862 780 "ti,mode-sleep", &prop); ··· 1009 875 ret = palmas_smps_init(palmas, id, reg_init); 1010 876 if (ret) 1011 877 goto err_unregister_regulator; 878 + } else { 879 + reg_init = NULL; 1012 880 } 1013 881 1014 882 /* Register the regulators */ ··· 1055 919 if (reg & PALMAS_SMPS12_VOLTAGE_RANGE) 1056 920 pmic->range[id] = 1; 1057 921 1058 - pmic->desc[id].ops = &palmas_ops_smps; 922 + if (reg_init && reg_init->roof_floor) 923 + pmic->desc[id].ops = 924 + &palmas_ops_ext_control_smps; 925 + else 926 + pmic->desc[id].ops = &palmas_ops_smps; 1059 927 pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES; 1060 928 pmic->desc[id].vsel_reg = 1061 929 PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, ··· 1102 962 1103 963 /* Start this loop from the id left from previous loop */ 1104 964 for (; id < PALMAS_NUM_REGS; id++) { 965 + if (pdata && pdata->reg_init[id]) 966 + reg_init = pdata->reg_init[id]; 967 + else 968 + reg_init = NULL; 1105 969 1106 970 /* Miss out regulators which are not available due 1107 971 * to alternate functions. ··· 1119 975 1120 976 if (id < PALMAS_REG_REGEN1) { 1121 977 pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES; 1122 - pmic->desc[id].ops = &palmas_ops_ldo; 978 + if (reg_init && reg_init->roof_floor) 979 + pmic->desc[id].ops = 980 + &palmas_ops_ext_control_ldo; 981 + else 982 + pmic->desc[id].ops = &palmas_ops_ldo; 1123 983 pmic->desc[id].min_uV = 900000; 1124 984 pmic->desc[id].uV_step = 50000; 1125 985 pmic->desc[id].linear_min_sel = 1; ··· 1147 999 } 1148 1000 } else { 1149 1001 pmic->desc[id].n_voltages = 1; 1150 - pmic->desc[id].ops = &palmas_ops_extreg; 1002 + if (reg_init && reg_init->roof_floor) 1003 + pmic->desc[id].ops = 1004 + &palmas_ops_ext_control_extreg; 1005 + else 1006 + pmic->desc[id].ops = &palmas_ops_extreg; 1151 1007 pmic->desc[id].enable_reg = 1152 1008 PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE, 1153 1009 palmas_regs_info[id].ctrl_addr);