1*08ff6f2aSHaojian Zhuang /* 2*08ff6f2aSHaojian Zhuang * Regulators driver for Maxim max8925 3*08ff6f2aSHaojian Zhuang * 4*08ff6f2aSHaojian Zhuang * Copyright (C) 2009 Marvell International Ltd. 5*08ff6f2aSHaojian Zhuang * Haojian Zhuang <haojian.zhuang@marvell.com> 6*08ff6f2aSHaojian Zhuang * 7*08ff6f2aSHaojian Zhuang * This program is free software; you can redistribute it and/or modify 8*08ff6f2aSHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 9*08ff6f2aSHaojian Zhuang * published by the Free Software Foundation. 10*08ff6f2aSHaojian Zhuang */ 11*08ff6f2aSHaojian Zhuang #include <linux/kernel.h> 12*08ff6f2aSHaojian Zhuang #include <linux/init.h> 13*08ff6f2aSHaojian Zhuang #include <linux/err.h> 14*08ff6f2aSHaojian Zhuang #include <linux/i2c.h> 15*08ff6f2aSHaojian Zhuang #include <linux/platform_device.h> 16*08ff6f2aSHaojian Zhuang #include <linux/regulator/driver.h> 17*08ff6f2aSHaojian Zhuang #include <linux/regulator/machine.h> 18*08ff6f2aSHaojian Zhuang #include <linux/mfd/max8925.h> 19*08ff6f2aSHaojian Zhuang 20*08ff6f2aSHaojian Zhuang #define SD1_DVM_VMIN 850000 21*08ff6f2aSHaojian Zhuang #define SD1_DVM_VMAX 1000000 22*08ff6f2aSHaojian Zhuang #define SD1_DVM_STEP 50000 23*08ff6f2aSHaojian Zhuang #define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */ 24*08ff6f2aSHaojian Zhuang #define SD1_DVM_EN 6 /* SDV1 bit 6 */ 25*08ff6f2aSHaojian Zhuang 26*08ff6f2aSHaojian Zhuang struct max8925_regulator_info { 27*08ff6f2aSHaojian Zhuang struct regulator_desc desc; 28*08ff6f2aSHaojian Zhuang struct regulator_dev *regulator; 29*08ff6f2aSHaojian Zhuang struct i2c_client *i2c; 30*08ff6f2aSHaojian Zhuang struct max8925_chip *chip; 31*08ff6f2aSHaojian Zhuang 32*08ff6f2aSHaojian Zhuang int min_uV; 33*08ff6f2aSHaojian Zhuang int max_uV; 34*08ff6f2aSHaojian Zhuang int step_uV; 35*08ff6f2aSHaojian Zhuang int vol_reg; 36*08ff6f2aSHaojian Zhuang int vol_shift; 37*08ff6f2aSHaojian Zhuang int vol_nbits; 38*08ff6f2aSHaojian Zhuang int enable_bit; 39*08ff6f2aSHaojian Zhuang int enable_reg; 40*08ff6f2aSHaojian Zhuang }; 41*08ff6f2aSHaojian Zhuang 42*08ff6f2aSHaojian Zhuang static inline int check_range(struct max8925_regulator_info *info, 43*08ff6f2aSHaojian Zhuang int min_uV, int max_uV) 44*08ff6f2aSHaojian Zhuang { 45*08ff6f2aSHaojian Zhuang if (min_uV < info->min_uV || min_uV > info->max_uV) 46*08ff6f2aSHaojian Zhuang return -EINVAL; 47*08ff6f2aSHaojian Zhuang 48*08ff6f2aSHaojian Zhuang return 0; 49*08ff6f2aSHaojian Zhuang } 50*08ff6f2aSHaojian Zhuang 51*08ff6f2aSHaojian Zhuang static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index) 52*08ff6f2aSHaojian Zhuang { 53*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *info = rdev_get_drvdata(rdev); 54*08ff6f2aSHaojian Zhuang return info->min_uV + index * info->step_uV; 55*08ff6f2aSHaojian Zhuang } 56*08ff6f2aSHaojian Zhuang 57*08ff6f2aSHaojian Zhuang static int max8925_set_voltage(struct regulator_dev *rdev, 58*08ff6f2aSHaojian Zhuang int min_uV, int max_uV) 59*08ff6f2aSHaojian Zhuang { 60*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *info = rdev_get_drvdata(rdev); 61*08ff6f2aSHaojian Zhuang unsigned char data, mask; 62*08ff6f2aSHaojian Zhuang 63*08ff6f2aSHaojian Zhuang if (check_range(info, min_uV, max_uV)) { 64*08ff6f2aSHaojian Zhuang dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n", 65*08ff6f2aSHaojian Zhuang min_uV, max_uV); 66*08ff6f2aSHaojian Zhuang return -EINVAL; 67*08ff6f2aSHaojian Zhuang } 68*08ff6f2aSHaojian Zhuang data = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; 69*08ff6f2aSHaojian Zhuang data <<= info->vol_shift; 70*08ff6f2aSHaojian Zhuang mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; 71*08ff6f2aSHaojian Zhuang 72*08ff6f2aSHaojian Zhuang return max8925_set_bits(info->i2c, info->vol_reg, mask, data); 73*08ff6f2aSHaojian Zhuang } 74*08ff6f2aSHaojian Zhuang 75*08ff6f2aSHaojian Zhuang static int max8925_get_voltage(struct regulator_dev *rdev) 76*08ff6f2aSHaojian Zhuang { 77*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *info = rdev_get_drvdata(rdev); 78*08ff6f2aSHaojian Zhuang unsigned char data, mask; 79*08ff6f2aSHaojian Zhuang int ret; 80*08ff6f2aSHaojian Zhuang 81*08ff6f2aSHaojian Zhuang ret = max8925_reg_read(info->i2c, info->vol_reg); 82*08ff6f2aSHaojian Zhuang if (ret < 0) 83*08ff6f2aSHaojian Zhuang return ret; 84*08ff6f2aSHaojian Zhuang mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; 85*08ff6f2aSHaojian Zhuang data = (ret & mask) >> info->vol_shift; 86*08ff6f2aSHaojian Zhuang 87*08ff6f2aSHaojian Zhuang return max8925_list_voltage(rdev, data); 88*08ff6f2aSHaojian Zhuang } 89*08ff6f2aSHaojian Zhuang 90*08ff6f2aSHaojian Zhuang static int max8925_enable(struct regulator_dev *rdev) 91*08ff6f2aSHaojian Zhuang { 92*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *info = rdev_get_drvdata(rdev); 93*08ff6f2aSHaojian Zhuang 94*08ff6f2aSHaojian Zhuang return max8925_set_bits(info->i2c, info->enable_reg, 95*08ff6f2aSHaojian Zhuang 1 << info->enable_bit, 96*08ff6f2aSHaojian Zhuang 1 << info->enable_bit); 97*08ff6f2aSHaojian Zhuang } 98*08ff6f2aSHaojian Zhuang 99*08ff6f2aSHaojian Zhuang static int max8925_disable(struct regulator_dev *rdev) 100*08ff6f2aSHaojian Zhuang { 101*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *info = rdev_get_drvdata(rdev); 102*08ff6f2aSHaojian Zhuang 103*08ff6f2aSHaojian Zhuang return max8925_set_bits(info->i2c, info->enable_reg, 104*08ff6f2aSHaojian Zhuang 1 << info->enable_bit, 0); 105*08ff6f2aSHaojian Zhuang } 106*08ff6f2aSHaojian Zhuang 107*08ff6f2aSHaojian Zhuang static int max8925_is_enabled(struct regulator_dev *rdev) 108*08ff6f2aSHaojian Zhuang { 109*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *info = rdev_get_drvdata(rdev); 110*08ff6f2aSHaojian Zhuang int ret; 111*08ff6f2aSHaojian Zhuang 112*08ff6f2aSHaojian Zhuang ret = max8925_reg_read(info->i2c, info->vol_reg); 113*08ff6f2aSHaojian Zhuang if (ret < 0) 114*08ff6f2aSHaojian Zhuang return ret; 115*08ff6f2aSHaojian Zhuang 116*08ff6f2aSHaojian Zhuang return ret & (1 << info->enable_bit); 117*08ff6f2aSHaojian Zhuang } 118*08ff6f2aSHaojian Zhuang 119*08ff6f2aSHaojian Zhuang static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV) 120*08ff6f2aSHaojian Zhuang { 121*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *info = rdev_get_drvdata(rdev); 122*08ff6f2aSHaojian Zhuang unsigned char data, mask; 123*08ff6f2aSHaojian Zhuang 124*08ff6f2aSHaojian Zhuang if (uV < SD1_DVM_VMIN || uV > SD1_DVM_VMAX) 125*08ff6f2aSHaojian Zhuang return -EINVAL; 126*08ff6f2aSHaojian Zhuang 127*08ff6f2aSHaojian Zhuang data = (uV - SD1_DVM_VMIN + SD1_DVM_STEP - 1) / SD1_DVM_STEP; 128*08ff6f2aSHaojian Zhuang data <<= SD1_DVM_SHIFT; 129*08ff6f2aSHaojian Zhuang mask = 3 << SD1_DVM_SHIFT; 130*08ff6f2aSHaojian Zhuang 131*08ff6f2aSHaojian Zhuang return max8925_set_bits(info->i2c, info->enable_reg, mask, data); 132*08ff6f2aSHaojian Zhuang } 133*08ff6f2aSHaojian Zhuang 134*08ff6f2aSHaojian Zhuang static int max8925_set_dvm_enable(struct regulator_dev *rdev) 135*08ff6f2aSHaojian Zhuang { 136*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *info = rdev_get_drvdata(rdev); 137*08ff6f2aSHaojian Zhuang 138*08ff6f2aSHaojian Zhuang return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, 139*08ff6f2aSHaojian Zhuang 1 << SD1_DVM_EN); 140*08ff6f2aSHaojian Zhuang } 141*08ff6f2aSHaojian Zhuang 142*08ff6f2aSHaojian Zhuang static int max8925_set_dvm_disable(struct regulator_dev *rdev) 143*08ff6f2aSHaojian Zhuang { 144*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *info = rdev_get_drvdata(rdev); 145*08ff6f2aSHaojian Zhuang 146*08ff6f2aSHaojian Zhuang return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, 0); 147*08ff6f2aSHaojian Zhuang } 148*08ff6f2aSHaojian Zhuang 149*08ff6f2aSHaojian Zhuang static struct regulator_ops max8925_regulator_sdv_ops = { 150*08ff6f2aSHaojian Zhuang .set_voltage = max8925_set_voltage, 151*08ff6f2aSHaojian Zhuang .get_voltage = max8925_get_voltage, 152*08ff6f2aSHaojian Zhuang .enable = max8925_enable, 153*08ff6f2aSHaojian Zhuang .disable = max8925_disable, 154*08ff6f2aSHaojian Zhuang .is_enabled = max8925_is_enabled, 155*08ff6f2aSHaojian Zhuang .set_suspend_voltage = max8925_set_dvm_voltage, 156*08ff6f2aSHaojian Zhuang .set_suspend_enable = max8925_set_dvm_enable, 157*08ff6f2aSHaojian Zhuang .set_suspend_disable = max8925_set_dvm_disable, 158*08ff6f2aSHaojian Zhuang }; 159*08ff6f2aSHaojian Zhuang 160*08ff6f2aSHaojian Zhuang static struct regulator_ops max8925_regulator_ldo_ops = { 161*08ff6f2aSHaojian Zhuang .set_voltage = max8925_set_voltage, 162*08ff6f2aSHaojian Zhuang .get_voltage = max8925_get_voltage, 163*08ff6f2aSHaojian Zhuang .enable = max8925_enable, 164*08ff6f2aSHaojian Zhuang .disable = max8925_disable, 165*08ff6f2aSHaojian Zhuang .is_enabled = max8925_is_enabled, 166*08ff6f2aSHaojian Zhuang }; 167*08ff6f2aSHaojian Zhuang 168*08ff6f2aSHaojian Zhuang #define MAX8925_SDV(_id, min, max, step) \ 169*08ff6f2aSHaojian Zhuang { \ 170*08ff6f2aSHaojian Zhuang .desc = { \ 171*08ff6f2aSHaojian Zhuang .name = "SDV" #_id, \ 172*08ff6f2aSHaojian Zhuang .ops = &max8925_regulator_sdv_ops, \ 173*08ff6f2aSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 174*08ff6f2aSHaojian Zhuang .id = MAX8925_ID_SD##_id, \ 175*08ff6f2aSHaojian Zhuang .owner = THIS_MODULE, \ 176*08ff6f2aSHaojian Zhuang }, \ 177*08ff6f2aSHaojian Zhuang .min_uV = min * 1000, \ 178*08ff6f2aSHaojian Zhuang .max_uV = max * 1000, \ 179*08ff6f2aSHaojian Zhuang .step_uV = step * 1000, \ 180*08ff6f2aSHaojian Zhuang .vol_reg = MAX8925_SDV##_id, \ 181*08ff6f2aSHaojian Zhuang .vol_shift = 0, \ 182*08ff6f2aSHaojian Zhuang .vol_nbits = 6, \ 183*08ff6f2aSHaojian Zhuang .enable_reg = MAX8925_SDCTL##_id, \ 184*08ff6f2aSHaojian Zhuang .enable_bit = 0, \ 185*08ff6f2aSHaojian Zhuang } 186*08ff6f2aSHaojian Zhuang 187*08ff6f2aSHaojian Zhuang #define MAX8925_LDO(_id, min, max, step) \ 188*08ff6f2aSHaojian Zhuang { \ 189*08ff6f2aSHaojian Zhuang .desc = { \ 190*08ff6f2aSHaojian Zhuang .name = "LDO" #_id, \ 191*08ff6f2aSHaojian Zhuang .ops = &max8925_regulator_ldo_ops, \ 192*08ff6f2aSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 193*08ff6f2aSHaojian Zhuang .id = MAX8925_ID_LDO##_id, \ 194*08ff6f2aSHaojian Zhuang .owner = THIS_MODULE, \ 195*08ff6f2aSHaojian Zhuang }, \ 196*08ff6f2aSHaojian Zhuang .min_uV = min * 1000, \ 197*08ff6f2aSHaojian Zhuang .max_uV = max * 1000, \ 198*08ff6f2aSHaojian Zhuang .step_uV = step * 1000, \ 199*08ff6f2aSHaojian Zhuang .vol_reg = MAX8925_LDOVOUT##_id, \ 200*08ff6f2aSHaojian Zhuang .vol_shift = 0, \ 201*08ff6f2aSHaojian Zhuang .vol_nbits = 6, \ 202*08ff6f2aSHaojian Zhuang .enable_reg = MAX8925_LDOCTL##_id, \ 203*08ff6f2aSHaojian Zhuang .enable_bit = 0, \ 204*08ff6f2aSHaojian Zhuang } 205*08ff6f2aSHaojian Zhuang 206*08ff6f2aSHaojian Zhuang static struct max8925_regulator_info max8925_regulator_info[] = { 207*08ff6f2aSHaojian Zhuang MAX8925_SDV(1, 637.5, 1425, 12.5), 208*08ff6f2aSHaojian Zhuang MAX8925_SDV(2, 650, 2225, 25), 209*08ff6f2aSHaojian Zhuang MAX8925_SDV(3, 750, 3900, 50), 210*08ff6f2aSHaojian Zhuang 211*08ff6f2aSHaojian Zhuang MAX8925_LDO(1, 750, 3900, 50), 212*08ff6f2aSHaojian Zhuang MAX8925_LDO(2, 650, 2250, 25), 213*08ff6f2aSHaojian Zhuang MAX8925_LDO(3, 650, 2250, 25), 214*08ff6f2aSHaojian Zhuang MAX8925_LDO(4, 750, 3900, 50), 215*08ff6f2aSHaojian Zhuang MAX8925_LDO(5, 750, 3900, 50), 216*08ff6f2aSHaojian Zhuang MAX8925_LDO(6, 750, 3900, 50), 217*08ff6f2aSHaojian Zhuang MAX8925_LDO(7, 750, 3900, 50), 218*08ff6f2aSHaojian Zhuang MAX8925_LDO(8, 750, 3900, 50), 219*08ff6f2aSHaojian Zhuang MAX8925_LDO(9, 750, 3900, 50), 220*08ff6f2aSHaojian Zhuang MAX8925_LDO(10, 750, 3900, 50), 221*08ff6f2aSHaojian Zhuang MAX8925_LDO(11, 750, 3900, 50), 222*08ff6f2aSHaojian Zhuang MAX8925_LDO(12, 750, 3900, 50), 223*08ff6f2aSHaojian Zhuang MAX8925_LDO(13, 750, 3900, 50), 224*08ff6f2aSHaojian Zhuang MAX8925_LDO(14, 750, 3900, 50), 225*08ff6f2aSHaojian Zhuang MAX8925_LDO(15, 750, 3900, 50), 226*08ff6f2aSHaojian Zhuang MAX8925_LDO(16, 750, 3900, 50), 227*08ff6f2aSHaojian Zhuang MAX8925_LDO(17, 650, 2250, 25), 228*08ff6f2aSHaojian Zhuang MAX8925_LDO(18, 650, 2250, 25), 229*08ff6f2aSHaojian Zhuang MAX8925_LDO(19, 750, 3900, 50), 230*08ff6f2aSHaojian Zhuang MAX8925_LDO(20, 750, 3900, 50), 231*08ff6f2aSHaojian Zhuang }; 232*08ff6f2aSHaojian Zhuang 233*08ff6f2aSHaojian Zhuang static inline struct max8925_regulator_info *find_regulator_info(int id) 234*08ff6f2aSHaojian Zhuang { 235*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *ri; 236*08ff6f2aSHaojian Zhuang int i; 237*08ff6f2aSHaojian Zhuang 238*08ff6f2aSHaojian Zhuang for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { 239*08ff6f2aSHaojian Zhuang ri = &max8925_regulator_info[i]; 240*08ff6f2aSHaojian Zhuang if (ri->desc.id == id) 241*08ff6f2aSHaojian Zhuang return ri; 242*08ff6f2aSHaojian Zhuang } 243*08ff6f2aSHaojian Zhuang return NULL; 244*08ff6f2aSHaojian Zhuang } 245*08ff6f2aSHaojian Zhuang 246*08ff6f2aSHaojian Zhuang static int __devinit max8925_regulator_probe(struct platform_device *pdev) 247*08ff6f2aSHaojian Zhuang { 248*08ff6f2aSHaojian Zhuang struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); 249*08ff6f2aSHaojian Zhuang struct max8925_platform_data *pdata = chip->dev->platform_data; 250*08ff6f2aSHaojian Zhuang struct max8925_regulator_info *ri = NULL; 251*08ff6f2aSHaojian Zhuang struct regulator_dev *rdev; 252*08ff6f2aSHaojian Zhuang 253*08ff6f2aSHaojian Zhuang ri = find_regulator_info(pdev->id); 254*08ff6f2aSHaojian Zhuang if (ri == NULL) { 255*08ff6f2aSHaojian Zhuang dev_err(&pdev->dev, "invalid regulator ID specified\n"); 256*08ff6f2aSHaojian Zhuang return -EINVAL; 257*08ff6f2aSHaojian Zhuang } 258*08ff6f2aSHaojian Zhuang ri->i2c = chip->i2c; 259*08ff6f2aSHaojian Zhuang ri->chip = chip; 260*08ff6f2aSHaojian Zhuang 261*08ff6f2aSHaojian Zhuang rdev = regulator_register(&ri->desc, &pdev->dev, 262*08ff6f2aSHaojian Zhuang pdata->regulator[pdev->id], ri); 263*08ff6f2aSHaojian Zhuang if (IS_ERR(rdev)) { 264*08ff6f2aSHaojian Zhuang dev_err(&pdev->dev, "failed to register regulator %s\n", 265*08ff6f2aSHaojian Zhuang ri->desc.name); 266*08ff6f2aSHaojian Zhuang return PTR_ERR(rdev); 267*08ff6f2aSHaojian Zhuang } 268*08ff6f2aSHaojian Zhuang 269*08ff6f2aSHaojian Zhuang platform_set_drvdata(pdev, rdev); 270*08ff6f2aSHaojian Zhuang return 0; 271*08ff6f2aSHaojian Zhuang } 272*08ff6f2aSHaojian Zhuang 273*08ff6f2aSHaojian Zhuang static int __devexit max8925_regulator_remove(struct platform_device *pdev) 274*08ff6f2aSHaojian Zhuang { 275*08ff6f2aSHaojian Zhuang struct regulator_dev *rdev = platform_get_drvdata(pdev); 276*08ff6f2aSHaojian Zhuang 277*08ff6f2aSHaojian Zhuang regulator_unregister(rdev); 278*08ff6f2aSHaojian Zhuang return 0; 279*08ff6f2aSHaojian Zhuang } 280*08ff6f2aSHaojian Zhuang 281*08ff6f2aSHaojian Zhuang static struct platform_driver max8925_regulator_driver = { 282*08ff6f2aSHaojian Zhuang .driver = { 283*08ff6f2aSHaojian Zhuang .name = "max8925-regulator", 284*08ff6f2aSHaojian Zhuang .owner = THIS_MODULE, 285*08ff6f2aSHaojian Zhuang }, 286*08ff6f2aSHaojian Zhuang .probe = max8925_regulator_probe, 287*08ff6f2aSHaojian Zhuang .remove = __devexit_p(max8925_regulator_remove), 288*08ff6f2aSHaojian Zhuang }; 289*08ff6f2aSHaojian Zhuang 290*08ff6f2aSHaojian Zhuang static int __init max8925_regulator_init(void) 291*08ff6f2aSHaojian Zhuang { 292*08ff6f2aSHaojian Zhuang return platform_driver_register(&max8925_regulator_driver); 293*08ff6f2aSHaojian Zhuang } 294*08ff6f2aSHaojian Zhuang subsys_initcall(max8925_regulator_init); 295*08ff6f2aSHaojian Zhuang 296*08ff6f2aSHaojian Zhuang static void __exit max8925_regulator_exit(void) 297*08ff6f2aSHaojian Zhuang { 298*08ff6f2aSHaojian Zhuang platform_driver_unregister(&max8925_regulator_driver); 299*08ff6f2aSHaojian Zhuang } 300*08ff6f2aSHaojian Zhuang module_exit(max8925_regulator_exit); 301*08ff6f2aSHaojian Zhuang 302*08ff6f2aSHaojian Zhuang MODULE_LICENSE("GPL"); 303*08ff6f2aSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 304*08ff6f2aSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC"); 305*08ff6f2aSHaojian Zhuang MODULE_ALIAS("platform:max8925-regulator"); 306*08ff6f2aSHaojian Zhuang 307