1994aae32SKeerthy /* 2994aae32SKeerthy * Regulator driver for LP873X PMIC 3994aae32SKeerthy * 4994aae32SKeerthy * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ 5994aae32SKeerthy * 6994aae32SKeerthy * This program is free software; you can redistribute it and/or 7994aae32SKeerthy * modify it under the terms of the GNU General Public License version 2 as 8994aae32SKeerthy * published by the Free Software Foundation. 9994aae32SKeerthy * 10994aae32SKeerthy * This program is distributed "as is" WITHOUT ANY WARRANTY of any 11994aae32SKeerthy * kind, whether expressed or implied; without even the implied warranty 12994aae32SKeerthy * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13994aae32SKeerthy * GNU General Public License version 2 for more details. 14994aae32SKeerthy */ 15994aae32SKeerthy 16994aae32SKeerthy #include <linux/module.h> 17994aae32SKeerthy #include <linux/platform_device.h> 18994aae32SKeerthy #include <linux/regmap.h> 19994aae32SKeerthy 20994aae32SKeerthy #include <linux/mfd/lp873x.h> 21994aae32SKeerthy 22994aae32SKeerthy #define LP873X_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, _er, _em, \ 234335f653SAxel Lin _delay, _lr, _cr) \ 24994aae32SKeerthy [_id] = { \ 25994aae32SKeerthy .desc = { \ 26994aae32SKeerthy .name = _name, \ 27205321f0SLokesh Vutla .supply_name = _of "-in", \ 28994aae32SKeerthy .id = _id, \ 29994aae32SKeerthy .of_match = of_match_ptr(_of), \ 30994aae32SKeerthy .regulators_node = of_match_ptr("regulators"),\ 31994aae32SKeerthy .ops = &_ops, \ 32994aae32SKeerthy .n_voltages = _n, \ 33994aae32SKeerthy .type = REGULATOR_VOLTAGE, \ 34994aae32SKeerthy .owner = THIS_MODULE, \ 35994aae32SKeerthy .vsel_reg = _vr, \ 36994aae32SKeerthy .vsel_mask = _vm, \ 37994aae32SKeerthy .enable_reg = _er, \ 38994aae32SKeerthy .enable_mask = _em, \ 39994aae32SKeerthy .ramp_delay = _delay, \ 40994aae32SKeerthy .linear_ranges = _lr, \ 414335f653SAxel Lin .n_linear_ranges = ARRAY_SIZE(_lr), \ 42994aae32SKeerthy }, \ 43994aae32SKeerthy .ctrl2_reg = _cr, \ 44994aae32SKeerthy } 45994aae32SKeerthy 46994aae32SKeerthy struct lp873x_regulator { 47994aae32SKeerthy struct regulator_desc desc; 48994aae32SKeerthy unsigned int ctrl2_reg; 49994aae32SKeerthy }; 50994aae32SKeerthy 51994aae32SKeerthy static const struct lp873x_regulator regulators[]; 52994aae32SKeerthy 53994aae32SKeerthy static const struct regulator_linear_range buck0_buck1_ranges[] = { 54994aae32SKeerthy REGULATOR_LINEAR_RANGE(0, 0x0, 0x13, 0), 55994aae32SKeerthy REGULATOR_LINEAR_RANGE(700000, 0x14, 0x17, 10000), 56994aae32SKeerthy REGULATOR_LINEAR_RANGE(735000, 0x18, 0x9d, 5000), 57994aae32SKeerthy REGULATOR_LINEAR_RANGE(1420000, 0x9e, 0xff, 20000), 58994aae32SKeerthy }; 59994aae32SKeerthy 60994aae32SKeerthy static const struct regulator_linear_range ldo0_ldo1_ranges[] = { 61994aae32SKeerthy REGULATOR_LINEAR_RANGE(800000, 0x0, 0x19, 100000), 62994aae32SKeerthy }; 63994aae32SKeerthy 64994aae32SKeerthy static unsigned int lp873x_buck_ramp_delay[] = { 65994aae32SKeerthy 30000, 15000, 10000, 7500, 3800, 1900, 940, 470 66994aae32SKeerthy }; 67994aae32SKeerthy 68994aae32SKeerthy /* LP873X BUCK current limit */ 69994aae32SKeerthy static const unsigned int lp873x_buck_uA[] = { 70994aae32SKeerthy 1500000, 2000000, 2500000, 3000000, 3500000, 4000000, 71994aae32SKeerthy }; 72994aae32SKeerthy 73994aae32SKeerthy static int lp873x_buck_set_ramp_delay(struct regulator_dev *rdev, 74994aae32SKeerthy int ramp_delay) 75994aae32SKeerthy { 76994aae32SKeerthy int id = rdev_get_id(rdev); 77994aae32SKeerthy struct lp873x *lp873 = rdev_get_drvdata(rdev); 78994aae32SKeerthy unsigned int reg; 79994aae32SKeerthy int ret; 80994aae32SKeerthy 81994aae32SKeerthy if (ramp_delay <= 470) 82994aae32SKeerthy reg = 7; 83994aae32SKeerthy else if (ramp_delay <= 940) 84994aae32SKeerthy reg = 6; 85994aae32SKeerthy else if (ramp_delay <= 1900) 86994aae32SKeerthy reg = 5; 87994aae32SKeerthy else if (ramp_delay <= 3800) 88994aae32SKeerthy reg = 4; 89994aae32SKeerthy else if (ramp_delay <= 7500) 90994aae32SKeerthy reg = 3; 91994aae32SKeerthy else if (ramp_delay <= 10000) 92994aae32SKeerthy reg = 2; 93994aae32SKeerthy else if (ramp_delay <= 15000) 94994aae32SKeerthy reg = 1; 95994aae32SKeerthy else 96994aae32SKeerthy reg = 0; 97994aae32SKeerthy 98994aae32SKeerthy ret = regmap_update_bits(lp873->regmap, regulators[id].ctrl2_reg, 99994aae32SKeerthy LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE, 100994aae32SKeerthy reg << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE)); 101994aae32SKeerthy if (ret) { 102994aae32SKeerthy dev_err(lp873->dev, "SLEW RATE write failed: %d\n", ret); 103994aae32SKeerthy return ret; 104994aae32SKeerthy } 105994aae32SKeerthy 106994aae32SKeerthy rdev->constraints->ramp_delay = lp873x_buck_ramp_delay[reg]; 107994aae32SKeerthy 108994aae32SKeerthy return 0; 109994aae32SKeerthy } 110994aae32SKeerthy 111994aae32SKeerthy static int lp873x_buck_set_current_limit(struct regulator_dev *rdev, 112994aae32SKeerthy int min_uA, int max_uA) 113994aae32SKeerthy { 114994aae32SKeerthy int id = rdev_get_id(rdev); 115994aae32SKeerthy struct lp873x *lp873 = rdev_get_drvdata(rdev); 116994aae32SKeerthy int i; 117994aae32SKeerthy 118994aae32SKeerthy for (i = ARRAY_SIZE(lp873x_buck_uA) - 1; i >= 0; i--) { 119994aae32SKeerthy if (lp873x_buck_uA[i] >= min_uA && 120994aae32SKeerthy lp873x_buck_uA[i] <= max_uA) 121994aae32SKeerthy return regmap_update_bits(lp873->regmap, 122994aae32SKeerthy regulators[id].ctrl2_reg, 123994aae32SKeerthy LP873X_BUCK0_CTRL_2_BUCK0_ILIM, 124994aae32SKeerthy i << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_ILIM)); 125994aae32SKeerthy } 126994aae32SKeerthy 127994aae32SKeerthy return -EINVAL; 128994aae32SKeerthy } 129994aae32SKeerthy 130994aae32SKeerthy static int lp873x_buck_get_current_limit(struct regulator_dev *rdev) 131994aae32SKeerthy { 132994aae32SKeerthy int id = rdev_get_id(rdev); 133994aae32SKeerthy struct lp873x *lp873 = rdev_get_drvdata(rdev); 134994aae32SKeerthy int ret; 135994aae32SKeerthy unsigned int val; 136994aae32SKeerthy 137994aae32SKeerthy ret = regmap_read(lp873->regmap, regulators[id].ctrl2_reg, &val); 138994aae32SKeerthy if (ret) 139994aae32SKeerthy return ret; 140994aae32SKeerthy 141994aae32SKeerthy val = (val & LP873X_BUCK0_CTRL_2_BUCK0_ILIM) >> 142994aae32SKeerthy __ffs(LP873X_BUCK0_CTRL_2_BUCK0_ILIM); 143994aae32SKeerthy 144994aae32SKeerthy return (val < ARRAY_SIZE(lp873x_buck_uA)) ? 145994aae32SKeerthy lp873x_buck_uA[val] : -EINVAL; 146994aae32SKeerthy } 147994aae32SKeerthy 148994aae32SKeerthy /* Operations permitted on BUCK0, BUCK1 */ 149699bdc23SAxel Lin static const struct regulator_ops lp873x_buck01_ops = { 150994aae32SKeerthy .is_enabled = regulator_is_enabled_regmap, 151994aae32SKeerthy .enable = regulator_enable_regmap, 152994aae32SKeerthy .disable = regulator_disable_regmap, 153994aae32SKeerthy .get_voltage_sel = regulator_get_voltage_sel_regmap, 154994aae32SKeerthy .set_voltage_sel = regulator_set_voltage_sel_regmap, 155994aae32SKeerthy .list_voltage = regulator_list_voltage_linear_range, 156994aae32SKeerthy .map_voltage = regulator_map_voltage_linear_range, 157994aae32SKeerthy .set_voltage_time_sel = regulator_set_voltage_time_sel, 158994aae32SKeerthy .set_ramp_delay = lp873x_buck_set_ramp_delay, 159994aae32SKeerthy .set_current_limit = lp873x_buck_set_current_limit, 160994aae32SKeerthy .get_current_limit = lp873x_buck_get_current_limit, 161994aae32SKeerthy }; 162994aae32SKeerthy 163994aae32SKeerthy /* Operations permitted on LDO0 and LDO1 */ 164699bdc23SAxel Lin static const struct regulator_ops lp873x_ldo01_ops = { 165994aae32SKeerthy .is_enabled = regulator_is_enabled_regmap, 166994aae32SKeerthy .enable = regulator_enable_regmap, 167994aae32SKeerthy .disable = regulator_disable_regmap, 168994aae32SKeerthy .get_voltage_sel = regulator_get_voltage_sel_regmap, 169994aae32SKeerthy .set_voltage_sel = regulator_set_voltage_sel_regmap, 170994aae32SKeerthy .list_voltage = regulator_list_voltage_linear_range, 171994aae32SKeerthy .map_voltage = regulator_map_voltage_linear_range, 172994aae32SKeerthy }; 173994aae32SKeerthy 174994aae32SKeerthy static const struct lp873x_regulator regulators[] = { 175994aae32SKeerthy LP873X_REGULATOR("BUCK0", LP873X_BUCK_0, "buck0", lp873x_buck01_ops, 176994aae32SKeerthy 256, LP873X_REG_BUCK0_VOUT, 177994aae32SKeerthy LP873X_BUCK0_VOUT_BUCK0_VSET, LP873X_REG_BUCK0_CTRL_1, 178994aae32SKeerthy LP873X_BUCK0_CTRL_1_BUCK0_EN, 10000, 1794335f653SAxel Lin buck0_buck1_ranges, LP873X_REG_BUCK0_CTRL_2), 180994aae32SKeerthy LP873X_REGULATOR("BUCK1", LP873X_BUCK_1, "buck1", lp873x_buck01_ops, 181994aae32SKeerthy 256, LP873X_REG_BUCK1_VOUT, 182994aae32SKeerthy LP873X_BUCK1_VOUT_BUCK1_VSET, LP873X_REG_BUCK1_CTRL_1, 183994aae32SKeerthy LP873X_BUCK1_CTRL_1_BUCK1_EN, 10000, 1844335f653SAxel Lin buck0_buck1_ranges, LP873X_REG_BUCK1_CTRL_2), 185994aae32SKeerthy LP873X_REGULATOR("LDO0", LP873X_LDO_0, "ldo0", lp873x_ldo01_ops, 26, 186994aae32SKeerthy LP873X_REG_LDO0_VOUT, LP873X_LDO0_VOUT_LDO0_VSET, 187994aae32SKeerthy LP873X_REG_LDO0_CTRL, 1884335f653SAxel Lin LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 0xFF), 189994aae32SKeerthy LP873X_REGULATOR("LDO1", LP873X_LDO_1, "ldo1", lp873x_ldo01_ops, 26, 190994aae32SKeerthy LP873X_REG_LDO1_VOUT, LP873X_LDO1_VOUT_LDO1_VSET, 191994aae32SKeerthy LP873X_REG_LDO1_CTRL, 1924335f653SAxel Lin LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 0xFF), 193994aae32SKeerthy }; 194994aae32SKeerthy 195994aae32SKeerthy static int lp873x_regulator_probe(struct platform_device *pdev) 196994aae32SKeerthy { 197994aae32SKeerthy struct lp873x *lp873 = dev_get_drvdata(pdev->dev.parent); 198994aae32SKeerthy struct regulator_config config = { }; 199994aae32SKeerthy struct regulator_dev *rdev; 200994aae32SKeerthy int i; 201994aae32SKeerthy 202994aae32SKeerthy platform_set_drvdata(pdev, lp873); 203994aae32SKeerthy 204994aae32SKeerthy config.dev = &pdev->dev; 205994aae32SKeerthy config.dev->of_node = lp873->dev->of_node; 206994aae32SKeerthy config.driver_data = lp873; 207994aae32SKeerthy config.regmap = lp873->regmap; 208994aae32SKeerthy 209994aae32SKeerthy for (i = 0; i < ARRAY_SIZE(regulators); i++) { 210994aae32SKeerthy rdev = devm_regulator_register(&pdev->dev, ®ulators[i].desc, 211994aae32SKeerthy &config); 212994aae32SKeerthy if (IS_ERR(rdev)) { 213994aae32SKeerthy dev_err(lp873->dev, "failed to register %s regulator\n", 214994aae32SKeerthy pdev->name); 215994aae32SKeerthy return PTR_ERR(rdev); 216994aae32SKeerthy } 217994aae32SKeerthy } 218994aae32SKeerthy 219994aae32SKeerthy return 0; 220994aae32SKeerthy } 221994aae32SKeerthy 222994aae32SKeerthy static const struct platform_device_id lp873x_regulator_id_table[] = { 223994aae32SKeerthy { "lp873x-regulator", }, 224994aae32SKeerthy { /* sentinel */ } 225994aae32SKeerthy }; 226994aae32SKeerthy MODULE_DEVICE_TABLE(platform, lp873x_regulator_id_table); 227994aae32SKeerthy 228994aae32SKeerthy static struct platform_driver lp873x_regulator_driver = { 229994aae32SKeerthy .driver = { 230994aae32SKeerthy .name = "lp873x-pmic", 231994aae32SKeerthy }, 232994aae32SKeerthy .probe = lp873x_regulator_probe, 233994aae32SKeerthy .id_table = lp873x_regulator_id_table, 234994aae32SKeerthy }; 235994aae32SKeerthy module_platform_driver(lp873x_regulator_driver); 236994aae32SKeerthy 237994aae32SKeerthy MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>"); 238994aae32SKeerthy MODULE_DESCRIPTION("LP873X voltage regulator driver"); 239994aae32SKeerthy MODULE_ALIAS("platform:lp873x-pmic"); 240994aae32SKeerthy MODULE_LICENSE("GPL v2"); 241