16ffc3270SLaxman Dewangan /* 26ffc3270SLaxman Dewangan * Regulator driver for RICOH RC5T583 power management chip. 36ffc3270SLaxman Dewangan * 46ffc3270SLaxman Dewangan * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. 56ffc3270SLaxman Dewangan * Author: Laxman dewangan <ldewangan@nvidia.com> 66ffc3270SLaxman Dewangan * 76ffc3270SLaxman Dewangan * based on code 86ffc3270SLaxman Dewangan * Copyright (C) 2011 RICOH COMPANY,LTD 96ffc3270SLaxman Dewangan * 106ffc3270SLaxman Dewangan * 116ffc3270SLaxman Dewangan * This program is free software; you can redistribute it and/or modify it 126ffc3270SLaxman Dewangan * under the terms and conditions of the GNU General Public License, 136ffc3270SLaxman Dewangan * version 2, as published by the Free Software Foundation. 146ffc3270SLaxman Dewangan * 156ffc3270SLaxman Dewangan * This program is distributed in the hope it will be useful, but WITHOUT 166ffc3270SLaxman Dewangan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 176ffc3270SLaxman Dewangan * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 186ffc3270SLaxman Dewangan * more details. 196ffc3270SLaxman Dewangan * 206ffc3270SLaxman Dewangan * You should have received a copy of the GNU General Public License 216ffc3270SLaxman Dewangan * along with this program. If not, see <http://www.gnu.org/licenses/>. 226ffc3270SLaxman Dewangan * 236ffc3270SLaxman Dewangan */ 246ffc3270SLaxman Dewangan 256ffc3270SLaxman Dewangan #include <linux/module.h> 266ffc3270SLaxman Dewangan #include <linux/delay.h> 276ffc3270SLaxman Dewangan #include <linux/init.h> 286ffc3270SLaxman Dewangan #include <linux/slab.h> 296ffc3270SLaxman Dewangan #include <linux/err.h> 306ffc3270SLaxman Dewangan #include <linux/platform_device.h> 316ffc3270SLaxman Dewangan #include <linux/regulator/driver.h> 326ffc3270SLaxman Dewangan #include <linux/regulator/machine.h> 336ffc3270SLaxman Dewangan #include <linux/gpio.h> 346ffc3270SLaxman Dewangan #include <linux/mfd/rc5t583.h> 356ffc3270SLaxman Dewangan 366ffc3270SLaxman Dewangan struct rc5t583_regulator_info { 376ffc3270SLaxman Dewangan int deepsleep_id; 386ffc3270SLaxman Dewangan 396ffc3270SLaxman Dewangan /* Regulator register address.*/ 406ffc3270SLaxman Dewangan uint8_t reg_disc_reg; 416ffc3270SLaxman Dewangan uint8_t disc_bit; 426ffc3270SLaxman Dewangan uint8_t deepsleep_reg; 436ffc3270SLaxman Dewangan 446ffc3270SLaxman Dewangan /* Chip constraints on regulator behavior */ 456ffc3270SLaxman Dewangan int min_uV; 466ffc3270SLaxman Dewangan int max_uV; 476ffc3270SLaxman Dewangan int step_uV; 486ffc3270SLaxman Dewangan 496ffc3270SLaxman Dewangan /* Regulator specific turn-on delay and voltage settling time*/ 506ffc3270SLaxman Dewangan int enable_uv_per_us; 516ffc3270SLaxman Dewangan int change_uv_per_us; 526ffc3270SLaxman Dewangan 536ffc3270SLaxman Dewangan /* Used by regulator core */ 546ffc3270SLaxman Dewangan struct regulator_desc desc; 556ffc3270SLaxman Dewangan }; 566ffc3270SLaxman Dewangan 576ffc3270SLaxman Dewangan struct rc5t583_regulator { 586ffc3270SLaxman Dewangan struct rc5t583_regulator_info *reg_info; 596ffc3270SLaxman Dewangan 606ffc3270SLaxman Dewangan /* Devices */ 616ffc3270SLaxman Dewangan struct device *dev; 626ffc3270SLaxman Dewangan struct rc5t583 *mfd; 636ffc3270SLaxman Dewangan struct regulator_dev *rdev; 646ffc3270SLaxman Dewangan }; 656ffc3270SLaxman Dewangan 666ffc3270SLaxman Dewangan static int rc5t583_list_voltage(struct regulator_dev *rdev, unsigned selector) 676ffc3270SLaxman Dewangan { 686ffc3270SLaxman Dewangan struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); 696ffc3270SLaxman Dewangan struct rc5t583_regulator_info *ri = reg->reg_info; 706ffc3270SLaxman Dewangan return ri->min_uV + (ri->step_uV * selector); 716ffc3270SLaxman Dewangan } 726ffc3270SLaxman Dewangan 73f604c10cSAxel Lin static int rc5t583_set_voltage(struct regulator_dev *rdev, 74f604c10cSAxel Lin int min_uV, int max_uV, unsigned *selector) 756ffc3270SLaxman Dewangan { 766ffc3270SLaxman Dewangan struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); 776ffc3270SLaxman Dewangan struct rc5t583_regulator_info *ri = reg->reg_info; 78f604c10cSAxel Lin int sel, ret; 79f604c10cSAxel Lin 80f604c10cSAxel Lin if (min_uV < ri->min_uV) 81f604c10cSAxel Lin min_uV = ri->min_uV; 82f604c10cSAxel Lin 83f604c10cSAxel Lin sel = DIV_ROUND_UP(min_uV - ri->min_uV, ri->step_uV); 84f604c10cSAxel Lin 85f604c10cSAxel Lin if (sel >= rdev->desc->n_voltages) { 86f604c10cSAxel Lin dev_err(&rdev->dev, "Invalid selector 0x%02x\n", sel); 876ffc3270SLaxman Dewangan return -EINVAL; 886ffc3270SLaxman Dewangan } 896ffc3270SLaxman Dewangan 90f604c10cSAxel Lin *selector = sel; 91f604c10cSAxel Lin 9215b397d7SAxel Lin ret = rc5t583_update(reg->mfd->dev, rdev->desc->vsel_reg, sel, 9315b397d7SAxel Lin rdev->desc->vsel_mask); 946ffc3270SLaxman Dewangan if (ret < 0) 9515b397d7SAxel Lin dev_err(&rdev->dev, "Error in update voltage register 0x%02x\n", 9615b397d7SAxel Lin rdev->desc->vsel_reg); 976ffc3270SLaxman Dewangan return ret; 986ffc3270SLaxman Dewangan } 996ffc3270SLaxman Dewangan 1006ffc3270SLaxman Dewangan static int rc5t583_regulator_enable_time(struct regulator_dev *rdev) 1016ffc3270SLaxman Dewangan { 1026ffc3270SLaxman Dewangan struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); 10315b397d7SAxel Lin int vsel = regulator_get_voltage_sel_regmap(rdev); 1046ffc3270SLaxman Dewangan int curr_uV = rc5t583_list_voltage(rdev, vsel); 10515b397d7SAxel Lin 1066ffc3270SLaxman Dewangan return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us); 1076ffc3270SLaxman Dewangan } 1086ffc3270SLaxman Dewangan 1096ffc3270SLaxman Dewangan static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev, 1106ffc3270SLaxman Dewangan unsigned int old_selector, unsigned int new_selector) 1116ffc3270SLaxman Dewangan { 1126ffc3270SLaxman Dewangan struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); 1136ffc3270SLaxman Dewangan int old_uV, new_uV; 1146ffc3270SLaxman Dewangan old_uV = rc5t583_list_voltage(rdev, old_selector); 1156ffc3270SLaxman Dewangan 1166ffc3270SLaxman Dewangan if (old_uV < 0) 1176ffc3270SLaxman Dewangan return old_uV; 1186ffc3270SLaxman Dewangan 1196ffc3270SLaxman Dewangan new_uV = rc5t583_list_voltage(rdev, new_selector); 1206ffc3270SLaxman Dewangan if (new_uV < 0) 1216ffc3270SLaxman Dewangan return new_uV; 1226ffc3270SLaxman Dewangan 1236ffc3270SLaxman Dewangan return DIV_ROUND_UP(abs(old_uV - new_uV), 1246ffc3270SLaxman Dewangan reg->reg_info->change_uv_per_us); 1256ffc3270SLaxman Dewangan } 1266ffc3270SLaxman Dewangan 1276ffc3270SLaxman Dewangan 1286ffc3270SLaxman Dewangan static struct regulator_ops rc5t583_ops = { 1295bb6936cSAxel Lin .is_enabled = regulator_is_enabled_regmap, 1305bb6936cSAxel Lin .enable = regulator_enable_regmap, 1315bb6936cSAxel Lin .disable = regulator_disable_regmap, 1326ffc3270SLaxman Dewangan .enable_time = rc5t583_regulator_enable_time, 13315b397d7SAxel Lin .get_voltage_sel = regulator_get_voltage_sel_regmap, 134f604c10cSAxel Lin .set_voltage = rc5t583_set_voltage, 1356ffc3270SLaxman Dewangan .list_voltage = rc5t583_list_voltage, 1366ffc3270SLaxman Dewangan .set_voltage_time_sel = rc5t583_set_voltage_time_sel, 1376ffc3270SLaxman Dewangan }; 1386ffc3270SLaxman Dewangan 13995e301baSAxel Lin #define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, \ 14095e301baSAxel Lin _vout_mask, _min_mv, _max_mv, _step_uV, _enable_mv) \ 1416ffc3270SLaxman Dewangan { \ 1426ffc3270SLaxman Dewangan .reg_disc_reg = RC5T583_REG_##_disc_reg, \ 1436ffc3270SLaxman Dewangan .disc_bit = _disc_bit, \ 14495e301baSAxel Lin .deepsleep_reg = RC5T583_REG_##_id##DAC_DS, \ 1456ffc3270SLaxman Dewangan .min_uV = _min_mv * 1000, \ 1466ffc3270SLaxman Dewangan .max_uV = _max_mv * 1000, \ 1476ffc3270SLaxman Dewangan .step_uV = _step_uV, \ 1486ffc3270SLaxman Dewangan .enable_uv_per_us = _enable_mv * 1000, \ 1496ffc3270SLaxman Dewangan .change_uv_per_us = 40 * 1000, \ 1506ffc3270SLaxman Dewangan .deepsleep_id = RC5T583_DS_##_id, \ 1516ffc3270SLaxman Dewangan .desc = { \ 1526ffc3270SLaxman Dewangan .name = "rc5t583-regulator-"#_id, \ 1536ffc3270SLaxman Dewangan .id = RC5T583_REGULATOR_##_id, \ 154e3a7384cSAxel Lin .n_voltages = (_max_mv - _min_mv) * 1000 / _step_uV + 1, \ 1556ffc3270SLaxman Dewangan .ops = &rc5t583_ops, \ 1566ffc3270SLaxman Dewangan .type = REGULATOR_VOLTAGE, \ 1576ffc3270SLaxman Dewangan .owner = THIS_MODULE, \ 15815b397d7SAxel Lin .vsel_reg = RC5T583_REG_##_id##DAC, \ 15915b397d7SAxel Lin .vsel_mask = _vout_mask, \ 1605bb6936cSAxel Lin .enable_reg = RC5T583_REG_##_en_reg, \ 1615bb6936cSAxel Lin .enable_mask = BIT(_en_bit), \ 1626ffc3270SLaxman Dewangan }, \ 1636ffc3270SLaxman Dewangan } 1646ffc3270SLaxman Dewangan 1656ffc3270SLaxman Dewangan static struct rc5t583_regulator_info rc5t583_reg_info[RC5T583_REGULATOR_MAX] = { 16695e301baSAxel Lin RC5T583_REG(DC0, DC0CTL, 0, DC0CTL, 1, 0x7F, 700, 1500, 12500, 4), 16795e301baSAxel Lin RC5T583_REG(DC1, DC1CTL, 0, DC1CTL, 1, 0x7F, 700, 1500, 12500, 14), 16895e301baSAxel Lin RC5T583_REG(DC2, DC2CTL, 0, DC2CTL, 1, 0x7F, 900, 2400, 12500, 14), 16995e301baSAxel Lin RC5T583_REG(DC3, DC3CTL, 0, DC3CTL, 1, 0x7F, 900, 2400, 12500, 14), 17095e301baSAxel Lin RC5T583_REG(LDO0, LDOEN2, 0, LDODIS2, 0, 0x7F, 900, 3400, 25000, 160), 17195e301baSAxel Lin RC5T583_REG(LDO1, LDOEN2, 1, LDODIS2, 1, 0x7F, 900, 3400, 25000, 160), 17295e301baSAxel Lin RC5T583_REG(LDO2, LDOEN2, 2, LDODIS2, 2, 0x7F, 900, 3400, 25000, 160), 17395e301baSAxel Lin RC5T583_REG(LDO3, LDOEN2, 3, LDODIS2, 3, 0x7F, 900, 3400, 25000, 160), 17495e301baSAxel Lin RC5T583_REG(LDO4, LDOEN2, 4, LDODIS2, 4, 0x3F, 750, 1500, 12500, 133), 17595e301baSAxel Lin RC5T583_REG(LDO5, LDOEN2, 5, LDODIS2, 5, 0x7F, 900, 3400, 25000, 267), 17695e301baSAxel Lin RC5T583_REG(LDO6, LDOEN2, 6, LDODIS2, 6, 0x7F, 900, 3400, 25000, 133), 17795e301baSAxel Lin RC5T583_REG(LDO7, LDOEN2, 7, LDODIS2, 7, 0x7F, 900, 3400, 25000, 233), 17895e301baSAxel Lin RC5T583_REG(LDO8, LDOEN1, 0, LDODIS1, 0, 0x7F, 900, 3400, 25000, 233), 17995e301baSAxel Lin RC5T583_REG(LDO9, LDOEN1, 1, LDODIS1, 1, 0x7F, 900, 3400, 25000, 133), 1806ffc3270SLaxman Dewangan }; 1816ffc3270SLaxman Dewangan 1826ffc3270SLaxman Dewangan static int __devinit rc5t583_regulator_probe(struct platform_device *pdev) 1836ffc3270SLaxman Dewangan { 1846ffc3270SLaxman Dewangan struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); 1856ffc3270SLaxman Dewangan struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); 1866ffc3270SLaxman Dewangan struct regulator_init_data *reg_data; 187c172708dSMark Brown struct regulator_config config = { }; 1886ffc3270SLaxman Dewangan struct rc5t583_regulator *reg = NULL; 1896ffc3270SLaxman Dewangan struct rc5t583_regulator *regs; 1906ffc3270SLaxman Dewangan struct regulator_dev *rdev; 1916ffc3270SLaxman Dewangan struct rc5t583_regulator_info *ri; 1926ffc3270SLaxman Dewangan int ret; 1936ffc3270SLaxman Dewangan int id; 1946ffc3270SLaxman Dewangan 1956ffc3270SLaxman Dewangan if (!pdata) { 1966ffc3270SLaxman Dewangan dev_err(&pdev->dev, "No platform data, exiting...\n"); 1976ffc3270SLaxman Dewangan return -ENODEV; 1986ffc3270SLaxman Dewangan } 1996ffc3270SLaxman Dewangan 2006ffc3270SLaxman Dewangan regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX * 2016ffc3270SLaxman Dewangan sizeof(struct rc5t583_regulator), GFP_KERNEL); 2026ffc3270SLaxman Dewangan if (!regs) { 2036ffc3270SLaxman Dewangan dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); 2046ffc3270SLaxman Dewangan return -ENOMEM; 2056ffc3270SLaxman Dewangan } 2066ffc3270SLaxman Dewangan 2076ffc3270SLaxman Dewangan 2086ffc3270SLaxman Dewangan for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) { 2096ffc3270SLaxman Dewangan reg_data = pdata->reg_init_data[id]; 2106ffc3270SLaxman Dewangan 2116ffc3270SLaxman Dewangan /* No need to register if there is no regulator data */ 2126ffc3270SLaxman Dewangan if (!reg_data) 2136ffc3270SLaxman Dewangan continue; 2146ffc3270SLaxman Dewangan 2156ffc3270SLaxman Dewangan reg = ®s[id]; 2166ffc3270SLaxman Dewangan ri = &rc5t583_reg_info[id]; 2176ffc3270SLaxman Dewangan reg->reg_info = ri; 2186ffc3270SLaxman Dewangan reg->mfd = rc5t583; 2196ffc3270SLaxman Dewangan reg->dev = &pdev->dev; 2206ffc3270SLaxman Dewangan 2216ffc3270SLaxman Dewangan if (ri->deepsleep_id == RC5T583_DS_NONE) 2226ffc3270SLaxman Dewangan goto skip_ext_pwr_config; 2236ffc3270SLaxman Dewangan 2246ffc3270SLaxman Dewangan ret = rc5t583_ext_power_req_config(rc5t583->dev, 2256ffc3270SLaxman Dewangan ri->deepsleep_id, 2266ffc3270SLaxman Dewangan pdata->regulator_ext_pwr_control[id], 2276ffc3270SLaxman Dewangan pdata->regulator_deepsleep_slot[id]); 2286ffc3270SLaxman Dewangan /* 2296ffc3270SLaxman Dewangan * Configuring external control is not a major issue, 2306ffc3270SLaxman Dewangan * just give warning. 2316ffc3270SLaxman Dewangan */ 2326ffc3270SLaxman Dewangan if (ret < 0) 2336ffc3270SLaxman Dewangan dev_warn(&pdev->dev, 2346ffc3270SLaxman Dewangan "Failed to configure ext control %d\n", id); 2356ffc3270SLaxman Dewangan 2366ffc3270SLaxman Dewangan skip_ext_pwr_config: 237c172708dSMark Brown config.dev = &pdev->dev; 238c172708dSMark Brown config.init_data = reg_data; 239c172708dSMark Brown config.driver_data = reg; 2405bb6936cSAxel Lin config.regmap = rc5t583->regmap; 241c172708dSMark Brown 242c172708dSMark Brown rdev = regulator_register(&ri->desc, &config); 243a69df8a1SAxel Lin if (IS_ERR(rdev)) { 2446ffc3270SLaxman Dewangan dev_err(&pdev->dev, "Failed to register regulator %s\n", 2456ffc3270SLaxman Dewangan ri->desc.name); 2466ffc3270SLaxman Dewangan ret = PTR_ERR(rdev); 2476ffc3270SLaxman Dewangan goto clean_exit; 2486ffc3270SLaxman Dewangan } 2496ffc3270SLaxman Dewangan reg->rdev = rdev; 2506ffc3270SLaxman Dewangan } 2516ffc3270SLaxman Dewangan platform_set_drvdata(pdev, regs); 2526ffc3270SLaxman Dewangan return 0; 2536ffc3270SLaxman Dewangan 2546ffc3270SLaxman Dewangan clean_exit: 255a69df8a1SAxel Lin while (--id >= 0) 2566ffc3270SLaxman Dewangan regulator_unregister(regs[id].rdev); 2576ffc3270SLaxman Dewangan 2586ffc3270SLaxman Dewangan return ret; 2596ffc3270SLaxman Dewangan } 2606ffc3270SLaxman Dewangan 2616ffc3270SLaxman Dewangan static int __devexit rc5t583_regulator_remove(struct platform_device *pdev) 2626ffc3270SLaxman Dewangan { 2636ffc3270SLaxman Dewangan struct rc5t583_regulator *regs = platform_get_drvdata(pdev); 2646ffc3270SLaxman Dewangan int id; 2656ffc3270SLaxman Dewangan 2666ffc3270SLaxman Dewangan for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) 2676ffc3270SLaxman Dewangan regulator_unregister(regs[id].rdev); 2686ffc3270SLaxman Dewangan return 0; 2696ffc3270SLaxman Dewangan } 2706ffc3270SLaxman Dewangan 2716ffc3270SLaxman Dewangan static struct platform_driver rc5t583_regulator_driver = { 2726ffc3270SLaxman Dewangan .driver = { 2736ffc3270SLaxman Dewangan .name = "rc5t583-regulator", 2746ffc3270SLaxman Dewangan .owner = THIS_MODULE, 2756ffc3270SLaxman Dewangan }, 2766ffc3270SLaxman Dewangan .probe = rc5t583_regulator_probe, 2776ffc3270SLaxman Dewangan .remove = __devexit_p(rc5t583_regulator_remove), 2786ffc3270SLaxman Dewangan }; 2796ffc3270SLaxman Dewangan 2806ffc3270SLaxman Dewangan static int __init rc5t583_regulator_init(void) 2816ffc3270SLaxman Dewangan { 2826ffc3270SLaxman Dewangan return platform_driver_register(&rc5t583_regulator_driver); 2836ffc3270SLaxman Dewangan } 2846ffc3270SLaxman Dewangan subsys_initcall(rc5t583_regulator_init); 2856ffc3270SLaxman Dewangan 2866ffc3270SLaxman Dewangan static void __exit rc5t583_regulator_exit(void) 2876ffc3270SLaxman Dewangan { 2886ffc3270SLaxman Dewangan platform_driver_unregister(&rc5t583_regulator_driver); 2896ffc3270SLaxman Dewangan } 2906ffc3270SLaxman Dewangan module_exit(rc5t583_regulator_exit); 2916ffc3270SLaxman Dewangan 2926ffc3270SLaxman Dewangan MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 2936ffc3270SLaxman Dewangan MODULE_DESCRIPTION("RC5T583 regulator driver"); 2946ffc3270SLaxman Dewangan MODULE_ALIAS("platform:rc5t583-regulator"); 2954eb06453SLaxman Dewangan MODULE_LICENSE("GPL v2"); 296