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

regulator: as3722: add regulator driver for AMS AS3722

The AMS AS3722 is a compact system PMU suitable for mobile phones,
tablets etc. It has 4 DCDC step down regulators, 3 DCDC step down
controller, 11 LDOs.

Add a driver to support accessing the DCDC/LDOs found on the AMS
AS3722 PMIC using regulators.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Florian Lobmaier <florian.lobmaier@ams.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Laxman Dewangan and committed by
Mark Brown
bc407334 272b98c6

+1017
+91
Documentation/devicetree/bindings/regulator/as3722-regulator.txt
··· 1 + Regulator of AMS AS3722 PMIC. 2 + Name of the regulator subnode must be "regulators". 3 + 4 + Optional properties: 5 + -------------------- 6 + The input supply of regulators are the optional properties on the 7 + regulator node. The AS3722 is having 7 DCDC step-down regulators as 8 + sd[0-6], 10 LDOs as ldo[0-7], ldo[9-11]. The input supply of these 9 + regulators are provided through following properties: 10 + vsup-sd2-supply: Input supply for SD2. 11 + vsup-sd3-supply: Input supply for SD3. 12 + vsup-sd4-supply: Input supply for SD4. 13 + vsup-sd5-supply: Input supply for SD5. 14 + vin-ldo0-supply: Input supply for LDO0. 15 + vin-ldo1-6-supply: Input supply for LDO1 and LDO6. 16 + vin-ldo2-5-7-supply: Input supply for LDO2, LDO5 and LDO7. 17 + vin-ldo3-4-supply: Input supply for LDO3 and LDO4. 18 + vin-ldo9-10-supply: Input supply for LDO9 and LDO10. 19 + vin-ldo11-supply: Input supply for LDO11. 20 + 21 + Optional nodes: 22 + -------------- 23 + - regulators : Must contain a sub-node per regulator from the list below. 24 + Each sub-node should contain the constraints and initialization 25 + information for that regulator. See regulator.txt for a 26 + description of standard properties for these sub-nodes. 27 + Additional custom properties are listed below. 28 + sd[0-6], ldo[0-7], ldo[9-11]. 29 + 30 + Optional sub-node properties: 31 + ---------------------------- 32 + ams,ext-control: External control of the rail. The option of 33 + this properties will tell which external input is 34 + controlling this rail. Valid values are 0, 1, 2 ad 3. 35 + 0: There is no external control of this rail. 36 + 1: Rail is controlled by ENABLE1 input pin. 37 + 2: Rail is controlled by ENABLE2 input pin. 38 + 3: Rail is controlled by ENABLE3 input pin. 39 + ams,enable-tracking: Enable tracking with SD1, only supported 40 + by LDO3. 41 + 42 + Example: 43 + ------- 44 + ams3722: ams3722 { 45 + compatible = "ams,as3722"; 46 + reg = <0x40>; 47 + ... 48 + 49 + regulators { 50 + vsup-sd2-supply = <...>; 51 + ... 52 + 53 + sd0 { 54 + regulator-name = "vdd_cpu"; 55 + regulator-min-microvolt = <700000>; 56 + regulator-max-microvolt = <1400000>; 57 + regulator-always-on; 58 + ams,ext-control = <2>; 59 + }; 60 + 61 + sd1 { 62 + regulator-name = "vdd_core"; 63 + regulator-min-microvolt = <700000>; 64 + regulator-max-microvolt = <1400000>; 65 + regulator-always-on; 66 + ams,ext-control = <1>; 67 + }; 68 + 69 + sd2 { 70 + regulator-name = "vddio_ddr"; 71 + regulator-min-microvolt = <1350000>; 72 + regulator-max-microvolt = <1350000>; 73 + regulator-always-on; 74 + }; 75 + 76 + sd4 { 77 + regulator-name = "avdd-hdmi-pex"; 78 + regulator-min-microvolt = <1050000>; 79 + regulator-max-microvolt = <1050000>; 80 + regulator-always-on; 81 + }; 82 + 83 + sd5 { 84 + regulator-name = "vdd-1v8"; 85 + regulator-min-microvolt = <1800000>; 86 + regulator-max-microvolt = <1800000>; 87 + regulator-always-on; 88 + }; 89 + .... 90 + }; 91 + };
+8
drivers/regulator/Kconfig
··· 133 133 This driver provides support for the voltage regulators on the 134 134 AS3711 PMIC 135 135 136 + config REGULATOR_AS3722 137 + tristate "AMS AS3722 PMIC Regulators" 138 + depends on MFD_AS3722 139 + help 140 + This driver provides support for the voltage regulators on the 141 + AS3722 PMIC. This will enable support for all the software 142 + controllable DCDC/LDO regulators. 143 + 136 144 config REGULATOR_DA903X 137 145 tristate "Dialog Semiconductor DA9030/DA9034 regulators" 138 146 depends on PMIC_DA903X
+1
drivers/regulator/Makefile
··· 18 18 obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o 19 19 obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o 20 20 obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o 21 + obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o 21 22 obj-$(CONFIG_REGULATOR_DA903X) += da903x.o 22 23 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o 23 24 obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o
+917
drivers/regulator/as3722-regulator.c
··· 1 + /* 2 + * Voltage regulator support for AMS AS3722 PMIC 3 + * 4 + * Copyright (C) 2013 ams 5 + * 6 + * Author: Florian Lobmaier <florian.lobmaier@ams.com> 7 + * Author: Laxman Dewangan <ldewangan@nvidia.com> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * GNU General Public License for more details. 18 + * 19 + * You should have received a copy of the GNU General Public License 20 + * along with this program; if not, write to the Free Software 21 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 + * 23 + */ 24 + 25 + #include <linux/err.h> 26 + #include <linux/kernel.h> 27 + #include <linux/module.h> 28 + #include <linux/mfd/as3722.h> 29 + #include <linux/of.h> 30 + #include <linux/of_platform.h> 31 + #include <linux/platform_device.h> 32 + #include <linux/regulator/driver.h> 33 + #include <linux/regulator/machine.h> 34 + #include <linux/regulator/of_regulator.h> 35 + #include <linux/slab.h> 36 + 37 + /* Regulator IDs */ 38 + enum as3722_regulators_id { 39 + AS3722_REGULATOR_ID_SD0, 40 + AS3722_REGULATOR_ID_SD1, 41 + AS3722_REGULATOR_ID_SD2, 42 + AS3722_REGULATOR_ID_SD3, 43 + AS3722_REGULATOR_ID_SD4, 44 + AS3722_REGULATOR_ID_SD5, 45 + AS3722_REGULATOR_ID_SD6, 46 + AS3722_REGULATOR_ID_LDO0, 47 + AS3722_REGULATOR_ID_LDO1, 48 + AS3722_REGULATOR_ID_LDO2, 49 + AS3722_REGULATOR_ID_LDO3, 50 + AS3722_REGULATOR_ID_LDO4, 51 + AS3722_REGULATOR_ID_LDO5, 52 + AS3722_REGULATOR_ID_LDO6, 53 + AS3722_REGULATOR_ID_LDO7, 54 + AS3722_REGULATOR_ID_LDO9, 55 + AS3722_REGULATOR_ID_LDO10, 56 + AS3722_REGULATOR_ID_LDO11, 57 + AS3722_REGULATOR_ID_MAX, 58 + }; 59 + 60 + struct as3722_register_mapping { 61 + u8 regulator_id; 62 + const char *name; 63 + const char *sname; 64 + u8 vsel_reg; 65 + u8 vsel_mask; 66 + int n_voltages; 67 + u32 enable_reg; 68 + u8 enable_mask; 69 + u32 control_reg; 70 + u8 mode_mask; 71 + u32 sleep_ctrl_reg; 72 + u8 sleep_ctrl_mask; 73 + }; 74 + 75 + struct as3722_regulator_config_data { 76 + struct regulator_init_data *reg_init; 77 + bool enable_tracking; 78 + int ext_control; 79 + }; 80 + 81 + struct as3722_regulators { 82 + struct device *dev; 83 + struct as3722 *as3722; 84 + struct regulator_dev *rdevs[AS3722_REGULATOR_ID_MAX]; 85 + struct regulator_desc desc[AS3722_REGULATOR_ID_MAX]; 86 + struct as3722_regulator_config_data 87 + reg_config_data[AS3722_REGULATOR_ID_MAX]; 88 + }; 89 + 90 + static const struct as3722_register_mapping as3722_reg_lookup[] = { 91 + { 92 + .regulator_id = AS3722_REGULATOR_ID_SD0, 93 + .name = "as3722-sd0", 94 + .vsel_reg = AS3722_SD0_VOLTAGE_REG, 95 + .vsel_mask = AS3722_SD_VSEL_MASK, 96 + .enable_reg = AS3722_SD_CONTROL_REG, 97 + .enable_mask = AS3722_SDn_CTRL(0), 98 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, 99 + .sleep_ctrl_mask = AS3722_SD0_EXT_ENABLE_MASK, 100 + .control_reg = AS3722_SD0_CONTROL_REG, 101 + .mode_mask = AS3722_SD0_MODE_FAST, 102 + .n_voltages = AS3722_SD0_VSEL_MAX, 103 + }, 104 + { 105 + .regulator_id = AS3722_REGULATOR_ID_SD1, 106 + .name = "as3722-sd1", 107 + .vsel_reg = AS3722_SD1_VOLTAGE_REG, 108 + .vsel_mask = AS3722_SD_VSEL_MASK, 109 + .enable_reg = AS3722_SD_CONTROL_REG, 110 + .enable_mask = AS3722_SDn_CTRL(1), 111 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, 112 + .sleep_ctrl_mask = AS3722_SD1_EXT_ENABLE_MASK, 113 + .control_reg = AS3722_SD1_CONTROL_REG, 114 + .mode_mask = AS3722_SD1_MODE_FAST, 115 + .n_voltages = AS3722_SD0_VSEL_MAX, 116 + }, 117 + { 118 + .regulator_id = AS3722_REGULATOR_ID_SD2, 119 + .name = "as3722-sd2", 120 + .sname = "vsup-sd2", 121 + .vsel_reg = AS3722_SD2_VOLTAGE_REG, 122 + .vsel_mask = AS3722_SD_VSEL_MASK, 123 + .enable_reg = AS3722_SD_CONTROL_REG, 124 + .enable_mask = AS3722_SDn_CTRL(2), 125 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, 126 + .sleep_ctrl_mask = AS3722_SD2_EXT_ENABLE_MASK, 127 + .control_reg = AS3722_SD23_CONTROL_REG, 128 + .mode_mask = AS3722_SD2_MODE_FAST, 129 + .n_voltages = AS3722_SD2_VSEL_MAX, 130 + }, 131 + { 132 + .regulator_id = AS3722_REGULATOR_ID_SD3, 133 + .name = "as3722-sd3", 134 + .sname = "vsup-sd3", 135 + .vsel_reg = AS3722_SD3_VOLTAGE_REG, 136 + .vsel_mask = AS3722_SD_VSEL_MASK, 137 + .enable_reg = AS3722_SD_CONTROL_REG, 138 + .enable_mask = AS3722_SDn_CTRL(3), 139 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, 140 + .sleep_ctrl_mask = AS3722_SD3_EXT_ENABLE_MASK, 141 + .control_reg = AS3722_SD23_CONTROL_REG, 142 + .mode_mask = AS3722_SD3_MODE_FAST, 143 + .n_voltages = AS3722_SD2_VSEL_MAX, 144 + }, 145 + { 146 + .regulator_id = AS3722_REGULATOR_ID_SD4, 147 + .name = "as3722-sd4", 148 + .sname = "vsup-sd4", 149 + .vsel_reg = AS3722_SD4_VOLTAGE_REG, 150 + .vsel_mask = AS3722_SD_VSEL_MASK, 151 + .enable_reg = AS3722_SD_CONTROL_REG, 152 + .enable_mask = AS3722_SDn_CTRL(4), 153 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, 154 + .sleep_ctrl_mask = AS3722_SD4_EXT_ENABLE_MASK, 155 + .control_reg = AS3722_SD4_CONTROL_REG, 156 + .mode_mask = AS3722_SD4_MODE_FAST, 157 + .n_voltages = AS3722_SD2_VSEL_MAX, 158 + }, 159 + { 160 + .regulator_id = AS3722_REGULATOR_ID_SD5, 161 + .name = "as3722-sd5", 162 + .sname = "vsup-sd5", 163 + .vsel_reg = AS3722_SD5_VOLTAGE_REG, 164 + .vsel_mask = AS3722_SD_VSEL_MASK, 165 + .enable_reg = AS3722_SD_CONTROL_REG, 166 + .enable_mask = AS3722_SDn_CTRL(5), 167 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, 168 + .sleep_ctrl_mask = AS3722_SD5_EXT_ENABLE_MASK, 169 + .control_reg = AS3722_SD5_CONTROL_REG, 170 + .mode_mask = AS3722_SD5_MODE_FAST, 171 + .n_voltages = AS3722_SD2_VSEL_MAX, 172 + }, 173 + { 174 + .regulator_id = AS3722_REGULATOR_ID_SD6, 175 + .name = "as3722-sd6", 176 + .vsel_reg = AS3722_SD6_VOLTAGE_REG, 177 + .vsel_mask = AS3722_SD_VSEL_MASK, 178 + .enable_reg = AS3722_SD_CONTROL_REG, 179 + .enable_mask = AS3722_SDn_CTRL(6), 180 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, 181 + .sleep_ctrl_mask = AS3722_SD6_EXT_ENABLE_MASK, 182 + .control_reg = AS3722_SD6_CONTROL_REG, 183 + .mode_mask = AS3722_SD6_MODE_FAST, 184 + .n_voltages = AS3722_SD0_VSEL_MAX, 185 + }, 186 + { 187 + .regulator_id = AS3722_REGULATOR_ID_LDO0, 188 + .name = "as3722-ldo0", 189 + .sname = "vin-ldo0", 190 + .vsel_reg = AS3722_LDO0_VOLTAGE_REG, 191 + .vsel_mask = AS3722_LDO0_VSEL_MASK, 192 + .enable_reg = AS3722_LDOCONTROL0_REG, 193 + .enable_mask = AS3722_LDO0_CTRL, 194 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, 195 + .sleep_ctrl_mask = AS3722_LDO0_EXT_ENABLE_MASK, 196 + .n_voltages = AS3722_LDO0_NUM_VOLT, 197 + }, 198 + { 199 + .regulator_id = AS3722_REGULATOR_ID_LDO1, 200 + .name = "as3722-ldo1", 201 + .sname = "vin-ldo1-6", 202 + .vsel_reg = AS3722_LDO1_VOLTAGE_REG, 203 + .vsel_mask = AS3722_LDO_VSEL_MASK, 204 + .enable_reg = AS3722_LDOCONTROL0_REG, 205 + .enable_mask = AS3722_LDO1_CTRL, 206 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, 207 + .sleep_ctrl_mask = AS3722_LDO1_EXT_ENABLE_MASK, 208 + .n_voltages = AS3722_LDO_NUM_VOLT, 209 + }, 210 + { 211 + .regulator_id = AS3722_REGULATOR_ID_LDO2, 212 + .name = "as3722-ldo2", 213 + .sname = "vin-ldo2-5-7", 214 + .vsel_reg = AS3722_LDO2_VOLTAGE_REG, 215 + .vsel_mask = AS3722_LDO_VSEL_MASK, 216 + .enable_reg = AS3722_LDOCONTROL0_REG, 217 + .enable_mask = AS3722_LDO2_CTRL, 218 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, 219 + .sleep_ctrl_mask = AS3722_LDO2_EXT_ENABLE_MASK, 220 + .n_voltages = AS3722_LDO_NUM_VOLT, 221 + }, 222 + { 223 + .regulator_id = AS3722_REGULATOR_ID_LDO3, 224 + .name = "as3722-ldo3", 225 + .name = "vin-ldo3-4", 226 + .vsel_reg = AS3722_LDO3_VOLTAGE_REG, 227 + .vsel_mask = AS3722_LDO3_VSEL_MASK, 228 + .enable_reg = AS3722_LDOCONTROL0_REG, 229 + .enable_mask = AS3722_LDO3_CTRL, 230 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, 231 + .sleep_ctrl_mask = AS3722_LDO3_EXT_ENABLE_MASK, 232 + .n_voltages = AS3722_LDO3_NUM_VOLT, 233 + }, 234 + { 235 + .regulator_id = AS3722_REGULATOR_ID_LDO4, 236 + .name = "as3722-ldo4", 237 + .name = "vin-ldo3-4", 238 + .vsel_reg = AS3722_LDO4_VOLTAGE_REG, 239 + .vsel_mask = AS3722_LDO_VSEL_MASK, 240 + .enable_reg = AS3722_LDOCONTROL0_REG, 241 + .enable_mask = AS3722_LDO4_CTRL, 242 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, 243 + .sleep_ctrl_mask = AS3722_LDO4_EXT_ENABLE_MASK, 244 + .n_voltages = AS3722_LDO_NUM_VOLT, 245 + }, 246 + { 247 + .regulator_id = AS3722_REGULATOR_ID_LDO5, 248 + .name = "as3722-ldo5", 249 + .sname = "vin-ldo2-5-7", 250 + .vsel_reg = AS3722_LDO5_VOLTAGE_REG, 251 + .vsel_mask = AS3722_LDO_VSEL_MASK, 252 + .enable_reg = AS3722_LDOCONTROL0_REG, 253 + .enable_mask = AS3722_LDO5_CTRL, 254 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, 255 + .sleep_ctrl_mask = AS3722_LDO5_EXT_ENABLE_MASK, 256 + .n_voltages = AS3722_LDO_NUM_VOLT, 257 + }, 258 + { 259 + .regulator_id = AS3722_REGULATOR_ID_LDO6, 260 + .name = "as3722-ldo6", 261 + .sname = "vin-ldo1-6", 262 + .vsel_reg = AS3722_LDO6_VOLTAGE_REG, 263 + .vsel_mask = AS3722_LDO_VSEL_MASK, 264 + .enable_reg = AS3722_LDOCONTROL0_REG, 265 + .enable_mask = AS3722_LDO6_CTRL, 266 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, 267 + .sleep_ctrl_mask = AS3722_LDO6_EXT_ENABLE_MASK, 268 + .n_voltages = AS3722_LDO_NUM_VOLT, 269 + }, 270 + { 271 + .regulator_id = AS3722_REGULATOR_ID_LDO7, 272 + .name = "as3722-ldo7", 273 + .sname = "vin-ldo2-5-7", 274 + .vsel_reg = AS3722_LDO7_VOLTAGE_REG, 275 + .vsel_mask = AS3722_LDO_VSEL_MASK, 276 + .enable_reg = AS3722_LDOCONTROL0_REG, 277 + .enable_mask = AS3722_LDO7_CTRL, 278 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, 279 + .sleep_ctrl_mask = AS3722_LDO7_EXT_ENABLE_MASK, 280 + .n_voltages = AS3722_LDO_NUM_VOLT, 281 + }, 282 + { 283 + .regulator_id = AS3722_REGULATOR_ID_LDO9, 284 + .name = "as3722-ldo9", 285 + .sname = "vin-ldo9-10", 286 + .vsel_reg = AS3722_LDO9_VOLTAGE_REG, 287 + .vsel_mask = AS3722_LDO_VSEL_MASK, 288 + .enable_reg = AS3722_LDOCONTROL1_REG, 289 + .enable_mask = AS3722_LDO9_CTRL, 290 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, 291 + .sleep_ctrl_mask = AS3722_LDO9_EXT_ENABLE_MASK, 292 + .n_voltages = AS3722_LDO_NUM_VOLT, 293 + }, 294 + { 295 + .regulator_id = AS3722_REGULATOR_ID_LDO10, 296 + .name = "as3722-ldo10", 297 + .sname = "vin-ldo9-10", 298 + .vsel_reg = AS3722_LDO10_VOLTAGE_REG, 299 + .vsel_mask = AS3722_LDO_VSEL_MASK, 300 + .enable_reg = AS3722_LDOCONTROL1_REG, 301 + .enable_mask = AS3722_LDO10_CTRL, 302 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, 303 + .sleep_ctrl_mask = AS3722_LDO10_EXT_ENABLE_MASK, 304 + .n_voltages = AS3722_LDO_NUM_VOLT, 305 + }, 306 + { 307 + .regulator_id = AS3722_REGULATOR_ID_LDO11, 308 + .name = "as3722-ldo11", 309 + .sname = "vin-ldo11", 310 + .vsel_reg = AS3722_LDO11_VOLTAGE_REG, 311 + .vsel_mask = AS3722_LDO_VSEL_MASK, 312 + .enable_reg = AS3722_LDOCONTROL1_REG, 313 + .enable_mask = AS3722_LDO11_CTRL, 314 + .sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, 315 + .sleep_ctrl_mask = AS3722_LDO11_EXT_ENABLE_MASK, 316 + .n_voltages = AS3722_LDO_NUM_VOLT, 317 + }, 318 + }; 319 + 320 + 321 + static const int as3722_ldo_current[] = { 150000, 300000 }; 322 + static const int as3722_sd016_current[] = { 2500000, 3000000, 3500000 }; 323 + 324 + static int as3722_current_to_index(int min_uA, int max_uA, 325 + const int *curr_table, int n_currents) 326 + { 327 + int i; 328 + 329 + for (i = n_currents - 1; i >= 0; i--) { 330 + if ((min_uA <= curr_table[i]) && (curr_table[i] <= max_uA)) 331 + return i; 332 + } 333 + return -EINVAL; 334 + } 335 + 336 + static int as3722_ldo_get_current_limit(struct regulator_dev *rdev) 337 + { 338 + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); 339 + struct as3722 *as3722 = as3722_regs->as3722; 340 + int id = rdev_get_id(rdev); 341 + u32 val; 342 + int ret; 343 + 344 + ret = as3722_read(as3722, as3722_reg_lookup[id].vsel_reg, &val); 345 + if (ret < 0) { 346 + dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", 347 + as3722_reg_lookup[id].vsel_reg, ret); 348 + return ret; 349 + } 350 + if (val & AS3722_LDO_ILIMIT_MASK) 351 + return 300000; 352 + return 150000; 353 + } 354 + 355 + static int as3722_ldo_set_current_limit(struct regulator_dev *rdev, 356 + int min_uA, int max_uA) 357 + { 358 + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); 359 + struct as3722 *as3722 = as3722_regs->as3722; 360 + int id = rdev_get_id(rdev); 361 + int ret; 362 + u32 reg = 0; 363 + 364 + ret = as3722_current_to_index(min_uA, max_uA, as3722_ldo_current, 365 + ARRAY_SIZE(as3722_ldo_current)); 366 + if (ret < 0) { 367 + dev_err(as3722_regs->dev, 368 + "Current range min:max = %d:%d does not support\n", 369 + min_uA, max_uA); 370 + return ret; 371 + } 372 + if (ret) 373 + reg = AS3722_LDO_ILIMIT_BIT; 374 + return as3722_update_bits(as3722, as3722_reg_lookup[id].vsel_reg, 375 + AS3722_LDO_ILIMIT_MASK, reg); 376 + } 377 + 378 + static struct regulator_ops as3722_ldo0_ops = { 379 + .is_enabled = regulator_is_enabled_regmap, 380 + .enable = regulator_enable_regmap, 381 + .disable = regulator_disable_regmap, 382 + .list_voltage = regulator_list_voltage_linear, 383 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 384 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 385 + .get_current_limit = as3722_ldo_get_current_limit, 386 + .set_current_limit = as3722_ldo_set_current_limit, 387 + }; 388 + 389 + static struct regulator_ops as3722_ldo0_extcntrl_ops = { 390 + .list_voltage = regulator_list_voltage_linear, 391 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 392 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 393 + .get_current_limit = as3722_ldo_get_current_limit, 394 + .set_current_limit = as3722_ldo_set_current_limit, 395 + }; 396 + 397 + static int as3722_ldo3_set_tracking_mode(struct as3722_regulators *as3722_reg, 398 + int id, u8 mode) 399 + { 400 + struct as3722 *as3722 = as3722_reg->as3722; 401 + 402 + switch (mode) { 403 + case AS3722_LDO3_MODE_PMOS: 404 + case AS3722_LDO3_MODE_PMOS_TRACKING: 405 + case AS3722_LDO3_MODE_NMOS: 406 + case AS3722_LDO3_MODE_SWITCH: 407 + return as3722_update_bits(as3722, 408 + as3722_reg_lookup[id].vsel_reg, 409 + AS3722_LDO3_MODE_MASK, mode); 410 + 411 + default: 412 + return -EINVAL; 413 + } 414 + } 415 + 416 + static int as3722_ldo3_get_current_limit(struct regulator_dev *rdev) 417 + { 418 + return 150000; 419 + } 420 + 421 + static struct regulator_ops as3722_ldo3_ops = { 422 + .is_enabled = regulator_is_enabled_regmap, 423 + .enable = regulator_enable_regmap, 424 + .disable = regulator_disable_regmap, 425 + .list_voltage = regulator_list_voltage_linear, 426 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 427 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 428 + .get_current_limit = as3722_ldo3_get_current_limit, 429 + }; 430 + 431 + static struct regulator_ops as3722_ldo3_extcntrl_ops = { 432 + .list_voltage = regulator_list_voltage_linear, 433 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 434 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 435 + .get_current_limit = as3722_ldo3_get_current_limit, 436 + }; 437 + 438 + #define regulator_lin_range(_min_sel, _max_sel, _min_uV, _step_uV) \ 439 + { \ 440 + .min_sel = _min_sel, \ 441 + .max_sel = _max_sel, \ 442 + .uV_step = _step_uV, \ 443 + .min_uV = _min_uV, \ 444 + .max_uV = _min_uV + (_max_sel - _min_sel + 1) * _step_uV, \ 445 + } 446 + 447 + static const struct regulator_linear_range as3722_ldo_ranges[] = { 448 + regulator_lin_range(0x01, 0x24, 800000, 25000), 449 + regulator_lin_range(0x40, 0x7F, 1725000, 25000), 450 + }; 451 + 452 + static struct regulator_ops as3722_ldo_ops = { 453 + .is_enabled = regulator_is_enabled_regmap, 454 + .enable = regulator_enable_regmap, 455 + .disable = regulator_disable_regmap, 456 + .map_voltage = regulator_map_voltage_linear_range, 457 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 458 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 459 + .list_voltage = regulator_list_voltage_linear_range, 460 + .get_current_limit = as3722_ldo_get_current_limit, 461 + .set_current_limit = as3722_ldo_set_current_limit, 462 + }; 463 + 464 + static struct regulator_ops as3722_ldo_extcntrl_ops = { 465 + .map_voltage = regulator_map_voltage_linear_range, 466 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 467 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 468 + .list_voltage = regulator_list_voltage_linear_range, 469 + .get_current_limit = as3722_ldo_get_current_limit, 470 + .set_current_limit = as3722_ldo_set_current_limit, 471 + }; 472 + 473 + static unsigned int as3722_sd_get_mode(struct regulator_dev *rdev) 474 + { 475 + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); 476 + struct as3722 *as3722 = as3722_regs->as3722; 477 + int id = rdev_get_id(rdev); 478 + u32 val; 479 + int ret; 480 + 481 + if (!as3722_reg_lookup[id].control_reg) 482 + return -ENOTSUPP; 483 + 484 + ret = as3722_read(as3722, as3722_reg_lookup[id].control_reg, &val); 485 + if (ret < 0) { 486 + dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", 487 + as3722_reg_lookup[id].control_reg, ret); 488 + return ret; 489 + } 490 + 491 + if (val & as3722_reg_lookup[id].mode_mask) 492 + return REGULATOR_MODE_FAST; 493 + else 494 + return REGULATOR_MODE_NORMAL; 495 + } 496 + 497 + static int as3722_sd_set_mode(struct regulator_dev *rdev, 498 + unsigned int mode) 499 + { 500 + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); 501 + struct as3722 *as3722 = as3722_regs->as3722; 502 + u8 id = rdev_get_id(rdev); 503 + u8 val = 0; 504 + int ret; 505 + 506 + if (!as3722_reg_lookup[id].control_reg) 507 + return -ERANGE; 508 + 509 + switch (mode) { 510 + case REGULATOR_MODE_FAST: 511 + val = as3722_reg_lookup[id].mode_mask; 512 + case REGULATOR_MODE_NORMAL: /* fall down */ 513 + break; 514 + default: 515 + return -EINVAL; 516 + } 517 + 518 + ret = as3722_update_bits(as3722, as3722_reg_lookup[id].control_reg, 519 + as3722_reg_lookup[id].mode_mask, val); 520 + if (ret < 0) { 521 + dev_err(as3722_regs->dev, "Reg 0x%02x update failed: %d\n", 522 + as3722_reg_lookup[id].control_reg, ret); 523 + return ret; 524 + } 525 + return ret; 526 + } 527 + 528 + static int as3722_sd016_get_current_limit(struct regulator_dev *rdev) 529 + { 530 + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); 531 + struct as3722 *as3722 = as3722_regs->as3722; 532 + int id = rdev_get_id(rdev); 533 + u32 val, reg; 534 + int mask; 535 + int ret; 536 + 537 + switch (id) { 538 + case AS3722_REGULATOR_ID_SD0: 539 + reg = AS3722_OVCURRENT_REG; 540 + mask = AS3722_OVCURRENT_SD0_TRIP_MASK; 541 + break; 542 + case AS3722_REGULATOR_ID_SD1: 543 + reg = AS3722_OVCURRENT_REG; 544 + mask = AS3722_OVCURRENT_SD1_TRIP_MASK; 545 + break; 546 + case AS3722_REGULATOR_ID_SD6: 547 + reg = AS3722_OVCURRENT_DEB_REG; 548 + mask = AS3722_OVCURRENT_SD6_TRIP_MASK; 549 + break; 550 + default: 551 + return -EINVAL; 552 + } 553 + ret = as3722_read(as3722, reg, &val); 554 + if (ret < 0) { 555 + dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", 556 + reg, ret); 557 + return ret; 558 + } 559 + val &= mask; 560 + val >>= ffs(mask) - 1; 561 + if (val == 3) 562 + return -EINVAL; 563 + return as3722_sd016_current[val]; 564 + } 565 + 566 + static int as3722_sd016_set_current_limit(struct regulator_dev *rdev, 567 + int min_uA, int max_uA) 568 + { 569 + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); 570 + struct as3722 *as3722 = as3722_regs->as3722; 571 + int id = rdev_get_id(rdev); 572 + int ret; 573 + int val; 574 + int mask; 575 + u32 reg; 576 + 577 + ret = as3722_current_to_index(min_uA, max_uA, as3722_sd016_current, 578 + ARRAY_SIZE(as3722_sd016_current)); 579 + if (ret < 0) { 580 + dev_err(as3722_regs->dev, 581 + "Current range min:max = %d:%d does not support\n", 582 + min_uA, max_uA); 583 + return ret; 584 + } 585 + 586 + switch (id) { 587 + case AS3722_REGULATOR_ID_SD0: 588 + reg = AS3722_OVCURRENT_REG; 589 + mask = AS3722_OVCURRENT_SD0_TRIP_MASK; 590 + break; 591 + case AS3722_REGULATOR_ID_SD1: 592 + reg = AS3722_OVCURRENT_REG; 593 + mask = AS3722_OVCURRENT_SD1_TRIP_MASK; 594 + break; 595 + case AS3722_REGULATOR_ID_SD6: 596 + reg = AS3722_OVCURRENT_DEB_REG; 597 + mask = AS3722_OVCURRENT_SD6_TRIP_MASK; 598 + break; 599 + default: 600 + return -EINVAL; 601 + } 602 + val = ret & mask; 603 + val <<= ffs(mask) - 1; 604 + return as3722_update_bits(as3722, reg, mask, val); 605 + } 606 + 607 + static const struct regulator_linear_range as3722_sd2345_ranges[] = { 608 + regulator_lin_range(0x01, 0x40, 600000, 12500), 609 + regulator_lin_range(0x41, 0x70, 1400000, 25000), 610 + regulator_lin_range(0x71, 0x7F, 1725000, 50000), 611 + }; 612 + 613 + static struct regulator_ops as3722_sd016_ops = { 614 + .is_enabled = regulator_is_enabled_regmap, 615 + .enable = regulator_enable_regmap, 616 + .disable = regulator_disable_regmap, 617 + .list_voltage = regulator_list_voltage_linear, 618 + .map_voltage = regulator_map_voltage_linear, 619 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 620 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 621 + .get_current_limit = as3722_sd016_get_current_limit, 622 + .set_current_limit = as3722_sd016_set_current_limit, 623 + .get_mode = as3722_sd_get_mode, 624 + .set_mode = as3722_sd_set_mode, 625 + }; 626 + 627 + static struct regulator_ops as3722_sd016_extcntrl_ops = { 628 + .list_voltage = regulator_list_voltage_linear, 629 + .map_voltage = regulator_map_voltage_linear, 630 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 631 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 632 + .get_current_limit = as3722_sd016_get_current_limit, 633 + .set_current_limit = as3722_sd016_set_current_limit, 634 + .get_mode = as3722_sd_get_mode, 635 + .set_mode = as3722_sd_set_mode, 636 + }; 637 + 638 + static struct regulator_ops as3722_sd2345_ops = { 639 + .is_enabled = regulator_is_enabled_regmap, 640 + .enable = regulator_enable_regmap, 641 + .disable = regulator_disable_regmap, 642 + .list_voltage = regulator_list_voltage_linear_range, 643 + .map_voltage = regulator_map_voltage_linear_range, 644 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 645 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 646 + .get_mode = as3722_sd_get_mode, 647 + .set_mode = as3722_sd_set_mode, 648 + }; 649 + 650 + static struct regulator_ops as3722_sd2345_extcntrl_ops = { 651 + .list_voltage = regulator_list_voltage_linear_range, 652 + .map_voltage = regulator_map_voltage_linear_range, 653 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 654 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 655 + .get_mode = as3722_sd_get_mode, 656 + .set_mode = as3722_sd_set_mode, 657 + }; 658 + 659 + static int as3722_extreg_init(struct as3722_regulators *as3722_regs, int id, 660 + int ext_pwr_ctrl) 661 + { 662 + int ret; 663 + unsigned int val; 664 + 665 + if ((ext_pwr_ctrl < AS3722_EXT_CONTROL_ENABLE1) || 666 + (ext_pwr_ctrl > AS3722_EXT_CONTROL_ENABLE3)) 667 + return -EINVAL; 668 + 669 + val = ext_pwr_ctrl << (ffs(as3722_reg_lookup[id].sleep_ctrl_mask) - 1); 670 + ret = as3722_update_bits(as3722_regs->as3722, 671 + as3722_reg_lookup[id].sleep_ctrl_reg, 672 + as3722_reg_lookup[id].sleep_ctrl_mask, val); 673 + if (ret < 0) 674 + dev_err(as3722_regs->dev, "Reg 0x%02x update failed: %d\n", 675 + as3722_reg_lookup[id].sleep_ctrl_reg, ret); 676 + return ret; 677 + } 678 + 679 + static struct of_regulator_match as3722_regulator_matches[] = { 680 + { .name = "sd0", }, 681 + { .name = "sd1", }, 682 + { .name = "sd2", }, 683 + { .name = "sd3", }, 684 + { .name = "sd4", }, 685 + { .name = "sd5", }, 686 + { .name = "sd6", }, 687 + { .name = "ldo0", }, 688 + { .name = "ldo1", }, 689 + { .name = "ldo2", }, 690 + { .name = "ldo3", }, 691 + { .name = "ldo4", }, 692 + { .name = "ldo5", }, 693 + { .name = "ldo6", }, 694 + { .name = "ldo7", }, 695 + { .name = "ldo9", }, 696 + { .name = "ldo10", }, 697 + { .name = "ldo11", }, 698 + }; 699 + 700 + static int as3722_get_regulator_dt_data(struct platform_device *pdev, 701 + struct as3722_regulators *as3722_regs) 702 + { 703 + struct device_node *np; 704 + struct as3722_regulator_config_data *reg_config; 705 + u32 prop; 706 + int id; 707 + int ret; 708 + 709 + np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); 710 + if (!np) { 711 + dev_err(&pdev->dev, "Device is not having regulators node\n"); 712 + return -ENODEV; 713 + } 714 + pdev->dev.of_node = np; 715 + 716 + ret = of_regulator_match(&pdev->dev, np, as3722_regulator_matches, 717 + ARRAY_SIZE(as3722_regulator_matches)); 718 + if (ret < 0) { 719 + dev_err(&pdev->dev, "Parsing of regulator node failed: %d\n", 720 + ret); 721 + return ret; 722 + } 723 + 724 + for (id = 0; id < ARRAY_SIZE(as3722_regulator_matches); ++id) { 725 + struct device_node *reg_node; 726 + 727 + reg_config = &as3722_regs->reg_config_data[id]; 728 + reg_config->reg_init = as3722_regulator_matches[id].init_data; 729 + reg_node = as3722_regulator_matches[id].of_node; 730 + 731 + if (!reg_config->reg_init || !reg_node) 732 + continue; 733 + 734 + ret = of_property_read_u32(reg_node, "ams,ext-control", &prop); 735 + if (!ret) { 736 + if (prop < 3) 737 + reg_config->ext_control = prop; 738 + else 739 + dev_warn(&pdev->dev, 740 + "ext-control have invalid option: %u\n", 741 + prop); 742 + } 743 + reg_config->enable_tracking = 744 + of_property_read_bool(reg_node, "ams,enable-tracking"); 745 + } 746 + return 0; 747 + } 748 + 749 + static int as3722_regulator_probe(struct platform_device *pdev) 750 + { 751 + struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent); 752 + struct as3722_regulators *as3722_regs; 753 + struct as3722_regulator_config_data *reg_config; 754 + struct regulator_dev *rdev; 755 + struct regulator_config config = { }; 756 + struct regulator_ops *ops; 757 + int id; 758 + int ret; 759 + 760 + as3722_regs = devm_kzalloc(&pdev->dev, sizeof(*as3722_regs), 761 + GFP_KERNEL); 762 + if (!as3722_regs) 763 + return -ENOMEM; 764 + 765 + as3722_regs->dev = &pdev->dev; 766 + as3722_regs->as3722 = as3722; 767 + platform_set_drvdata(pdev, as3722_regs); 768 + 769 + ret = as3722_get_regulator_dt_data(pdev, as3722_regs); 770 + if (ret < 0) 771 + return ret; 772 + 773 + config.dev = &pdev->dev; 774 + config.driver_data = as3722_regs; 775 + config.regmap = as3722->regmap; 776 + 777 + for (id = 0; id < AS3722_REGULATOR_ID_MAX; id++) { 778 + reg_config = &as3722_regs->reg_config_data[id]; 779 + 780 + as3722_regs->desc[id].name = as3722_reg_lookup[id].name; 781 + as3722_regs->desc[id].supply_name = as3722_reg_lookup[id].sname; 782 + as3722_regs->desc[id].id = as3722_reg_lookup[id].regulator_id; 783 + as3722_regs->desc[id].n_voltages = 784 + as3722_reg_lookup[id].n_voltages; 785 + as3722_regs->desc[id].type = REGULATOR_VOLTAGE; 786 + as3722_regs->desc[id].owner = THIS_MODULE; 787 + as3722_regs->desc[id].enable_reg = 788 + as3722_reg_lookup[id].enable_reg; 789 + as3722_regs->desc[id].enable_mask = 790 + as3722_reg_lookup[id].enable_mask; 791 + as3722_regs->desc[id].vsel_reg = as3722_reg_lookup[id].vsel_reg; 792 + as3722_regs->desc[id].vsel_mask = 793 + as3722_reg_lookup[id].vsel_mask; 794 + switch (id) { 795 + case AS3722_REGULATOR_ID_LDO0: 796 + if (reg_config->ext_control) 797 + ops = &as3722_ldo0_extcntrl_ops; 798 + else 799 + ops = &as3722_ldo0_ops; 800 + as3722_regs->desc[id].min_uV = 825000; 801 + as3722_regs->desc[id].uV_step = 25000; 802 + as3722_regs->desc[id].linear_min_sel = 1; 803 + as3722_regs->desc[id].enable_time = 500; 804 + break; 805 + case AS3722_REGULATOR_ID_LDO3: 806 + if (reg_config->ext_control) 807 + ops = &as3722_ldo3_extcntrl_ops; 808 + else 809 + ops = &as3722_ldo3_ops; 810 + as3722_regs->desc[id].min_uV = 620000; 811 + as3722_regs->desc[id].uV_step = 20000; 812 + as3722_regs->desc[id].linear_min_sel = 1; 813 + as3722_regs->desc[id].enable_time = 500; 814 + if (reg_config->enable_tracking) { 815 + ret = as3722_ldo3_set_tracking_mode(as3722_regs, 816 + id, AS3722_LDO3_MODE_PMOS_TRACKING); 817 + if (ret < 0) { 818 + dev_err(&pdev->dev, 819 + "LDO3 tracking failed: %d\n", 820 + ret); 821 + return ret; 822 + } 823 + } 824 + break; 825 + case AS3722_REGULATOR_ID_SD0: 826 + case AS3722_REGULATOR_ID_SD1: 827 + case AS3722_REGULATOR_ID_SD6: 828 + if (reg_config->ext_control) 829 + ops = &as3722_sd016_extcntrl_ops; 830 + else 831 + ops = &as3722_sd016_ops; 832 + as3722_regs->desc[id].min_uV = 610000; 833 + as3722_regs->desc[id].uV_step = 10000; 834 + as3722_regs->desc[id].linear_min_sel = 1; 835 + break; 836 + case AS3722_REGULATOR_ID_SD2: 837 + case AS3722_REGULATOR_ID_SD3: 838 + case AS3722_REGULATOR_ID_SD4: 839 + case AS3722_REGULATOR_ID_SD5: 840 + if (reg_config->ext_control) 841 + ops = &as3722_sd2345_extcntrl_ops; 842 + else 843 + ops = &as3722_sd2345_ops; 844 + as3722_regs->desc[id].linear_ranges = 845 + as3722_sd2345_ranges; 846 + as3722_regs->desc[id].n_linear_ranges = 847 + ARRAY_SIZE(as3722_sd2345_ranges); 848 + break; 849 + default: 850 + if (reg_config->ext_control) 851 + ops = &as3722_ldo_extcntrl_ops; 852 + else 853 + ops = &as3722_ldo_ops; 854 + as3722_regs->desc[id].min_uV = 825000; 855 + as3722_regs->desc[id].uV_step = 25000; 856 + as3722_regs->desc[id].linear_min_sel = 1; 857 + as3722_regs->desc[id].enable_time = 500; 858 + as3722_regs->desc[id].linear_ranges = as3722_ldo_ranges; 859 + as3722_regs->desc[id].n_linear_ranges = 860 + ARRAY_SIZE(as3722_ldo_ranges); 861 + break; 862 + } 863 + as3722_regs->desc[id].ops = ops; 864 + config.init_data = reg_config->reg_init; 865 + config.of_node = as3722_regulator_matches[id].of_node; 866 + rdev = devm_regulator_register(&pdev->dev, 867 + &as3722_regs->desc[id], &config); 868 + if (IS_ERR(rdev)) { 869 + ret = PTR_ERR(rdev); 870 + dev_err(&pdev->dev, "regulator %d register failed %d\n", 871 + id, ret); 872 + return ret; 873 + } 874 + 875 + as3722_regs->rdevs[id] = rdev; 876 + if (reg_config->ext_control) { 877 + ret = regulator_enable_regmap(rdev); 878 + if (ret < 0) { 879 + dev_err(&pdev->dev, 880 + "Regulator %d enable failed: %d\n", 881 + id, ret); 882 + return ret; 883 + } 884 + ret = as3722_extreg_init(as3722_regs, id, 885 + reg_config->ext_control); 886 + if (ret < 0) { 887 + dev_err(&pdev->dev, 888 + "AS3722 ext control failed: %d", ret); 889 + return ret; 890 + } 891 + } 892 + } 893 + return 0; 894 + } 895 + 896 + static const struct of_device_id of_as3722_regulator_match[] = { 897 + { .compatible = "ams,as3722-regulator", }, 898 + {}, 899 + }; 900 + MODULE_DEVICE_TABLE(of, of_as3722_regulator_match); 901 + 902 + static struct platform_driver as3722_regulator_driver = { 903 + .driver = { 904 + .name = "as3722-regulator", 905 + .owner = THIS_MODULE, 906 + .of_match_table = of_as3722_regulator_match, 907 + }, 908 + .probe = as3722_regulator_probe, 909 + }; 910 + 911 + module_platform_driver(as3722_regulator_driver); 912 + 913 + MODULE_ALIAS("platform:as3722-regulator"); 914 + MODULE_DESCRIPTION("AS3722 regulator driver"); 915 + MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>"); 916 + MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 917 + MODULE_LICENSE("GPL");