1*08bf1c0aSAshish Jangam /* 2*08bf1c0aSAshish Jangam * da9052-regulator.c: Regulator driver for DA9052 3*08bf1c0aSAshish Jangam * 4*08bf1c0aSAshish Jangam * Copyright(c) 2011 Dialog Semiconductor Ltd. 5*08bf1c0aSAshish Jangam * 6*08bf1c0aSAshish Jangam * Author: David Dajun Chen <dchen@diasemi.com> 7*08bf1c0aSAshish Jangam * 8*08bf1c0aSAshish Jangam * This program is free software; you can redistribute it and/or modify 9*08bf1c0aSAshish Jangam * it under the terms of the GNU General Public License as published by 10*08bf1c0aSAshish Jangam * the Free Software Foundation; either version 2 of the License, or 11*08bf1c0aSAshish Jangam * (at your option) any later version. 12*08bf1c0aSAshish Jangam * 13*08bf1c0aSAshish Jangam */ 14*08bf1c0aSAshish Jangam 15*08bf1c0aSAshish Jangam #include <linux/module.h> 16*08bf1c0aSAshish Jangam #include <linux/moduleparam.h> 17*08bf1c0aSAshish Jangam #include <linux/init.h> 18*08bf1c0aSAshish Jangam #include <linux/err.h> 19*08bf1c0aSAshish Jangam #include <linux/platform_device.h> 20*08bf1c0aSAshish Jangam #include <linux/regulator/driver.h> 21*08bf1c0aSAshish Jangam #include <linux/regulator/machine.h> 22*08bf1c0aSAshish Jangam 23*08bf1c0aSAshish Jangam #include <linux/mfd/da9052/da9052.h> 24*08bf1c0aSAshish Jangam #include <linux/mfd/da9052/reg.h> 25*08bf1c0aSAshish Jangam #include <linux/mfd/da9052/pdata.h> 26*08bf1c0aSAshish Jangam 27*08bf1c0aSAshish Jangam /* Buck step size */ 28*08bf1c0aSAshish Jangam #define DA9052_BUCK_PERI_3uV_STEP 100000 29*08bf1c0aSAshish Jangam #define DA9052_BUCK_PERI_REG_MAP_UPTO_3uV 24 30*08bf1c0aSAshish Jangam #define DA9052_CONST_3uV 3000000 31*08bf1c0aSAshish Jangam 32*08bf1c0aSAshish Jangam #define DA9052_MIN_UA 0 33*08bf1c0aSAshish Jangam #define DA9052_MAX_UA 3 34*08bf1c0aSAshish Jangam #define DA9052_CURRENT_RANGE 4 35*08bf1c0aSAshish Jangam 36*08bf1c0aSAshish Jangam /* Bit masks */ 37*08bf1c0aSAshish Jangam #define DA9052_BUCK_ILIM_MASK_EVEN 0x0c 38*08bf1c0aSAshish Jangam #define DA9052_BUCK_ILIM_MASK_ODD 0xc0 39*08bf1c0aSAshish Jangam 40*08bf1c0aSAshish Jangam static const u32 da9052_current_limits[3][4] = { 41*08bf1c0aSAshish Jangam {700000, 800000, 1000000, 1200000}, /* DA9052-BC BUCKs */ 42*08bf1c0aSAshish Jangam {1600000, 2000000, 2400000, 3000000}, /* DA9053-AA/Bx BUCK-CORE */ 43*08bf1c0aSAshish Jangam {800000, 1000000, 1200000, 1500000}, /* DA9053-AA/Bx BUCK-PRO, 44*08bf1c0aSAshish Jangam * BUCK-MEM and BUCK-PERI 45*08bf1c0aSAshish Jangam */ 46*08bf1c0aSAshish Jangam }; 47*08bf1c0aSAshish Jangam 48*08bf1c0aSAshish Jangam struct da9052_regulator_info { 49*08bf1c0aSAshish Jangam struct regulator_desc reg_desc; 50*08bf1c0aSAshish Jangam int step_uV; 51*08bf1c0aSAshish Jangam int min_uV; 52*08bf1c0aSAshish Jangam int max_uV; 53*08bf1c0aSAshish Jangam unsigned char volt_shift; 54*08bf1c0aSAshish Jangam unsigned char en_bit; 55*08bf1c0aSAshish Jangam unsigned char activate_bit; 56*08bf1c0aSAshish Jangam }; 57*08bf1c0aSAshish Jangam 58*08bf1c0aSAshish Jangam struct da9052_regulator { 59*08bf1c0aSAshish Jangam struct da9052 *da9052; 60*08bf1c0aSAshish Jangam struct da9052_regulator_info *info; 61*08bf1c0aSAshish Jangam struct regulator_dev *rdev; 62*08bf1c0aSAshish Jangam }; 63*08bf1c0aSAshish Jangam 64*08bf1c0aSAshish Jangam static int verify_range(struct da9052_regulator_info *info, 65*08bf1c0aSAshish Jangam int min_uV, int max_uV) 66*08bf1c0aSAshish Jangam { 67*08bf1c0aSAshish Jangam if (min_uV > info->max_uV || max_uV < info->min_uV) 68*08bf1c0aSAshish Jangam return -EINVAL; 69*08bf1c0aSAshish Jangam 70*08bf1c0aSAshish Jangam return 0; 71*08bf1c0aSAshish Jangam } 72*08bf1c0aSAshish Jangam 73*08bf1c0aSAshish Jangam static int da9052_regulator_enable(struct regulator_dev *rdev) 74*08bf1c0aSAshish Jangam { 75*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 76*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 77*08bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 78*08bf1c0aSAshish Jangam 79*08bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, 80*08bf1c0aSAshish Jangam DA9052_BUCKCORE_REG + offset, 81*08bf1c0aSAshish Jangam 1 << info->en_bit, 1 << info->en_bit); 82*08bf1c0aSAshish Jangam } 83*08bf1c0aSAshish Jangam 84*08bf1c0aSAshish Jangam static int da9052_regulator_disable(struct regulator_dev *rdev) 85*08bf1c0aSAshish Jangam { 86*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 87*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 88*08bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 89*08bf1c0aSAshish Jangam 90*08bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, 91*08bf1c0aSAshish Jangam DA9052_BUCKCORE_REG + offset, 92*08bf1c0aSAshish Jangam 1 << info->en_bit, 0); 93*08bf1c0aSAshish Jangam } 94*08bf1c0aSAshish Jangam 95*08bf1c0aSAshish Jangam static int da9052_regulator_is_enabled(struct regulator_dev *rdev) 96*08bf1c0aSAshish Jangam { 97*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 98*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 99*08bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 100*08bf1c0aSAshish Jangam int ret; 101*08bf1c0aSAshish Jangam 102*08bf1c0aSAshish Jangam ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset); 103*08bf1c0aSAshish Jangam if (ret < 0) 104*08bf1c0aSAshish Jangam return ret; 105*08bf1c0aSAshish Jangam 106*08bf1c0aSAshish Jangam return ret & (1 << info->en_bit); 107*08bf1c0aSAshish Jangam } 108*08bf1c0aSAshish Jangam 109*08bf1c0aSAshish Jangam static int da9052_dcdc_get_current_limit(struct regulator_dev *rdev) 110*08bf1c0aSAshish Jangam { 111*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 112*08bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 113*08bf1c0aSAshish Jangam int ret, row = 2; 114*08bf1c0aSAshish Jangam 115*08bf1c0aSAshish Jangam ret = da9052_reg_read(regulator->da9052, DA9052_BUCKA_REG + offset/2); 116*08bf1c0aSAshish Jangam if (ret < 0) 117*08bf1c0aSAshish Jangam return ret; 118*08bf1c0aSAshish Jangam 119*08bf1c0aSAshish Jangam /* Determine the even or odd position of the buck current limit 120*08bf1c0aSAshish Jangam * register field 121*08bf1c0aSAshish Jangam */ 122*08bf1c0aSAshish Jangam if (offset % 2 == 0) 123*08bf1c0aSAshish Jangam ret = (ret & DA9052_BUCK_ILIM_MASK_EVEN) >> 2; 124*08bf1c0aSAshish Jangam else 125*08bf1c0aSAshish Jangam ret = (ret & DA9052_BUCK_ILIM_MASK_ODD) >> 6; 126*08bf1c0aSAshish Jangam 127*08bf1c0aSAshish Jangam /* Select the appropriate current limit range */ 128*08bf1c0aSAshish Jangam if (regulator->da9052->chip_id == DA9052) 129*08bf1c0aSAshish Jangam row = 0; 130*08bf1c0aSAshish Jangam else if (offset == 0) 131*08bf1c0aSAshish Jangam row = 1; 132*08bf1c0aSAshish Jangam 133*08bf1c0aSAshish Jangam return da9052_current_limits[row][ret]; 134*08bf1c0aSAshish Jangam } 135*08bf1c0aSAshish Jangam 136*08bf1c0aSAshish Jangam static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA, 137*08bf1c0aSAshish Jangam int max_uA) 138*08bf1c0aSAshish Jangam { 139*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 140*08bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 141*08bf1c0aSAshish Jangam int reg_val = 0; 142*08bf1c0aSAshish Jangam int i, row = 2; 143*08bf1c0aSAshish Jangam 144*08bf1c0aSAshish Jangam /* Select the appropriate current limit range */ 145*08bf1c0aSAshish Jangam if (regulator->da9052->chip_id == DA9052) 146*08bf1c0aSAshish Jangam row = 0; 147*08bf1c0aSAshish Jangam else if (offset == 0) 148*08bf1c0aSAshish Jangam row = 1; 149*08bf1c0aSAshish Jangam 150*08bf1c0aSAshish Jangam if (min_uA > da9052_current_limits[row][DA9052_MAX_UA] || 151*08bf1c0aSAshish Jangam max_uA < da9052_current_limits[row][DA9052_MIN_UA]) 152*08bf1c0aSAshish Jangam return -EINVAL; 153*08bf1c0aSAshish Jangam 154*08bf1c0aSAshish Jangam for (i = 0; i < DA9052_CURRENT_RANGE; i++) { 155*08bf1c0aSAshish Jangam if (min_uA <= da9052_current_limits[row][i]) { 156*08bf1c0aSAshish Jangam reg_val = i; 157*08bf1c0aSAshish Jangam break; 158*08bf1c0aSAshish Jangam } 159*08bf1c0aSAshish Jangam } 160*08bf1c0aSAshish Jangam 161*08bf1c0aSAshish Jangam /* Determine the even or odd position of the buck current limit 162*08bf1c0aSAshish Jangam * register field 163*08bf1c0aSAshish Jangam */ 164*08bf1c0aSAshish Jangam if (offset % 2 == 0) 165*08bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, 166*08bf1c0aSAshish Jangam DA9052_BUCKA_REG + offset/2, 167*08bf1c0aSAshish Jangam DA9052_BUCK_ILIM_MASK_EVEN, 168*08bf1c0aSAshish Jangam reg_val << 2); 169*08bf1c0aSAshish Jangam else 170*08bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, 171*08bf1c0aSAshish Jangam DA9052_BUCKA_REG + offset/2, 172*08bf1c0aSAshish Jangam DA9052_BUCK_ILIM_MASK_ODD, 173*08bf1c0aSAshish Jangam reg_val << 6); 174*08bf1c0aSAshish Jangam } 175*08bf1c0aSAshish Jangam 176*08bf1c0aSAshish Jangam static int da9052_list_buckperi_voltage(struct regulator_dev *rdev, 177*08bf1c0aSAshish Jangam unsigned int selector) 178*08bf1c0aSAshish Jangam { 179*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 180*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 181*08bf1c0aSAshish Jangam int volt_uV; 182*08bf1c0aSAshish Jangam 183*08bf1c0aSAshish Jangam if ((regulator->da9052->chip_id == DA9052) && 184*08bf1c0aSAshish Jangam (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) { 185*08bf1c0aSAshish Jangam volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV) 186*08bf1c0aSAshish Jangam + info->min_uV); 187*08bf1c0aSAshish Jangam volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV) 188*08bf1c0aSAshish Jangam * (DA9052_BUCK_PERI_3uV_STEP); 189*08bf1c0aSAshish Jangam } else 190*08bf1c0aSAshish Jangam volt_uV = (selector * info->step_uV) + info->min_uV; 191*08bf1c0aSAshish Jangam 192*08bf1c0aSAshish Jangam if (volt_uV > info->max_uV) 193*08bf1c0aSAshish Jangam return -EINVAL; 194*08bf1c0aSAshish Jangam 195*08bf1c0aSAshish Jangam return volt_uV; 196*08bf1c0aSAshish Jangam } 197*08bf1c0aSAshish Jangam 198*08bf1c0aSAshish Jangam static int da9052_list_voltage(struct regulator_dev *rdev, 199*08bf1c0aSAshish Jangam unsigned int selector) 200*08bf1c0aSAshish Jangam { 201*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 202*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 203*08bf1c0aSAshish Jangam int volt_uV; 204*08bf1c0aSAshish Jangam 205*08bf1c0aSAshish Jangam volt_uV = info->min_uV + info->step_uV * selector; 206*08bf1c0aSAshish Jangam 207*08bf1c0aSAshish Jangam if (volt_uV > info->max_uV) 208*08bf1c0aSAshish Jangam return -EINVAL; 209*08bf1c0aSAshish Jangam 210*08bf1c0aSAshish Jangam return volt_uV; 211*08bf1c0aSAshish Jangam } 212*08bf1c0aSAshish Jangam 213*08bf1c0aSAshish Jangam static int da9052_regulator_set_voltage_int(struct regulator_dev *rdev, 214*08bf1c0aSAshish Jangam int min_uV, int max_uV, 215*08bf1c0aSAshish Jangam unsigned int *selector) 216*08bf1c0aSAshish Jangam { 217*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 218*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 219*08bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 220*08bf1c0aSAshish Jangam int ret; 221*08bf1c0aSAshish Jangam 222*08bf1c0aSAshish Jangam ret = verify_range(info, min_uV, max_uV); 223*08bf1c0aSAshish Jangam if (ret < 0) 224*08bf1c0aSAshish Jangam return ret; 225*08bf1c0aSAshish Jangam 226*08bf1c0aSAshish Jangam if (min_uV < info->min_uV) 227*08bf1c0aSAshish Jangam min_uV = info->min_uV; 228*08bf1c0aSAshish Jangam 229*08bf1c0aSAshish Jangam *selector = (min_uV - info->min_uV) / info->step_uV; 230*08bf1c0aSAshish Jangam 231*08bf1c0aSAshish Jangam ret = da9052_list_voltage(rdev, *selector); 232*08bf1c0aSAshish Jangam if (ret < 0) 233*08bf1c0aSAshish Jangam return ret; 234*08bf1c0aSAshish Jangam 235*08bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, 236*08bf1c0aSAshish Jangam DA9052_BUCKCORE_REG + offset, 237*08bf1c0aSAshish Jangam (1 << info->volt_shift) - 1, *selector); 238*08bf1c0aSAshish Jangam } 239*08bf1c0aSAshish Jangam 240*08bf1c0aSAshish Jangam static int da9052_set_ldo_voltage(struct regulator_dev *rdev, 241*08bf1c0aSAshish Jangam int min_uV, int max_uV, 242*08bf1c0aSAshish Jangam unsigned int *selector) 243*08bf1c0aSAshish Jangam { 244*08bf1c0aSAshish Jangam return da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector); 245*08bf1c0aSAshish Jangam } 246*08bf1c0aSAshish Jangam 247*08bf1c0aSAshish Jangam static int da9052_set_ldo5_6_voltage(struct regulator_dev *rdev, 248*08bf1c0aSAshish Jangam int min_uV, int max_uV, 249*08bf1c0aSAshish Jangam unsigned int *selector) 250*08bf1c0aSAshish Jangam { 251*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 252*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 253*08bf1c0aSAshish Jangam int ret; 254*08bf1c0aSAshish Jangam 255*08bf1c0aSAshish Jangam ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector); 256*08bf1c0aSAshish Jangam if (ret < 0) 257*08bf1c0aSAshish Jangam return ret; 258*08bf1c0aSAshish Jangam 259*08bf1c0aSAshish Jangam /* Some LDOs are DVC controlled which requires enabling of 260*08bf1c0aSAshish Jangam * the LDO activate bit to implment the changes on the 261*08bf1c0aSAshish Jangam * LDO output. 262*08bf1c0aSAshish Jangam */ 263*08bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 0, 264*08bf1c0aSAshish Jangam info->activate_bit); 265*08bf1c0aSAshish Jangam } 266*08bf1c0aSAshish Jangam 267*08bf1c0aSAshish Jangam static int da9052_set_dcdc_voltage(struct regulator_dev *rdev, 268*08bf1c0aSAshish Jangam int min_uV, int max_uV, 269*08bf1c0aSAshish Jangam unsigned int *selector) 270*08bf1c0aSAshish Jangam { 271*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 272*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 273*08bf1c0aSAshish Jangam int ret; 274*08bf1c0aSAshish Jangam 275*08bf1c0aSAshish Jangam ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector); 276*08bf1c0aSAshish Jangam if (ret < 0) 277*08bf1c0aSAshish Jangam return ret; 278*08bf1c0aSAshish Jangam 279*08bf1c0aSAshish Jangam /* Some DCDCs are DVC controlled which requires enabling of 280*08bf1c0aSAshish Jangam * the DCDC activate bit to implment the changes on the 281*08bf1c0aSAshish Jangam * DCDC output. 282*08bf1c0aSAshish Jangam */ 283*08bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 0, 284*08bf1c0aSAshish Jangam info->activate_bit); 285*08bf1c0aSAshish Jangam } 286*08bf1c0aSAshish Jangam 287*08bf1c0aSAshish Jangam static int da9052_get_regulator_voltage_sel(struct regulator_dev *rdev) 288*08bf1c0aSAshish Jangam { 289*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 290*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 291*08bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 292*08bf1c0aSAshish Jangam int ret; 293*08bf1c0aSAshish Jangam 294*08bf1c0aSAshish Jangam ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset); 295*08bf1c0aSAshish Jangam if (ret < 0) 296*08bf1c0aSAshish Jangam return ret; 297*08bf1c0aSAshish Jangam 298*08bf1c0aSAshish Jangam ret &= ((1 << info->volt_shift) - 1); 299*08bf1c0aSAshish Jangam 300*08bf1c0aSAshish Jangam return ret; 301*08bf1c0aSAshish Jangam } 302*08bf1c0aSAshish Jangam 303*08bf1c0aSAshish Jangam static int da9052_set_buckperi_voltage(struct regulator_dev *rdev, int min_uV, 304*08bf1c0aSAshish Jangam int max_uV, unsigned int *selector) 305*08bf1c0aSAshish Jangam { 306*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 307*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 308*08bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 309*08bf1c0aSAshish Jangam int ret; 310*08bf1c0aSAshish Jangam 311*08bf1c0aSAshish Jangam ret = verify_range(info, min_uV, max_uV); 312*08bf1c0aSAshish Jangam if (ret < 0) 313*08bf1c0aSAshish Jangam return ret; 314*08bf1c0aSAshish Jangam 315*08bf1c0aSAshish Jangam if (min_uV < info->min_uV) 316*08bf1c0aSAshish Jangam min_uV = info->min_uV; 317*08bf1c0aSAshish Jangam 318*08bf1c0aSAshish Jangam if ((regulator->da9052->chip_id == DA9052) && 319*08bf1c0aSAshish Jangam (min_uV >= DA9052_CONST_3uV)) 320*08bf1c0aSAshish Jangam *selector = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV + 321*08bf1c0aSAshish Jangam ((min_uV - DA9052_CONST_3uV) / 322*08bf1c0aSAshish Jangam (DA9052_BUCK_PERI_3uV_STEP)); 323*08bf1c0aSAshish Jangam else 324*08bf1c0aSAshish Jangam *selector = (min_uV - info->min_uV) / info->step_uV; 325*08bf1c0aSAshish Jangam 326*08bf1c0aSAshish Jangam ret = da9052_list_buckperi_voltage(rdev, *selector); 327*08bf1c0aSAshish Jangam if (ret < 0) 328*08bf1c0aSAshish Jangam return ret; 329*08bf1c0aSAshish Jangam 330*08bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, 331*08bf1c0aSAshish Jangam DA9052_BUCKCORE_REG + offset, 332*08bf1c0aSAshish Jangam (1 << info->volt_shift) - 1, *selector); 333*08bf1c0aSAshish Jangam } 334*08bf1c0aSAshish Jangam 335*08bf1c0aSAshish Jangam static int da9052_get_buckperi_voltage_sel(struct regulator_dev *rdev) 336*08bf1c0aSAshish Jangam { 337*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 338*08bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 339*08bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 340*08bf1c0aSAshish Jangam int ret; 341*08bf1c0aSAshish Jangam 342*08bf1c0aSAshish Jangam ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset); 343*08bf1c0aSAshish Jangam if (ret < 0) 344*08bf1c0aSAshish Jangam return ret; 345*08bf1c0aSAshish Jangam 346*08bf1c0aSAshish Jangam ret &= ((1 << info->volt_shift) - 1); 347*08bf1c0aSAshish Jangam 348*08bf1c0aSAshish Jangam return ret; 349*08bf1c0aSAshish Jangam } 350*08bf1c0aSAshish Jangam 351*08bf1c0aSAshish Jangam static struct regulator_ops da9052_buckperi_ops = { 352*08bf1c0aSAshish Jangam .list_voltage = da9052_list_buckperi_voltage, 353*08bf1c0aSAshish Jangam .get_voltage_sel = da9052_get_buckperi_voltage_sel, 354*08bf1c0aSAshish Jangam .set_voltage = da9052_set_buckperi_voltage, 355*08bf1c0aSAshish Jangam 356*08bf1c0aSAshish Jangam .get_current_limit = da9052_dcdc_get_current_limit, 357*08bf1c0aSAshish Jangam .set_current_limit = da9052_dcdc_set_current_limit, 358*08bf1c0aSAshish Jangam 359*08bf1c0aSAshish Jangam .is_enabled = da9052_regulator_is_enabled, 360*08bf1c0aSAshish Jangam .enable = da9052_regulator_enable, 361*08bf1c0aSAshish Jangam .disable = da9052_regulator_disable, 362*08bf1c0aSAshish Jangam }; 363*08bf1c0aSAshish Jangam 364*08bf1c0aSAshish Jangam static struct regulator_ops da9052_dcdc_ops = { 365*08bf1c0aSAshish Jangam .set_voltage = da9052_set_dcdc_voltage, 366*08bf1c0aSAshish Jangam .get_current_limit = da9052_dcdc_get_current_limit, 367*08bf1c0aSAshish Jangam .set_current_limit = da9052_dcdc_set_current_limit, 368*08bf1c0aSAshish Jangam 369*08bf1c0aSAshish Jangam .list_voltage = da9052_list_voltage, 370*08bf1c0aSAshish Jangam .get_voltage_sel = da9052_get_regulator_voltage_sel, 371*08bf1c0aSAshish Jangam .is_enabled = da9052_regulator_is_enabled, 372*08bf1c0aSAshish Jangam .enable = da9052_regulator_enable, 373*08bf1c0aSAshish Jangam .disable = da9052_regulator_disable, 374*08bf1c0aSAshish Jangam }; 375*08bf1c0aSAshish Jangam 376*08bf1c0aSAshish Jangam static struct regulator_ops da9052_ldo5_6_ops = { 377*08bf1c0aSAshish Jangam .set_voltage = da9052_set_ldo5_6_voltage, 378*08bf1c0aSAshish Jangam 379*08bf1c0aSAshish Jangam .list_voltage = da9052_list_voltage, 380*08bf1c0aSAshish Jangam .get_voltage_sel = da9052_get_regulator_voltage_sel, 381*08bf1c0aSAshish Jangam .is_enabled = da9052_regulator_is_enabled, 382*08bf1c0aSAshish Jangam .enable = da9052_regulator_enable, 383*08bf1c0aSAshish Jangam .disable = da9052_regulator_disable, 384*08bf1c0aSAshish Jangam }; 385*08bf1c0aSAshish Jangam 386*08bf1c0aSAshish Jangam static struct regulator_ops da9052_ldo_ops = { 387*08bf1c0aSAshish Jangam .set_voltage = da9052_set_ldo_voltage, 388*08bf1c0aSAshish Jangam 389*08bf1c0aSAshish Jangam .list_voltage = da9052_list_voltage, 390*08bf1c0aSAshish Jangam .get_voltage_sel = da9052_get_regulator_voltage_sel, 391*08bf1c0aSAshish Jangam .is_enabled = da9052_regulator_is_enabled, 392*08bf1c0aSAshish Jangam .enable = da9052_regulator_enable, 393*08bf1c0aSAshish Jangam .disable = da9052_regulator_disable, 394*08bf1c0aSAshish Jangam }; 395*08bf1c0aSAshish Jangam 396*08bf1c0aSAshish Jangam #define DA9052_LDO5_6(_id, step, min, max, sbits, ebits, abits) \ 397*08bf1c0aSAshish Jangam {\ 398*08bf1c0aSAshish Jangam .reg_desc = {\ 399*08bf1c0aSAshish Jangam .name = "LDO" #_id,\ 400*08bf1c0aSAshish Jangam .ops = &da9052_ldo5_6_ops,\ 401*08bf1c0aSAshish Jangam .type = REGULATOR_VOLTAGE,\ 402*08bf1c0aSAshish Jangam .id = _id,\ 403*08bf1c0aSAshish Jangam .owner = THIS_MODULE,\ 404*08bf1c0aSAshish Jangam },\ 405*08bf1c0aSAshish Jangam .min_uV = (min) * 1000,\ 406*08bf1c0aSAshish Jangam .max_uV = (max) * 1000,\ 407*08bf1c0aSAshish Jangam .step_uV = (step) * 1000,\ 408*08bf1c0aSAshish Jangam .volt_shift = (sbits),\ 409*08bf1c0aSAshish Jangam .en_bit = (ebits),\ 410*08bf1c0aSAshish Jangam .activate_bit = (abits),\ 411*08bf1c0aSAshish Jangam } 412*08bf1c0aSAshish Jangam 413*08bf1c0aSAshish Jangam #define DA9052_LDO(_id, step, min, max, sbits, ebits, abits) \ 414*08bf1c0aSAshish Jangam {\ 415*08bf1c0aSAshish Jangam .reg_desc = {\ 416*08bf1c0aSAshish Jangam .name = "LDO" #_id,\ 417*08bf1c0aSAshish Jangam .ops = &da9052_ldo_ops,\ 418*08bf1c0aSAshish Jangam .type = REGULATOR_VOLTAGE,\ 419*08bf1c0aSAshish Jangam .id = _id,\ 420*08bf1c0aSAshish Jangam .owner = THIS_MODULE,\ 421*08bf1c0aSAshish Jangam },\ 422*08bf1c0aSAshish Jangam .min_uV = (min) * 1000,\ 423*08bf1c0aSAshish Jangam .max_uV = (max) * 1000,\ 424*08bf1c0aSAshish Jangam .step_uV = (step) * 1000,\ 425*08bf1c0aSAshish Jangam .volt_shift = (sbits),\ 426*08bf1c0aSAshish Jangam .en_bit = (ebits),\ 427*08bf1c0aSAshish Jangam .activate_bit = (abits),\ 428*08bf1c0aSAshish Jangam } 429*08bf1c0aSAshish Jangam 430*08bf1c0aSAshish Jangam #define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ 431*08bf1c0aSAshish Jangam {\ 432*08bf1c0aSAshish Jangam .reg_desc = {\ 433*08bf1c0aSAshish Jangam .name = "BUCK" #_id,\ 434*08bf1c0aSAshish Jangam .ops = &da9052_dcdc_ops,\ 435*08bf1c0aSAshish Jangam .type = REGULATOR_VOLTAGE,\ 436*08bf1c0aSAshish Jangam .id = _id,\ 437*08bf1c0aSAshish Jangam .owner = THIS_MODULE,\ 438*08bf1c0aSAshish Jangam },\ 439*08bf1c0aSAshish Jangam .min_uV = (min) * 1000,\ 440*08bf1c0aSAshish Jangam .max_uV = (max) * 1000,\ 441*08bf1c0aSAshish Jangam .step_uV = (step) * 1000,\ 442*08bf1c0aSAshish Jangam .volt_shift = (sbits),\ 443*08bf1c0aSAshish Jangam .en_bit = (ebits),\ 444*08bf1c0aSAshish Jangam .activate_bit = (abits),\ 445*08bf1c0aSAshish Jangam } 446*08bf1c0aSAshish Jangam 447*08bf1c0aSAshish Jangam #define DA9052_BUCKPERI(_id, step, min, max, sbits, ebits, abits) \ 448*08bf1c0aSAshish Jangam {\ 449*08bf1c0aSAshish Jangam .reg_desc = {\ 450*08bf1c0aSAshish Jangam .name = "BUCK" #_id,\ 451*08bf1c0aSAshish Jangam .ops = &da9052_buckperi_ops,\ 452*08bf1c0aSAshish Jangam .type = REGULATOR_VOLTAGE,\ 453*08bf1c0aSAshish Jangam .id = _id,\ 454*08bf1c0aSAshish Jangam .owner = THIS_MODULE,\ 455*08bf1c0aSAshish Jangam },\ 456*08bf1c0aSAshish Jangam .min_uV = (min) * 1000,\ 457*08bf1c0aSAshish Jangam .max_uV = (max) * 1000,\ 458*08bf1c0aSAshish Jangam .step_uV = (step) * 1000,\ 459*08bf1c0aSAshish Jangam .volt_shift = (sbits),\ 460*08bf1c0aSAshish Jangam .en_bit = (ebits),\ 461*08bf1c0aSAshish Jangam .activate_bit = (abits),\ 462*08bf1c0aSAshish Jangam } 463*08bf1c0aSAshish Jangam 464*08bf1c0aSAshish Jangam struct da9052_regulator_info da9052_regulator_info[] = { 465*08bf1c0aSAshish Jangam /* Buck1 - 4 */ 466*08bf1c0aSAshish Jangam DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), 467*08bf1c0aSAshish Jangam DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), 468*08bf1c0aSAshish Jangam DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), 469*08bf1c0aSAshish Jangam DA9052_BUCKPERI(3, 50, 1800, 3600, 5, 6, 0), 470*08bf1c0aSAshish Jangam /* LD01 - LDO10 */ 471*08bf1c0aSAshish Jangam DA9052_LDO(4, 50, 600, 1800, 5, 6, 0), 472*08bf1c0aSAshish Jangam DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), 473*08bf1c0aSAshish Jangam DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), 474*08bf1c0aSAshish Jangam DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0), 475*08bf1c0aSAshish Jangam DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0), 476*08bf1c0aSAshish Jangam DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0), 477*08bf1c0aSAshish Jangam DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0), 478*08bf1c0aSAshish Jangam DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0), 479*08bf1c0aSAshish Jangam DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0), 480*08bf1c0aSAshish Jangam DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0), 481*08bf1c0aSAshish Jangam }; 482*08bf1c0aSAshish Jangam 483*08bf1c0aSAshish Jangam struct da9052_regulator_info da9053_regulator_info[] = { 484*08bf1c0aSAshish Jangam /* Buck1 - 4 */ 485*08bf1c0aSAshish Jangam DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), 486*08bf1c0aSAshish Jangam DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), 487*08bf1c0aSAshish Jangam DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), 488*08bf1c0aSAshish Jangam DA9052_BUCKPERI(3, 25, 925, 2500, 6, 6, 0), 489*08bf1c0aSAshish Jangam /* LD01 - LDO10 */ 490*08bf1c0aSAshish Jangam DA9052_LDO(4, 50, 600, 1800, 5, 6, 0), 491*08bf1c0aSAshish Jangam DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), 492*08bf1c0aSAshish Jangam DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), 493*08bf1c0aSAshish Jangam DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0), 494*08bf1c0aSAshish Jangam DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0), 495*08bf1c0aSAshish Jangam DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0), 496*08bf1c0aSAshish Jangam DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0), 497*08bf1c0aSAshish Jangam DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0), 498*08bf1c0aSAshish Jangam DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0), 499*08bf1c0aSAshish Jangam DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0), 500*08bf1c0aSAshish Jangam }; 501*08bf1c0aSAshish Jangam 502*08bf1c0aSAshish Jangam static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, 503*08bf1c0aSAshish Jangam int id) 504*08bf1c0aSAshish Jangam { 505*08bf1c0aSAshish Jangam struct da9052_regulator_info *info; 506*08bf1c0aSAshish Jangam int i; 507*08bf1c0aSAshish Jangam 508*08bf1c0aSAshish Jangam if (chip_id == DA9052) { 509*08bf1c0aSAshish Jangam for (i = 0; i < ARRAY_SIZE(da9052_regulator_info); i++) { 510*08bf1c0aSAshish Jangam info = &da9052_regulator_info[i]; 511*08bf1c0aSAshish Jangam if (info->reg_desc.id == id) 512*08bf1c0aSAshish Jangam return info; 513*08bf1c0aSAshish Jangam } 514*08bf1c0aSAshish Jangam } else { 515*08bf1c0aSAshish Jangam for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) { 516*08bf1c0aSAshish Jangam info = &da9053_regulator_info[i]; 517*08bf1c0aSAshish Jangam if (info->reg_desc.id == id) 518*08bf1c0aSAshish Jangam return info; 519*08bf1c0aSAshish Jangam } 520*08bf1c0aSAshish Jangam } 521*08bf1c0aSAshish Jangam 522*08bf1c0aSAshish Jangam return NULL; 523*08bf1c0aSAshish Jangam } 524*08bf1c0aSAshish Jangam 525*08bf1c0aSAshish Jangam static int __devinit da9052_regulator_probe(struct platform_device *pdev) 526*08bf1c0aSAshish Jangam { 527*08bf1c0aSAshish Jangam struct da9052_regulator *regulator; 528*08bf1c0aSAshish Jangam struct da9052 *da9052; 529*08bf1c0aSAshish Jangam struct da9052_pdata *pdata; 530*08bf1c0aSAshish Jangam int ret; 531*08bf1c0aSAshish Jangam 532*08bf1c0aSAshish Jangam regulator = kzalloc(sizeof(struct da9052_regulator), GFP_KERNEL); 533*08bf1c0aSAshish Jangam if (!regulator) 534*08bf1c0aSAshish Jangam return -ENOMEM; 535*08bf1c0aSAshish Jangam 536*08bf1c0aSAshish Jangam da9052 = dev_get_drvdata(pdev->dev.parent); 537*08bf1c0aSAshish Jangam pdata = da9052->dev->platform_data; 538*08bf1c0aSAshish Jangam regulator->da9052 = da9052; 539*08bf1c0aSAshish Jangam 540*08bf1c0aSAshish Jangam regulator->info = find_regulator_info(regulator->da9052->chip_id, 541*08bf1c0aSAshish Jangam pdev->id); 542*08bf1c0aSAshish Jangam if (regulator->info == NULL) { 543*08bf1c0aSAshish Jangam dev_err(&pdev->dev, "invalid regulator ID specified\n"); 544*08bf1c0aSAshish Jangam ret = -EINVAL; 545*08bf1c0aSAshish Jangam goto err; 546*08bf1c0aSAshish Jangam } 547*08bf1c0aSAshish Jangam regulator->rdev = regulator_register(®ulator->info->reg_desc, 548*08bf1c0aSAshish Jangam &pdev->dev, 549*08bf1c0aSAshish Jangam pdata->regulators[pdev->id], 550*08bf1c0aSAshish Jangam regulator); 551*08bf1c0aSAshish Jangam if (IS_ERR(regulator->rdev)) { 552*08bf1c0aSAshish Jangam dev_err(&pdev->dev, "failed to register regulator %s\n", 553*08bf1c0aSAshish Jangam regulator->info->reg_desc.name); 554*08bf1c0aSAshish Jangam ret = PTR_ERR(regulator->rdev); 555*08bf1c0aSAshish Jangam goto err; 556*08bf1c0aSAshish Jangam } 557*08bf1c0aSAshish Jangam 558*08bf1c0aSAshish Jangam platform_set_drvdata(pdev, regulator); 559*08bf1c0aSAshish Jangam 560*08bf1c0aSAshish Jangam return 0; 561*08bf1c0aSAshish Jangam err: 562*08bf1c0aSAshish Jangam kfree(regulator); 563*08bf1c0aSAshish Jangam return ret; 564*08bf1c0aSAshish Jangam } 565*08bf1c0aSAshish Jangam 566*08bf1c0aSAshish Jangam static int __devexit da9052_regulator_remove(struct platform_device *pdev) 567*08bf1c0aSAshish Jangam { 568*08bf1c0aSAshish Jangam struct da9052_regulator *regulator = platform_get_drvdata(pdev); 569*08bf1c0aSAshish Jangam 570*08bf1c0aSAshish Jangam regulator_unregister(regulator->rdev); 571*08bf1c0aSAshish Jangam kfree(regulator); 572*08bf1c0aSAshish Jangam 573*08bf1c0aSAshish Jangam return 0; 574*08bf1c0aSAshish Jangam } 575*08bf1c0aSAshish Jangam 576*08bf1c0aSAshish Jangam static struct platform_driver da9052_regulator_driver = { 577*08bf1c0aSAshish Jangam .probe = da9052_regulator_probe, 578*08bf1c0aSAshish Jangam .remove = __devexit_p(da9052_regulator_remove), 579*08bf1c0aSAshish Jangam .driver = { 580*08bf1c0aSAshish Jangam .name = "da9052-regulator", 581*08bf1c0aSAshish Jangam .owner = THIS_MODULE, 582*08bf1c0aSAshish Jangam }, 583*08bf1c0aSAshish Jangam }; 584*08bf1c0aSAshish Jangam 585*08bf1c0aSAshish Jangam static int __init da9052_regulator_init(void) 586*08bf1c0aSAshish Jangam { 587*08bf1c0aSAshish Jangam return platform_driver_register(&da9052_regulator_driver); 588*08bf1c0aSAshish Jangam } 589*08bf1c0aSAshish Jangam subsys_initcall(da9052_regulator_init); 590*08bf1c0aSAshish Jangam 591*08bf1c0aSAshish Jangam static void __exit da9052_regulator_exit(void) 592*08bf1c0aSAshish Jangam { 593*08bf1c0aSAshish Jangam platform_driver_unregister(&da9052_regulator_driver); 594*08bf1c0aSAshish Jangam } 595*08bf1c0aSAshish Jangam module_exit(da9052_regulator_exit); 596*08bf1c0aSAshish Jangam 597*08bf1c0aSAshish Jangam MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 598*08bf1c0aSAshish Jangam MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC"); 599*08bf1c0aSAshish Jangam MODULE_LICENSE("GPL"); 600*08bf1c0aSAshish Jangam MODULE_ALIAS("platform:da9052-regulator"); 601