1be0e2d3eSHaojian Zhuang /* 2be0e2d3eSHaojian Zhuang * Regulators driver for Marvell 88PM8607 3be0e2d3eSHaojian Zhuang * 4be0e2d3eSHaojian Zhuang * Copyright (C) 2009 Marvell International Ltd. 5be0e2d3eSHaojian Zhuang * Haojian Zhuang <haojian.zhuang@marvell.com> 6be0e2d3eSHaojian Zhuang * 7be0e2d3eSHaojian Zhuang * This program is free software; you can redistribute it and/or modify 8be0e2d3eSHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 9be0e2d3eSHaojian Zhuang * published by the Free Software Foundation. 10be0e2d3eSHaojian Zhuang */ 11be0e2d3eSHaojian Zhuang #include <linux/kernel.h> 12be0e2d3eSHaojian Zhuang #include <linux/init.h> 13be0e2d3eSHaojian Zhuang #include <linux/err.h> 14*53dbab7aSHaojian Zhuang #include <linux/i2c.h> 15be0e2d3eSHaojian Zhuang #include <linux/platform_device.h> 16be0e2d3eSHaojian Zhuang #include <linux/regulator/driver.h> 17be0e2d3eSHaojian Zhuang #include <linux/regulator/machine.h> 18*53dbab7aSHaojian Zhuang #include <linux/mfd/88pm860x.h> 19be0e2d3eSHaojian Zhuang 20be0e2d3eSHaojian Zhuang struct pm8607_regulator_info { 21be0e2d3eSHaojian Zhuang struct regulator_desc desc; 22*53dbab7aSHaojian Zhuang struct pm860x_chip *chip; 23be0e2d3eSHaojian Zhuang struct regulator_dev *regulator; 24*53dbab7aSHaojian Zhuang struct i2c_client *i2c; 25be0e2d3eSHaojian Zhuang 26be0e2d3eSHaojian Zhuang int min_uV; 27be0e2d3eSHaojian Zhuang int max_uV; 28be0e2d3eSHaojian Zhuang int step_uV; 29be0e2d3eSHaojian Zhuang int vol_reg; 30be0e2d3eSHaojian Zhuang int vol_shift; 31be0e2d3eSHaojian Zhuang int vol_nbits; 32be0e2d3eSHaojian Zhuang int update_reg; 33be0e2d3eSHaojian Zhuang int update_bit; 34be0e2d3eSHaojian Zhuang int enable_reg; 35be0e2d3eSHaojian Zhuang int enable_bit; 36be0e2d3eSHaojian Zhuang int slope_double; 37be0e2d3eSHaojian Zhuang }; 38be0e2d3eSHaojian Zhuang 39be0e2d3eSHaojian Zhuang static inline int check_range(struct pm8607_regulator_info *info, 40be0e2d3eSHaojian Zhuang int min_uV, int max_uV) 41be0e2d3eSHaojian Zhuang { 42be0e2d3eSHaojian Zhuang if (max_uV < info->min_uV || min_uV > info->max_uV || min_uV > max_uV) 43be0e2d3eSHaojian Zhuang return -EINVAL; 44be0e2d3eSHaojian Zhuang 45be0e2d3eSHaojian Zhuang return 0; 46be0e2d3eSHaojian Zhuang } 47be0e2d3eSHaojian Zhuang 48be0e2d3eSHaojian Zhuang static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) 49be0e2d3eSHaojian Zhuang { 50be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 51*53dbab7aSHaojian Zhuang uint8_t chip_id = info->chip->chip_version; 52be0e2d3eSHaojian Zhuang int ret = -EINVAL; 53be0e2d3eSHaojian Zhuang 54be0e2d3eSHaojian Zhuang switch (info->desc.id) { 55be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK1: 56be0e2d3eSHaojian Zhuang ret = (index < 0x1d) ? (index * 25000 + 800000) : 57be0e2d3eSHaojian Zhuang ((index < 0x20) ? 1500000 : 58be0e2d3eSHaojian Zhuang ((index < 0x40) ? ((index - 0x20) * 25000) : 59be0e2d3eSHaojian Zhuang -EINVAL)); 60be0e2d3eSHaojian Zhuang break; 61be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK3: 62be0e2d3eSHaojian Zhuang ret = (index < 0x3d) ? (index * 25000) : 63be0e2d3eSHaojian Zhuang ((index < 0x40) ? 1500000 : -EINVAL); 64be0e2d3eSHaojian Zhuang if (ret < 0) 65be0e2d3eSHaojian Zhuang break; 66be0e2d3eSHaojian Zhuang if (info->slope_double) 67be0e2d3eSHaojian Zhuang ret <<= 1; 68be0e2d3eSHaojian Zhuang break; 69be0e2d3eSHaojian Zhuang case PM8607_ID_LDO1: 70be0e2d3eSHaojian Zhuang ret = (index == 0) ? 1800000 : 71be0e2d3eSHaojian Zhuang ((index == 1) ? 1200000 : 72be0e2d3eSHaojian Zhuang ((index == 2) ? 2800000 : -EINVAL)); 73be0e2d3eSHaojian Zhuang break; 74be0e2d3eSHaojian Zhuang case PM8607_ID_LDO5: 75be0e2d3eSHaojian Zhuang ret = (index == 0) ? 2900000 : 76be0e2d3eSHaojian Zhuang ((index == 1) ? 3000000 : 77be0e2d3eSHaojian Zhuang ((index == 2) ? 3100000 : 3300000)); 78be0e2d3eSHaojian Zhuang break; 79be0e2d3eSHaojian Zhuang case PM8607_ID_LDO7: 80be0e2d3eSHaojian Zhuang case PM8607_ID_LDO8: 81be0e2d3eSHaojian Zhuang ret = (index < 3) ? (index * 50000 + 1800000) : 82be0e2d3eSHaojian Zhuang ((index < 8) ? (index * 50000 + 2550000) : 83be0e2d3eSHaojian Zhuang -EINVAL); 84be0e2d3eSHaojian Zhuang break; 85be0e2d3eSHaojian Zhuang case PM8607_ID_LDO12: 86be0e2d3eSHaojian Zhuang ret = (index < 2) ? (index * 100000 + 1800000) : 87be0e2d3eSHaojian Zhuang ((index < 7) ? (index * 100000 + 2500000) : 88be0e2d3eSHaojian Zhuang ((index == 7) ? 3300000 : 1200000)); 89be0e2d3eSHaojian Zhuang break; 90be0e2d3eSHaojian Zhuang case PM8607_ID_LDO2: 91be0e2d3eSHaojian Zhuang case PM8607_ID_LDO3: 92be0e2d3eSHaojian Zhuang case PM8607_ID_LDO9: 93be0e2d3eSHaojian Zhuang switch (chip_id) { 94be0e2d3eSHaojian Zhuang case PM8607_CHIP_A0: 95be0e2d3eSHaojian Zhuang case PM8607_CHIP_A1: 96be0e2d3eSHaojian Zhuang ret = (index < 3) ? (index * 50000 + 1800000) : 97be0e2d3eSHaojian Zhuang ((index < 8) ? (index * 50000 + 2550000) : 98be0e2d3eSHaojian Zhuang -EINVAL); 99be0e2d3eSHaojian Zhuang break; 100be0e2d3eSHaojian Zhuang case PM8607_CHIP_B0: 101be0e2d3eSHaojian Zhuang ret = (index < 3) ? (index * 50000 + 1800000) : 102be0e2d3eSHaojian Zhuang ((index < 7) ? (index * 50000 + 2550000) : 103be0e2d3eSHaojian Zhuang 3300000); 104be0e2d3eSHaojian Zhuang break; 105be0e2d3eSHaojian Zhuang } 106be0e2d3eSHaojian Zhuang break; 107be0e2d3eSHaojian Zhuang case PM8607_ID_LDO4: 108be0e2d3eSHaojian Zhuang switch (chip_id) { 109be0e2d3eSHaojian Zhuang case PM8607_CHIP_A0: 110be0e2d3eSHaojian Zhuang case PM8607_CHIP_A1: 111be0e2d3eSHaojian Zhuang ret = (index < 3) ? (index * 50000 + 1800000) : 112be0e2d3eSHaojian Zhuang ((index < 8) ? (index * 50000 + 2550000) : 113be0e2d3eSHaojian Zhuang -EINVAL); 114be0e2d3eSHaojian Zhuang break; 115be0e2d3eSHaojian Zhuang case PM8607_CHIP_B0: 116be0e2d3eSHaojian Zhuang ret = (index < 3) ? (index * 50000 + 1800000) : 117be0e2d3eSHaojian Zhuang ((index < 6) ? (index * 50000 + 2550000) : 118be0e2d3eSHaojian Zhuang ((index == 6) ? 2900000 : 3300000)); 119be0e2d3eSHaojian Zhuang break; 120be0e2d3eSHaojian Zhuang } 121be0e2d3eSHaojian Zhuang break; 122be0e2d3eSHaojian Zhuang case PM8607_ID_LDO6: 123be0e2d3eSHaojian Zhuang switch (chip_id) { 124be0e2d3eSHaojian Zhuang case PM8607_CHIP_A0: 125be0e2d3eSHaojian Zhuang case PM8607_CHIP_A1: 126be0e2d3eSHaojian Zhuang ret = (index < 3) ? (index * 50000 + 1800000) : 127be0e2d3eSHaojian Zhuang ((index < 8) ? (index * 50000 + 2450000) : 128be0e2d3eSHaojian Zhuang -EINVAL); 129be0e2d3eSHaojian Zhuang break; 130be0e2d3eSHaojian Zhuang case PM8607_CHIP_B0: 131be0e2d3eSHaojian Zhuang ret = (index < 2) ? (index * 50000 + 1800000) : 132be0e2d3eSHaojian Zhuang ((index < 7) ? (index * 50000 + 2500000) : 133be0e2d3eSHaojian Zhuang 3300000); 134be0e2d3eSHaojian Zhuang break; 135be0e2d3eSHaojian Zhuang } 136be0e2d3eSHaojian Zhuang break; 137be0e2d3eSHaojian Zhuang case PM8607_ID_LDO10: 138be0e2d3eSHaojian Zhuang switch (chip_id) { 139be0e2d3eSHaojian Zhuang case PM8607_CHIP_A0: 140be0e2d3eSHaojian Zhuang case PM8607_CHIP_A1: 141be0e2d3eSHaojian Zhuang ret = (index < 3) ? (index * 50000 + 1800000) : 142be0e2d3eSHaojian Zhuang ((index < 8) ? (index * 50000 + 2550000) : 143be0e2d3eSHaojian Zhuang 1200000); 144be0e2d3eSHaojian Zhuang break; 145be0e2d3eSHaojian Zhuang case PM8607_CHIP_B0: 146be0e2d3eSHaojian Zhuang ret = (index < 3) ? (index * 50000 + 1800000) : 147be0e2d3eSHaojian Zhuang ((index < 7) ? (index * 50000 + 2550000) : 148be0e2d3eSHaojian Zhuang ((index == 7) ? 3300000 : 1200000)); 149be0e2d3eSHaojian Zhuang break; 150be0e2d3eSHaojian Zhuang } 151be0e2d3eSHaojian Zhuang break; 152be0e2d3eSHaojian Zhuang case PM8607_ID_LDO14: 153be0e2d3eSHaojian Zhuang switch (chip_id) { 154be0e2d3eSHaojian Zhuang case PM8607_CHIP_A0: 155be0e2d3eSHaojian Zhuang case PM8607_CHIP_A1: 156be0e2d3eSHaojian Zhuang ret = (index < 3) ? (index * 50000 + 1800000) : 157be0e2d3eSHaojian Zhuang ((index < 8) ? (index * 50000 + 2550000) : 158be0e2d3eSHaojian Zhuang -EINVAL); 159be0e2d3eSHaojian Zhuang break; 160be0e2d3eSHaojian Zhuang case PM8607_CHIP_B0: 161be0e2d3eSHaojian Zhuang ret = (index < 2) ? (index * 50000 + 1800000) : 162be0e2d3eSHaojian Zhuang ((index < 7) ? (index * 50000 + 2600000) : 163be0e2d3eSHaojian Zhuang 3300000); 164be0e2d3eSHaojian Zhuang break; 165be0e2d3eSHaojian Zhuang } 166be0e2d3eSHaojian Zhuang break; 167be0e2d3eSHaojian Zhuang } 168be0e2d3eSHaojian Zhuang return ret; 169be0e2d3eSHaojian Zhuang } 170be0e2d3eSHaojian Zhuang 171be0e2d3eSHaojian Zhuang static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) 172be0e2d3eSHaojian Zhuang { 173be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 174*53dbab7aSHaojian Zhuang uint8_t chip_id = info->chip->chip_version; 175ddec6810SMark Brown int val = -ENOENT; 176ddec6810SMark Brown int ret; 177be0e2d3eSHaojian Zhuang 178be0e2d3eSHaojian Zhuang switch (info->desc.id) { 179be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK1: 180be0e2d3eSHaojian Zhuang if (min_uV >= 800000) /* 800mV ~ 1500mV / 25mV */ 181be0e2d3eSHaojian Zhuang val = (min_uV - 775001) / 25000; 182be0e2d3eSHaojian Zhuang else { /* 25mV ~ 775mV / 25mV */ 183be0e2d3eSHaojian Zhuang val = (min_uV + 249999) / 25000; 184be0e2d3eSHaojian Zhuang val += 32; 185be0e2d3eSHaojian Zhuang } 186be0e2d3eSHaojian Zhuang break; 187be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK3: 188be0e2d3eSHaojian Zhuang if (info->slope_double) 189be0e2d3eSHaojian Zhuang min_uV = min_uV >> 1; 190be0e2d3eSHaojian Zhuang val = (min_uV + 249999) / 25000; /* 0mV ~ 1500mV / 25mV */ 191be0e2d3eSHaojian Zhuang 192be0e2d3eSHaojian Zhuang break; 193be0e2d3eSHaojian Zhuang case PM8607_ID_LDO1: 194be0e2d3eSHaojian Zhuang if (min_uV > 1800000) 195be0e2d3eSHaojian Zhuang val = 2; 196be0e2d3eSHaojian Zhuang else if (min_uV > 1200000) 197be0e2d3eSHaojian Zhuang val = 0; 198be0e2d3eSHaojian Zhuang else 199be0e2d3eSHaojian Zhuang val = 1; 200be0e2d3eSHaojian Zhuang break; 201be0e2d3eSHaojian Zhuang case PM8607_ID_LDO5: 202be0e2d3eSHaojian Zhuang if (min_uV > 3100000) 203be0e2d3eSHaojian Zhuang val = 3; 204be0e2d3eSHaojian Zhuang else /* 2900mV ~ 3100mV / 100mV */ 205be0e2d3eSHaojian Zhuang val = (min_uV - 2800001) / 100000; 206be0e2d3eSHaojian Zhuang break; 207be0e2d3eSHaojian Zhuang case PM8607_ID_LDO7: 208be0e2d3eSHaojian Zhuang case PM8607_ID_LDO8: 209be0e2d3eSHaojian Zhuang if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ 210be0e2d3eSHaojian Zhuang if (min_uV <= 1800000) 211be0e2d3eSHaojian Zhuang val = 0; /* 1800mv */ 212be0e2d3eSHaojian Zhuang else if (min_uV <= 1900000) 213be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 214be0e2d3eSHaojian Zhuang else 215be0e2d3eSHaojian Zhuang val = 3; /* 2700mV */ 216be0e2d3eSHaojian Zhuang } else { /* 2700mV ~ 2900mV / 50mV */ 217be0e2d3eSHaojian Zhuang if (min_uV <= 2900000) { 218be0e2d3eSHaojian Zhuang val = (min_uV - 2650001) / 50000; 219be0e2d3eSHaojian Zhuang val += 3; 220be0e2d3eSHaojian Zhuang } else 221be0e2d3eSHaojian Zhuang val = -EINVAL; 222be0e2d3eSHaojian Zhuang } 223be0e2d3eSHaojian Zhuang break; 224be0e2d3eSHaojian Zhuang case PM8607_ID_LDO10: 225be0e2d3eSHaojian Zhuang if (min_uV > 2850000) 226be0e2d3eSHaojian Zhuang val = 7; 227be0e2d3eSHaojian Zhuang else if (min_uV <= 1200000) 228be0e2d3eSHaojian Zhuang val = 8; 229be0e2d3eSHaojian Zhuang else if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ 230be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 231be0e2d3eSHaojian Zhuang else { /* 2700mV ~ 2850mV / 50mV */ 232be0e2d3eSHaojian Zhuang val = (min_uV - 2650001) / 50000; 233be0e2d3eSHaojian Zhuang val += 3; 234be0e2d3eSHaojian Zhuang } 235be0e2d3eSHaojian Zhuang break; 236be0e2d3eSHaojian Zhuang case PM8607_ID_LDO12: 237be0e2d3eSHaojian Zhuang if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 100mV */ 238be0e2d3eSHaojian Zhuang if (min_uV <= 1200000) 239be0e2d3eSHaojian Zhuang val = 8; /* 1200mV */ 240be0e2d3eSHaojian Zhuang else if (min_uV <= 1800000) 241be0e2d3eSHaojian Zhuang val = 0; /* 1800mV */ 242be0e2d3eSHaojian Zhuang else if (min_uV <= 1900000) 243be0e2d3eSHaojian Zhuang val = (min_uV - 1700001) / 100000; 244be0e2d3eSHaojian Zhuang else 245be0e2d3eSHaojian Zhuang val = 2; /* 2700mV */ 246be0e2d3eSHaojian Zhuang } else { /* 2700mV ~ 3100mV / 100mV */ 247be0e2d3eSHaojian Zhuang if (min_uV <= 3100000) { 248be0e2d3eSHaojian Zhuang val = (min_uV - 2600001) / 100000; 249be0e2d3eSHaojian Zhuang val += 2; 250be0e2d3eSHaojian Zhuang } else if (min_uV <= 3300000) 251be0e2d3eSHaojian Zhuang val = 7; 252be0e2d3eSHaojian Zhuang else 253be0e2d3eSHaojian Zhuang val = -EINVAL; 254be0e2d3eSHaojian Zhuang } 255be0e2d3eSHaojian Zhuang break; 256be0e2d3eSHaojian Zhuang case PM8607_ID_LDO2: 257be0e2d3eSHaojian Zhuang case PM8607_ID_LDO3: 258be0e2d3eSHaojian Zhuang case PM8607_ID_LDO9: 259be0e2d3eSHaojian Zhuang switch (chip_id) { 260be0e2d3eSHaojian Zhuang case PM8607_CHIP_A0: 261be0e2d3eSHaojian Zhuang case PM8607_CHIP_A1: 262be0e2d3eSHaojian Zhuang if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ 263be0e2d3eSHaojian Zhuang if (min_uV <= 1800000) 264be0e2d3eSHaojian Zhuang val = 0; 265be0e2d3eSHaojian Zhuang else if (min_uV <= 1900000) 266be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 267be0e2d3eSHaojian Zhuang else 268be0e2d3eSHaojian Zhuang val = 3; /* 2700mV */ 269be0e2d3eSHaojian Zhuang else { /* 2700mV ~ 2900mV / 50mV */ 270be0e2d3eSHaojian Zhuang if (min_uV <= 2900000) { 271be0e2d3eSHaojian Zhuang val = (min_uV - 2650001) / 50000; 272be0e2d3eSHaojian Zhuang val += 3; 273be0e2d3eSHaojian Zhuang } else 274be0e2d3eSHaojian Zhuang val = -EINVAL; 275be0e2d3eSHaojian Zhuang } 276be0e2d3eSHaojian Zhuang break; 277be0e2d3eSHaojian Zhuang case PM8607_CHIP_B0: 278be0e2d3eSHaojian Zhuang if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ 279be0e2d3eSHaojian Zhuang if (min_uV <= 1800000) 280be0e2d3eSHaojian Zhuang val = 0; 281be0e2d3eSHaojian Zhuang else if (min_uV <= 1900000) 282be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 283be0e2d3eSHaojian Zhuang else 284be0e2d3eSHaojian Zhuang val = 3; /* 2700mV */ 285be0e2d3eSHaojian Zhuang } else { /* 2700mV ~ 2850mV / 50mV */ 286be0e2d3eSHaojian Zhuang if (min_uV <= 2850000) { 287be0e2d3eSHaojian Zhuang val = (min_uV - 2650001) / 50000; 288be0e2d3eSHaojian Zhuang val += 3; 289be0e2d3eSHaojian Zhuang } else if (min_uV <= 3300000) 290be0e2d3eSHaojian Zhuang val = 7; 291be0e2d3eSHaojian Zhuang else 292be0e2d3eSHaojian Zhuang val = -EINVAL; 293be0e2d3eSHaojian Zhuang } 294be0e2d3eSHaojian Zhuang break; 295be0e2d3eSHaojian Zhuang } 296be0e2d3eSHaojian Zhuang break; 297be0e2d3eSHaojian Zhuang case PM8607_ID_LDO4: 298be0e2d3eSHaojian Zhuang switch (chip_id) { 299be0e2d3eSHaojian Zhuang case PM8607_CHIP_A0: 300be0e2d3eSHaojian Zhuang case PM8607_CHIP_A1: 301be0e2d3eSHaojian Zhuang if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ 302be0e2d3eSHaojian Zhuang if (min_uV <= 1800000) 303be0e2d3eSHaojian Zhuang val = 0; 304be0e2d3eSHaojian Zhuang else if (min_uV <= 1900000) 305be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 306be0e2d3eSHaojian Zhuang else 307be0e2d3eSHaojian Zhuang val = 3; /* 2700mV */ 308be0e2d3eSHaojian Zhuang else { /* 2700mV ~ 2900mV / 50mV */ 309be0e2d3eSHaojian Zhuang if (min_uV <= 2900000) { 310be0e2d3eSHaojian Zhuang val = (min_uV - 2650001) / 50000; 311be0e2d3eSHaojian Zhuang val += 3; 312be0e2d3eSHaojian Zhuang } else 313be0e2d3eSHaojian Zhuang val = -EINVAL; 314be0e2d3eSHaojian Zhuang } 315be0e2d3eSHaojian Zhuang break; 316be0e2d3eSHaojian Zhuang case PM8607_CHIP_B0: 317be0e2d3eSHaojian Zhuang if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ 318be0e2d3eSHaojian Zhuang if (min_uV <= 1800000) 319be0e2d3eSHaojian Zhuang val = 0; 320be0e2d3eSHaojian Zhuang else if (min_uV <= 1900000) 321be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 322be0e2d3eSHaojian Zhuang else 323be0e2d3eSHaojian Zhuang val = 3; /* 2700mV */ 324be0e2d3eSHaojian Zhuang } else { /* 2700mV ~ 2800mV / 50mV */ 325be0e2d3eSHaojian Zhuang if (min_uV <= 2850000) { 326be0e2d3eSHaojian Zhuang val = (min_uV - 2650001) / 50000; 327be0e2d3eSHaojian Zhuang val += 3; 328be0e2d3eSHaojian Zhuang } else if (min_uV <= 2900000) 329be0e2d3eSHaojian Zhuang val = 6; 330be0e2d3eSHaojian Zhuang else if (min_uV <= 3300000) 331be0e2d3eSHaojian Zhuang val = 7; 332be0e2d3eSHaojian Zhuang else 333be0e2d3eSHaojian Zhuang val = -EINVAL; 334be0e2d3eSHaojian Zhuang } 335be0e2d3eSHaojian Zhuang break; 336be0e2d3eSHaojian Zhuang } 337be0e2d3eSHaojian Zhuang break; 338be0e2d3eSHaojian Zhuang case PM8607_ID_LDO6: 339be0e2d3eSHaojian Zhuang switch (chip_id) { 340be0e2d3eSHaojian Zhuang case PM8607_CHIP_A0: 341be0e2d3eSHaojian Zhuang case PM8607_CHIP_A1: 342be0e2d3eSHaojian Zhuang if (min_uV < 2600000) { /* 1800mV ~ 1900mV / 50mV */ 343be0e2d3eSHaojian Zhuang if (min_uV <= 1800000) 344be0e2d3eSHaojian Zhuang val = 0; 345be0e2d3eSHaojian Zhuang else if (min_uV <= 1900000) 346be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 347be0e2d3eSHaojian Zhuang else 348be0e2d3eSHaojian Zhuang val = 3; /* 2600mV */ 349be0e2d3eSHaojian Zhuang } else { /* 2600mV ~ 2800mV / 50mV */ 350be0e2d3eSHaojian Zhuang if (min_uV <= 2800000) { 351be0e2d3eSHaojian Zhuang val = (min_uV - 2550001) / 50000; 352be0e2d3eSHaojian Zhuang val += 3; 353be0e2d3eSHaojian Zhuang } else 354be0e2d3eSHaojian Zhuang val = -EINVAL; 355be0e2d3eSHaojian Zhuang } 356be0e2d3eSHaojian Zhuang break; 357be0e2d3eSHaojian Zhuang case PM8607_CHIP_B0: 358be0e2d3eSHaojian Zhuang if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */ 359be0e2d3eSHaojian Zhuang if (min_uV <= 1800000) 360be0e2d3eSHaojian Zhuang val = 0; 361be0e2d3eSHaojian Zhuang else if (min_uV <= 1850000) 362be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 363be0e2d3eSHaojian Zhuang else 364be0e2d3eSHaojian Zhuang val = 2; /* 2600mV */ 365be0e2d3eSHaojian Zhuang } else { /* 2600mV ~ 2800mV / 50mV */ 366be0e2d3eSHaojian Zhuang if (min_uV <= 2800000) { 367be0e2d3eSHaojian Zhuang val = (min_uV - 2550001) / 50000; 368be0e2d3eSHaojian Zhuang val += 2; 369be0e2d3eSHaojian Zhuang } else if (min_uV <= 3300000) 370be0e2d3eSHaojian Zhuang val = 7; 371be0e2d3eSHaojian Zhuang else 372be0e2d3eSHaojian Zhuang val = -EINVAL; 373be0e2d3eSHaojian Zhuang } 374be0e2d3eSHaojian Zhuang break; 375be0e2d3eSHaojian Zhuang } 376be0e2d3eSHaojian Zhuang break; 377be0e2d3eSHaojian Zhuang case PM8607_ID_LDO14: 378be0e2d3eSHaojian Zhuang switch (chip_id) { 379be0e2d3eSHaojian Zhuang case PM8607_CHIP_A0: 380be0e2d3eSHaojian Zhuang case PM8607_CHIP_A1: 381be0e2d3eSHaojian Zhuang if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ 382be0e2d3eSHaojian Zhuang if (min_uV <= 1800000) 383be0e2d3eSHaojian Zhuang val = 0; 384be0e2d3eSHaojian Zhuang else if (min_uV <= 1900000) 385be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 386be0e2d3eSHaojian Zhuang else 387be0e2d3eSHaojian Zhuang val = 3; /* 2700mV */ 388be0e2d3eSHaojian Zhuang } else { /* 2700mV ~ 2900mV / 50mV */ 389be0e2d3eSHaojian Zhuang if (min_uV <= 2900000) { 390be0e2d3eSHaojian Zhuang val = (min_uV - 2650001) / 50000; 391be0e2d3eSHaojian Zhuang val += 3; 392be0e2d3eSHaojian Zhuang } else 393be0e2d3eSHaojian Zhuang val = -EINVAL; 394be0e2d3eSHaojian Zhuang } 395be0e2d3eSHaojian Zhuang break; 396be0e2d3eSHaojian Zhuang case PM8607_CHIP_B0: 397be0e2d3eSHaojian Zhuang if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */ 398be0e2d3eSHaojian Zhuang if (min_uV <= 1800000) 399be0e2d3eSHaojian Zhuang val = 0; 400be0e2d3eSHaojian Zhuang else if (min_uV <= 1850000) 401be0e2d3eSHaojian Zhuang val = (min_uV - 1750001) / 50000; 402be0e2d3eSHaojian Zhuang else 403be0e2d3eSHaojian Zhuang val = 2; /* 2700mV */ 404be0e2d3eSHaojian Zhuang } else { /* 2700mV ~ 2900mV / 50mV */ 405be0e2d3eSHaojian Zhuang if (min_uV <= 2900000) { 406be0e2d3eSHaojian Zhuang val = (min_uV - 2650001) / 50000; 407be0e2d3eSHaojian Zhuang val += 2; 408be0e2d3eSHaojian Zhuang } else if (min_uV <= 3300000) 409be0e2d3eSHaojian Zhuang val = 7; 410be0e2d3eSHaojian Zhuang else 411be0e2d3eSHaojian Zhuang val = -EINVAL; 412be0e2d3eSHaojian Zhuang } 413be0e2d3eSHaojian Zhuang break; 414be0e2d3eSHaojian Zhuang } 415be0e2d3eSHaojian Zhuang break; 416be0e2d3eSHaojian Zhuang } 417be0e2d3eSHaojian Zhuang if (val >= 0) { 418be0e2d3eSHaojian Zhuang ret = pm8607_list_voltage(rdev, val); 419be0e2d3eSHaojian Zhuang if (ret > max_uV) { 420be0e2d3eSHaojian Zhuang pr_err("exceed voltage range (%d %d) uV", 421be0e2d3eSHaojian Zhuang min_uV, max_uV); 422be0e2d3eSHaojian Zhuang return -EINVAL; 423be0e2d3eSHaojian Zhuang } 424be0e2d3eSHaojian Zhuang } else 425be0e2d3eSHaojian Zhuang pr_err("invalid voltage range (%d %d) uV", min_uV, max_uV); 426be0e2d3eSHaojian Zhuang return val; 427be0e2d3eSHaojian Zhuang } 428be0e2d3eSHaojian Zhuang 429be0e2d3eSHaojian Zhuang static int pm8607_set_voltage(struct regulator_dev *rdev, 430be0e2d3eSHaojian Zhuang int min_uV, int max_uV) 431be0e2d3eSHaojian Zhuang { 432be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 433be0e2d3eSHaojian Zhuang uint8_t val, mask; 434be0e2d3eSHaojian Zhuang int ret; 435be0e2d3eSHaojian Zhuang 436be0e2d3eSHaojian Zhuang if (check_range(info, min_uV, max_uV)) { 437be0e2d3eSHaojian Zhuang pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); 438be0e2d3eSHaojian Zhuang return -EINVAL; 439be0e2d3eSHaojian Zhuang } 440be0e2d3eSHaojian Zhuang 441be0e2d3eSHaojian Zhuang ret = choose_voltage(rdev, min_uV, max_uV); 442be0e2d3eSHaojian Zhuang if (ret < 0) 443be0e2d3eSHaojian Zhuang return -EINVAL; 444be0e2d3eSHaojian Zhuang val = (uint8_t)(ret << info->vol_shift); 445be0e2d3eSHaojian Zhuang mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; 446be0e2d3eSHaojian Zhuang 447*53dbab7aSHaojian Zhuang ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val); 448be0e2d3eSHaojian Zhuang if (ret) 449be0e2d3eSHaojian Zhuang return ret; 450be0e2d3eSHaojian Zhuang switch (info->desc.id) { 451be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK1: 452be0e2d3eSHaojian Zhuang case PM8607_ID_BUCK3: 453*53dbab7aSHaojian Zhuang ret = pm860x_set_bits(info->i2c, info->update_reg, 454be0e2d3eSHaojian Zhuang 1 << info->update_bit, 455be0e2d3eSHaojian Zhuang 1 << info->update_bit); 456be0e2d3eSHaojian Zhuang break; 457be0e2d3eSHaojian Zhuang } 458be0e2d3eSHaojian Zhuang return ret; 459be0e2d3eSHaojian Zhuang } 460be0e2d3eSHaojian Zhuang 461be0e2d3eSHaojian Zhuang static int pm8607_get_voltage(struct regulator_dev *rdev) 462be0e2d3eSHaojian Zhuang { 463be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 464be0e2d3eSHaojian Zhuang uint8_t val, mask; 465be0e2d3eSHaojian Zhuang int ret; 466be0e2d3eSHaojian Zhuang 467*53dbab7aSHaojian Zhuang ret = pm860x_reg_read(info->i2c, info->vol_reg); 468be0e2d3eSHaojian Zhuang if (ret < 0) 469be0e2d3eSHaojian Zhuang return ret; 470be0e2d3eSHaojian Zhuang 471be0e2d3eSHaojian Zhuang mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; 472be0e2d3eSHaojian Zhuang val = ((unsigned char)ret & mask) >> info->vol_shift; 473be0e2d3eSHaojian Zhuang 474be0e2d3eSHaojian Zhuang return pm8607_list_voltage(rdev, val); 475be0e2d3eSHaojian Zhuang } 476be0e2d3eSHaojian Zhuang 477be0e2d3eSHaojian Zhuang static int pm8607_enable(struct regulator_dev *rdev) 478be0e2d3eSHaojian Zhuang { 479be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 480be0e2d3eSHaojian Zhuang 481*53dbab7aSHaojian Zhuang return pm860x_set_bits(info->i2c, info->enable_reg, 482be0e2d3eSHaojian Zhuang 1 << info->enable_bit, 483be0e2d3eSHaojian Zhuang 1 << info->enable_bit); 484be0e2d3eSHaojian Zhuang } 485be0e2d3eSHaojian Zhuang 486be0e2d3eSHaojian Zhuang static int pm8607_disable(struct regulator_dev *rdev) 487be0e2d3eSHaojian Zhuang { 488be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 489be0e2d3eSHaojian Zhuang 490*53dbab7aSHaojian Zhuang return pm860x_set_bits(info->i2c, info->enable_reg, 491be0e2d3eSHaojian Zhuang 1 << info->enable_bit, 0); 492be0e2d3eSHaojian Zhuang } 493be0e2d3eSHaojian Zhuang 494be0e2d3eSHaojian Zhuang static int pm8607_is_enabled(struct regulator_dev *rdev) 495be0e2d3eSHaojian Zhuang { 496be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); 497be0e2d3eSHaojian Zhuang int ret; 498be0e2d3eSHaojian Zhuang 499*53dbab7aSHaojian Zhuang ret = pm860x_reg_read(info->i2c, info->enable_reg); 500be0e2d3eSHaojian Zhuang if (ret < 0) 501be0e2d3eSHaojian Zhuang return ret; 502be0e2d3eSHaojian Zhuang 503be0e2d3eSHaojian Zhuang return !!((unsigned char)ret & (1 << info->enable_bit)); 504be0e2d3eSHaojian Zhuang } 505be0e2d3eSHaojian Zhuang 506be0e2d3eSHaojian Zhuang static struct regulator_ops pm8607_regulator_ops = { 507be0e2d3eSHaojian Zhuang .set_voltage = pm8607_set_voltage, 508be0e2d3eSHaojian Zhuang .get_voltage = pm8607_get_voltage, 509be0e2d3eSHaojian Zhuang .enable = pm8607_enable, 510be0e2d3eSHaojian Zhuang .disable = pm8607_disable, 511be0e2d3eSHaojian Zhuang .is_enabled = pm8607_is_enabled, 512be0e2d3eSHaojian Zhuang }; 513be0e2d3eSHaojian Zhuang 514be0e2d3eSHaojian Zhuang #define PM8607_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ 515be0e2d3eSHaojian Zhuang { \ 516be0e2d3eSHaojian Zhuang .desc = { \ 517be0e2d3eSHaojian Zhuang .name = "BUCK" #_id, \ 518be0e2d3eSHaojian Zhuang .ops = &pm8607_regulator_ops, \ 519be0e2d3eSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 520be0e2d3eSHaojian Zhuang .id = PM8607_ID_BUCK##_id, \ 521be0e2d3eSHaojian Zhuang .owner = THIS_MODULE, \ 522be0e2d3eSHaojian Zhuang }, \ 523be0e2d3eSHaojian Zhuang .min_uV = (min) * 1000, \ 524be0e2d3eSHaojian Zhuang .max_uV = (max) * 1000, \ 525be0e2d3eSHaojian Zhuang .step_uV = (step) * 1000, \ 526be0e2d3eSHaojian Zhuang .vol_reg = PM8607_##vreg, \ 527be0e2d3eSHaojian Zhuang .vol_shift = (0), \ 528be0e2d3eSHaojian Zhuang .vol_nbits = (nbits), \ 529be0e2d3eSHaojian Zhuang .update_reg = PM8607_##ureg, \ 530be0e2d3eSHaojian Zhuang .update_bit = (ubit), \ 531be0e2d3eSHaojian Zhuang .enable_reg = PM8607_##ereg, \ 532be0e2d3eSHaojian Zhuang .enable_bit = (ebit), \ 533be0e2d3eSHaojian Zhuang .slope_double = (0), \ 534be0e2d3eSHaojian Zhuang } 535be0e2d3eSHaojian Zhuang 536be0e2d3eSHaojian Zhuang #define PM8607_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \ 537be0e2d3eSHaojian Zhuang { \ 538be0e2d3eSHaojian Zhuang .desc = { \ 539be0e2d3eSHaojian Zhuang .name = "LDO" #_id, \ 540be0e2d3eSHaojian Zhuang .ops = &pm8607_regulator_ops, \ 541be0e2d3eSHaojian Zhuang .type = REGULATOR_VOLTAGE, \ 542be0e2d3eSHaojian Zhuang .id = PM8607_ID_LDO##_id, \ 543be0e2d3eSHaojian Zhuang .owner = THIS_MODULE, \ 544be0e2d3eSHaojian Zhuang }, \ 545be0e2d3eSHaojian Zhuang .min_uV = (min) * 1000, \ 546be0e2d3eSHaojian Zhuang .max_uV = (max) * 1000, \ 547be0e2d3eSHaojian Zhuang .step_uV = (step) * 1000, \ 548be0e2d3eSHaojian Zhuang .vol_reg = PM8607_##vreg, \ 549be0e2d3eSHaojian Zhuang .vol_shift = (shift), \ 550be0e2d3eSHaojian Zhuang .vol_nbits = (nbits), \ 551be0e2d3eSHaojian Zhuang .enable_reg = PM8607_##ereg, \ 552be0e2d3eSHaojian Zhuang .enable_bit = (ebit), \ 553be0e2d3eSHaojian Zhuang .slope_double = (0), \ 554be0e2d3eSHaojian Zhuang } 555be0e2d3eSHaojian Zhuang 556be0e2d3eSHaojian Zhuang static struct pm8607_regulator_info pm8607_regulator_info[] = { 557be0e2d3eSHaojian Zhuang PM8607_DVC(1, 0, 1500, 25, BUCK1, 6, GO, 0, SUPPLIES_EN11, 0), 558be0e2d3eSHaojian Zhuang PM8607_DVC(3, 0, 1500, 25, BUCK3, 6, GO, 2, SUPPLIES_EN11, 2), 559be0e2d3eSHaojian Zhuang 560be0e2d3eSHaojian Zhuang PM8607_LDO(1 , 1200, 2800, 0, LDO1 , 0, 2, SUPPLIES_EN11, 3), 561be0e2d3eSHaojian Zhuang PM8607_LDO(2 , 1800, 3300, 0, LDO2 , 0, 3, SUPPLIES_EN11, 4), 562be0e2d3eSHaojian Zhuang PM8607_LDO(3 , 1800, 3300, 0, LDO3 , 0, 3, SUPPLIES_EN11, 5), 563be0e2d3eSHaojian Zhuang PM8607_LDO(4 , 1800, 3300, 0, LDO4 , 0, 3, SUPPLIES_EN11, 6), 564be0e2d3eSHaojian Zhuang PM8607_LDO(5 , 2900, 3300, 0, LDO5 , 0, 2, SUPPLIES_EN11, 7), 565be0e2d3eSHaojian Zhuang PM8607_LDO(6 , 1800, 3300, 0, LDO6 , 0, 3, SUPPLIES_EN12, 0), 566be0e2d3eSHaojian Zhuang PM8607_LDO(7 , 1800, 2900, 0, LDO7 , 0, 3, SUPPLIES_EN12, 1), 567be0e2d3eSHaojian Zhuang PM8607_LDO(8 , 1800, 2900, 0, LDO8 , 0, 3, SUPPLIES_EN12, 2), 568be0e2d3eSHaojian Zhuang PM8607_LDO(9 , 1800, 3300, 0, LDO9 , 0, 3, SUPPLIES_EN12, 3), 569be0e2d3eSHaojian Zhuang PM8607_LDO(10, 1200, 3300, 0, LDO10, 0, 4, SUPPLIES_EN11, 4), 570be0e2d3eSHaojian Zhuang PM8607_LDO(12, 1200, 3300, 0, LDO12, 0, 4, SUPPLIES_EN11, 5), 571be0e2d3eSHaojian Zhuang PM8607_LDO(14, 1800, 3300, 0, LDO14, 0, 3, SUPPLIES_EN11, 6), 572be0e2d3eSHaojian Zhuang }; 573be0e2d3eSHaojian Zhuang 574be0e2d3eSHaojian Zhuang static inline struct pm8607_regulator_info *find_regulator_info(int id) 575be0e2d3eSHaojian Zhuang { 576be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info; 577be0e2d3eSHaojian Zhuang int i; 578be0e2d3eSHaojian Zhuang 579be0e2d3eSHaojian Zhuang for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { 580be0e2d3eSHaojian Zhuang info = &pm8607_regulator_info[i]; 581be0e2d3eSHaojian Zhuang if (info->desc.id == id) 582be0e2d3eSHaojian Zhuang return info; 583be0e2d3eSHaojian Zhuang } 584be0e2d3eSHaojian Zhuang return NULL; 585be0e2d3eSHaojian Zhuang } 586be0e2d3eSHaojian Zhuang 587be0e2d3eSHaojian Zhuang static int __devinit pm8607_regulator_probe(struct platform_device *pdev) 588be0e2d3eSHaojian Zhuang { 589*53dbab7aSHaojian Zhuang struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); 590*53dbab7aSHaojian Zhuang struct pm860x_platform_data *pdata = chip->dev->platform_data; 591be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = NULL; 592be0e2d3eSHaojian Zhuang 593be0e2d3eSHaojian Zhuang info = find_regulator_info(pdev->id); 594be0e2d3eSHaojian Zhuang if (info == NULL) { 595be0e2d3eSHaojian Zhuang dev_err(&pdev->dev, "invalid regulator ID specified\n"); 596be0e2d3eSHaojian Zhuang return -EINVAL; 597be0e2d3eSHaojian Zhuang } 598be0e2d3eSHaojian Zhuang 599*53dbab7aSHaojian Zhuang info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 600be0e2d3eSHaojian Zhuang info->chip = chip; 601be0e2d3eSHaojian Zhuang 602be0e2d3eSHaojian Zhuang info->regulator = regulator_register(&info->desc, &pdev->dev, 603be0e2d3eSHaojian Zhuang pdata->regulator[pdev->id], info); 604be0e2d3eSHaojian Zhuang if (IS_ERR(info->regulator)) { 605be0e2d3eSHaojian Zhuang dev_err(&pdev->dev, "failed to register regulator %s\n", 606be0e2d3eSHaojian Zhuang info->desc.name); 607be0e2d3eSHaojian Zhuang return PTR_ERR(info->regulator); 608be0e2d3eSHaojian Zhuang } 609be0e2d3eSHaojian Zhuang 610be0e2d3eSHaojian Zhuang /* check DVC ramp slope double */ 611be0e2d3eSHaojian Zhuang if (info->desc.id == PM8607_ID_BUCK3) 612be0e2d3eSHaojian Zhuang if (info->chip->buck3_double) 613be0e2d3eSHaojian Zhuang info->slope_double = 1; 614be0e2d3eSHaojian Zhuang 615be0e2d3eSHaojian Zhuang platform_set_drvdata(pdev, info); 616be0e2d3eSHaojian Zhuang return 0; 617be0e2d3eSHaojian Zhuang } 618be0e2d3eSHaojian Zhuang 619be0e2d3eSHaojian Zhuang static int __devexit pm8607_regulator_remove(struct platform_device *pdev) 620be0e2d3eSHaojian Zhuang { 621be0e2d3eSHaojian Zhuang struct pm8607_regulator_info *info = platform_get_drvdata(pdev); 622be0e2d3eSHaojian Zhuang 623be0e2d3eSHaojian Zhuang regulator_unregister(info->regulator); 624be0e2d3eSHaojian Zhuang return 0; 625be0e2d3eSHaojian Zhuang } 626be0e2d3eSHaojian Zhuang 627be0e2d3eSHaojian Zhuang #define PM8607_REGULATOR_DRIVER(_name) \ 628be0e2d3eSHaojian Zhuang { \ 629be0e2d3eSHaojian Zhuang .driver = { \ 630be0e2d3eSHaojian Zhuang .name = "88pm8607-" #_name, \ 631be0e2d3eSHaojian Zhuang .owner = THIS_MODULE, \ 632be0e2d3eSHaojian Zhuang }, \ 633be0e2d3eSHaojian Zhuang .probe = pm8607_regulator_probe, \ 634be0e2d3eSHaojian Zhuang .remove = __devexit_p(pm8607_regulator_remove), \ 635be0e2d3eSHaojian Zhuang } 636be0e2d3eSHaojian Zhuang 637be0e2d3eSHaojian Zhuang static struct platform_driver pm8607_regulator_driver[] = { 638be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(buck1), 639be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(buck2), 640be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(buck3), 641be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo1), 642be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo2), 643be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo3), 644be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo4), 645be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo5), 646be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo6), 647be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo7), 648be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo8), 649be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo9), 650be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo10), 651be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo12), 652be0e2d3eSHaojian Zhuang PM8607_REGULATOR_DRIVER(ldo14), 653be0e2d3eSHaojian Zhuang }; 654be0e2d3eSHaojian Zhuang 655be0e2d3eSHaojian Zhuang static int __init pm8607_regulator_init(void) 656be0e2d3eSHaojian Zhuang { 657be0e2d3eSHaojian Zhuang int i, count, ret; 658be0e2d3eSHaojian Zhuang 659be0e2d3eSHaojian Zhuang count = ARRAY_SIZE(pm8607_regulator_driver); 660be0e2d3eSHaojian Zhuang for (i = 0; i < count; i++) { 661be0e2d3eSHaojian Zhuang ret = platform_driver_register(&pm8607_regulator_driver[i]); 662be0e2d3eSHaojian Zhuang if (ret != 0) 663be0e2d3eSHaojian Zhuang pr_err("Failed to register regulator driver: %d\n", 664be0e2d3eSHaojian Zhuang ret); 665be0e2d3eSHaojian Zhuang } 666be0e2d3eSHaojian Zhuang return 0; 667be0e2d3eSHaojian Zhuang } 668be0e2d3eSHaojian Zhuang subsys_initcall(pm8607_regulator_init); 669be0e2d3eSHaojian Zhuang 670be0e2d3eSHaojian Zhuang static void __exit pm8607_regulator_exit(void) 671be0e2d3eSHaojian Zhuang { 672be0e2d3eSHaojian Zhuang int i, count; 673be0e2d3eSHaojian Zhuang 674be0e2d3eSHaojian Zhuang count = ARRAY_SIZE(pm8607_regulator_driver); 675be0e2d3eSHaojian Zhuang for (i = 0; i < count; i++) 676be0e2d3eSHaojian Zhuang platform_driver_unregister(&pm8607_regulator_driver[i]); 677be0e2d3eSHaojian Zhuang } 678be0e2d3eSHaojian Zhuang module_exit(pm8607_regulator_exit); 679be0e2d3eSHaojian Zhuang 680be0e2d3eSHaojian Zhuang MODULE_LICENSE("GPL"); 681be0e2d3eSHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 682be0e2d3eSHaojian Zhuang MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC"); 683be0e2d3eSHaojian Zhuang MODULE_ALIAS("platform:88pm8607-regulator"); 684