10376148fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d1a82001SLee Jones /* 3d1a82001SLee Jones * Copyright (C) ST-Ericsson SA 2010 4d1a82001SLee Jones * 5d1a82001SLee Jones * Authors: Bengt Jonsson <bengt.g.jonsson@stericsson.com> 6d1a82001SLee Jones * 7d1a82001SLee Jones * This file is based on drivers/regulator/ab8500.c 8d1a82001SLee Jones * 9d1a82001SLee Jones * AB8500 external regulators 10d1a82001SLee Jones * 11d1a82001SLee Jones * ab8500-ext supports the following regulators: 12d1a82001SLee Jones * - VextSupply3 13d1a82001SLee Jones */ 14d1a82001SLee Jones #include <linux/init.h> 15d1a82001SLee Jones #include <linux/kernel.h> 16d1a82001SLee Jones #include <linux/err.h> 17d1a82001SLee Jones #include <linux/module.h> 1830aa4b26SLee Jones #include <linux/of.h> 19d1a82001SLee Jones #include <linux/platform_device.h> 20d1a82001SLee Jones #include <linux/regulator/driver.h> 21d1a82001SLee Jones #include <linux/regulator/machine.h> 2230aa4b26SLee Jones #include <linux/regulator/of_regulator.h> 23d1a82001SLee Jones #include <linux/mfd/abx500.h> 24d1a82001SLee Jones #include <linux/mfd/abx500/ab8500.h> 253acb64c0SLinus Walleij 263acb64c0SLinus Walleij /* AB8500 external regulators */ 273acb64c0SLinus Walleij enum ab8500_ext_regulator_id { 283acb64c0SLinus Walleij AB8500_EXT_SUPPLY1, 293acb64c0SLinus Walleij AB8500_EXT_SUPPLY2, 303acb64c0SLinus Walleij AB8500_EXT_SUPPLY3, 313acb64c0SLinus Walleij AB8500_NUM_EXT_REGULATORS, 323acb64c0SLinus Walleij }; 333acb64c0SLinus Walleij 343acb64c0SLinus Walleij struct ab8500_ext_regulator_cfg { 353acb64c0SLinus Walleij bool hwreq; /* requires hw mode or high power mode */ 363acb64c0SLinus Walleij }; 37d1a82001SLee Jones 3879886be0SArnd Bergmann /* supply for VextSupply3 */ 3979886be0SArnd Bergmann static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = { 4079886be0SArnd Bergmann /* SIM supply for 3 V SIM cards */ 4179886be0SArnd Bergmann REGULATOR_SUPPLY("vinvsim", "sim-detect.0"), 4279886be0SArnd Bergmann }; 4379886be0SArnd Bergmann 4479886be0SArnd Bergmann /* 4579886be0SArnd Bergmann * AB8500 external regulators 4679886be0SArnd Bergmann */ 4779886be0SArnd Bergmann static struct regulator_init_data ab8500_ext_regulators[] = { 4879886be0SArnd Bergmann /* fixed Vbat supplies VSMPS1_EXT_1V8 */ 4979886be0SArnd Bergmann [AB8500_EXT_SUPPLY1] = { 5079886be0SArnd Bergmann .constraints = { 5179886be0SArnd Bergmann .name = "ab8500-ext-supply1", 5279886be0SArnd Bergmann .min_uV = 1800000, 5379886be0SArnd Bergmann .max_uV = 1800000, 5479886be0SArnd Bergmann .initial_mode = REGULATOR_MODE_IDLE, 5579886be0SArnd Bergmann .boot_on = 1, 5679886be0SArnd Bergmann .always_on = 1, 5779886be0SArnd Bergmann }, 5879886be0SArnd Bergmann }, 5979886be0SArnd Bergmann /* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */ 6079886be0SArnd Bergmann [AB8500_EXT_SUPPLY2] = { 6179886be0SArnd Bergmann .constraints = { 6279886be0SArnd Bergmann .name = "ab8500-ext-supply2", 6379886be0SArnd Bergmann .min_uV = 1360000, 6479886be0SArnd Bergmann .max_uV = 1360000, 6579886be0SArnd Bergmann }, 6679886be0SArnd Bergmann }, 6779886be0SArnd Bergmann /* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */ 6879886be0SArnd Bergmann [AB8500_EXT_SUPPLY3] = { 6979886be0SArnd Bergmann .constraints = { 7079886be0SArnd Bergmann .name = "ab8500-ext-supply3", 7179886be0SArnd Bergmann .min_uV = 3400000, 7279886be0SArnd Bergmann .max_uV = 3400000, 7379886be0SArnd Bergmann .valid_ops_mask = REGULATOR_CHANGE_STATUS, 7479886be0SArnd Bergmann .boot_on = 1, 7579886be0SArnd Bergmann }, 7679886be0SArnd Bergmann .num_consumer_supplies = 7779886be0SArnd Bergmann ARRAY_SIZE(ab8500_ext_supply3_consumers), 7879886be0SArnd Bergmann .consumer_supplies = ab8500_ext_supply3_consumers, 7979886be0SArnd Bergmann }, 8079886be0SArnd Bergmann }; 8179886be0SArnd Bergmann 82d1a82001SLee Jones /** 83d1a82001SLee Jones * struct ab8500_ext_regulator_info - ab8500 regulator information 84d1a82001SLee Jones * @dev: device pointer 85d1a82001SLee Jones * @desc: regulator description 8618bc2b39SBengt Jonsson * @cfg: regulator configuration (extension of regulator FW configuration) 87d1a82001SLee Jones * @update_bank: bank to control on/off 88d1a82001SLee Jones * @update_reg: register to control on/off 89d1a82001SLee Jones * @update_mask: mask to enable/disable and set mode of regulator 90d1a82001SLee Jones * @update_val: bits holding the regulator current mode 9118bc2b39SBengt Jonsson * @update_val_hp: bits to set EN pin active (LPn pin deactive) 92d1a82001SLee Jones * normally this means high power mode 9318bc2b39SBengt Jonsson * @update_val_lp: bits to set EN pin active and LPn pin active 94d1a82001SLee Jones * normally this means low power mode 9518bc2b39SBengt Jonsson * @update_val_hw: bits to set regulator pins in HW control 9618bc2b39SBengt Jonsson * SysClkReq pins and logic will choose mode 97d1a82001SLee Jones */ 98d1a82001SLee Jones struct ab8500_ext_regulator_info { 99d1a82001SLee Jones struct device *dev; 100d1a82001SLee Jones struct regulator_desc desc; 10118bc2b39SBengt Jonsson struct ab8500_ext_regulator_cfg *cfg; 102d1a82001SLee Jones u8 update_bank; 103d1a82001SLee Jones u8 update_reg; 104d1a82001SLee Jones u8 update_mask; 105d1a82001SLee Jones u8 update_val; 10618bc2b39SBengt Jonsson u8 update_val_hp; 10718bc2b39SBengt Jonsson u8 update_val_lp; 10818bc2b39SBengt Jonsson u8 update_val_hw; 109d1a82001SLee Jones }; 110d1a82001SLee Jones 11118bc2b39SBengt Jonsson static int ab8500_ext_regulator_enable(struct regulator_dev *rdev) 11218bc2b39SBengt Jonsson { 11318bc2b39SBengt Jonsson int ret; 11418bc2b39SBengt Jonsson struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 11518bc2b39SBengt Jonsson u8 regval; 11618bc2b39SBengt Jonsson 11718bc2b39SBengt Jonsson if (info == NULL) { 11818bc2b39SBengt Jonsson dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 11918bc2b39SBengt Jonsson return -EINVAL; 12018bc2b39SBengt Jonsson } 12118bc2b39SBengt Jonsson 12218bc2b39SBengt Jonsson /* 1237384744dSAxel Lin * To satisfy both HW high power request and SW request, the regulator 1247384744dSAxel Lin * must be on in high power. 12518bc2b39SBengt Jonsson */ 12618bc2b39SBengt Jonsson if (info->cfg && info->cfg->hwreq) 1277384744dSAxel Lin regval = info->update_val_hp; 1287384744dSAxel Lin else 1297384744dSAxel Lin regval = info->update_val; 13018bc2b39SBengt Jonsson 13118bc2b39SBengt Jonsson ret = abx500_mask_and_set_register_interruptible(info->dev, 13218bc2b39SBengt Jonsson info->update_bank, info->update_reg, 1337384744dSAxel Lin info->update_mask, regval); 13437daa8aeSAxel Lin if (ret < 0) { 13580a9c22aSAxel Lin dev_err(rdev_get_dev(rdev), 1367384744dSAxel Lin "couldn't set enable bits for regulator\n"); 13737daa8aeSAxel Lin return ret; 13837daa8aeSAxel Lin } 13918bc2b39SBengt Jonsson 1407384744dSAxel Lin dev_dbg(rdev_get_dev(rdev), 1417384744dSAxel Lin "%s-enable (bank, reg, mask, value): 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 1427384744dSAxel Lin info->desc.name, info->update_bank, info->update_reg, 1437384744dSAxel Lin info->update_mask, regval); 1447384744dSAxel Lin 1457384744dSAxel Lin return 0; 146d1a82001SLee Jones } 147d1a82001SLee Jones 148d1a82001SLee Jones static int ab8500_ext_regulator_disable(struct regulator_dev *rdev) 149d1a82001SLee Jones { 150d1a82001SLee Jones int ret; 151d1a82001SLee Jones struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 15218bc2b39SBengt Jonsson u8 regval; 153d1a82001SLee Jones 154d1a82001SLee Jones if (info == NULL) { 155d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 156d1a82001SLee Jones return -EINVAL; 157d1a82001SLee Jones } 158d1a82001SLee Jones 1597384744dSAxel Lin /* 1607384744dSAxel Lin * Set the regulator in HW request mode if configured 1617384744dSAxel Lin */ 1627384744dSAxel Lin if (info->cfg && info->cfg->hwreq) 1637384744dSAxel Lin regval = info->update_val_hw; 1647384744dSAxel Lin else 1657384744dSAxel Lin regval = 0; 1667384744dSAxel Lin 1677384744dSAxel Lin ret = abx500_mask_and_set_register_interruptible(info->dev, 1687384744dSAxel Lin info->update_bank, info->update_reg, 1697384744dSAxel Lin info->update_mask, regval); 1707384744dSAxel Lin if (ret < 0) { 17180a9c22aSAxel Lin dev_err(rdev_get_dev(rdev), 1727384744dSAxel Lin "couldn't set disable bits for regulator\n"); 1737384744dSAxel Lin return ret; 1747384744dSAxel Lin } 175d1a82001SLee Jones 176d1a82001SLee Jones dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):" 177d1a82001SLee Jones " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 178d1a82001SLee Jones info->desc.name, info->update_bank, info->update_reg, 17918bc2b39SBengt Jonsson info->update_mask, regval); 180d1a82001SLee Jones 1817384744dSAxel Lin return 0; 182d1a82001SLee Jones } 183d1a82001SLee Jones 184d1a82001SLee Jones static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev) 185d1a82001SLee Jones { 186d1a82001SLee Jones int ret; 187d1a82001SLee Jones struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 188d1a82001SLee Jones u8 regval; 189d1a82001SLee Jones 190d1a82001SLee Jones if (info == NULL) { 191d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 192d1a82001SLee Jones return -EINVAL; 193d1a82001SLee Jones } 194d1a82001SLee Jones 195d1a82001SLee Jones ret = abx500_get_register_interruptible(info->dev, 196d1a82001SLee Jones info->update_bank, info->update_reg, ®val); 197d1a82001SLee Jones if (ret < 0) { 198d1a82001SLee Jones dev_err(rdev_get_dev(rdev), 199d1a82001SLee Jones "couldn't read 0x%x register\n", info->update_reg); 200d1a82001SLee Jones return ret; 201d1a82001SLee Jones } 202d1a82001SLee Jones 203d1a82001SLee Jones dev_dbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value):" 204d1a82001SLee Jones " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 205d1a82001SLee Jones info->desc.name, info->update_bank, info->update_reg, 206d1a82001SLee Jones info->update_mask, regval); 207d1a82001SLee Jones 20818bc2b39SBengt Jonsson if (((regval & info->update_mask) == info->update_val_lp) || 20918bc2b39SBengt Jonsson ((regval & info->update_mask) == info->update_val_hp)) 2109ab51a0eSAxel Lin return 1; 211d1a82001SLee Jones else 2129ab51a0eSAxel Lin return 0; 213d1a82001SLee Jones } 214d1a82001SLee Jones 215d1a82001SLee Jones static int ab8500_ext_regulator_set_mode(struct regulator_dev *rdev, 216d1a82001SLee Jones unsigned int mode) 217d1a82001SLee Jones { 218d1a82001SLee Jones int ret = 0; 219d1a82001SLee Jones struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 22066511fa4SAxel Lin u8 regval; 221d1a82001SLee Jones 222d1a82001SLee Jones if (info == NULL) { 223d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 224d1a82001SLee Jones return -EINVAL; 225d1a82001SLee Jones } 226d1a82001SLee Jones 227d1a82001SLee Jones switch (mode) { 228d1a82001SLee Jones case REGULATOR_MODE_NORMAL: 22966511fa4SAxel Lin regval = info->update_val_hp; 230d1a82001SLee Jones break; 231d1a82001SLee Jones case REGULATOR_MODE_IDLE: 23266511fa4SAxel Lin regval = info->update_val_lp; 233d1a82001SLee Jones break; 234d1a82001SLee Jones 235d1a82001SLee Jones default: 236d1a82001SLee Jones return -EINVAL; 237d1a82001SLee Jones } 238d1a82001SLee Jones 23966511fa4SAxel Lin /* If regulator is enabled and info->cfg->hwreq is set, the regulator 24066511fa4SAxel Lin must be on in high power, so we don't need to write the register with 24166511fa4SAxel Lin the same value. 24266511fa4SAxel Lin */ 24366511fa4SAxel Lin if (ab8500_ext_regulator_is_enabled(rdev) && 24466511fa4SAxel Lin !(info->cfg && info->cfg->hwreq)) { 24566511fa4SAxel Lin ret = abx500_mask_and_set_register_interruptible(info->dev, 24666511fa4SAxel Lin info->update_bank, info->update_reg, 24766511fa4SAxel Lin info->update_mask, regval); 24866511fa4SAxel Lin if (ret < 0) { 249d1a82001SLee Jones dev_err(rdev_get_dev(rdev), 250d1a82001SLee Jones "Could not set regulator mode.\n"); 25166511fa4SAxel Lin return ret; 25266511fa4SAxel Lin } 253d1a82001SLee Jones 254d1a82001SLee Jones dev_dbg(rdev_get_dev(rdev), 255d1a82001SLee Jones "%s-set_mode (bank, reg, mask, value): " 256d1a82001SLee Jones "0x%x, 0x%x, 0x%x, 0x%x\n", 257d1a82001SLee Jones info->desc.name, info->update_bank, info->update_reg, 258d1a82001SLee Jones info->update_mask, regval); 259d1a82001SLee Jones } 260d1a82001SLee Jones 26166511fa4SAxel Lin info->update_val = regval; 26266511fa4SAxel Lin 26366511fa4SAxel Lin return 0; 264d1a82001SLee Jones } 265d1a82001SLee Jones 266d1a82001SLee Jones static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev) 267d1a82001SLee Jones { 268d1a82001SLee Jones struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 269d1a82001SLee Jones int ret; 270d1a82001SLee Jones 271d1a82001SLee Jones if (info == NULL) { 272d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 273d1a82001SLee Jones return -EINVAL; 274d1a82001SLee Jones } 275d1a82001SLee Jones 276d1a82001SLee Jones if (info->update_val == info->update_val_hp) 277d1a82001SLee Jones ret = REGULATOR_MODE_NORMAL; 278d1a82001SLee Jones else if (info->update_val == info->update_val_lp) 279d1a82001SLee Jones ret = REGULATOR_MODE_IDLE; 280d1a82001SLee Jones else 281d1a82001SLee Jones ret = -EINVAL; 282d1a82001SLee Jones 283d1a82001SLee Jones return ret; 284d1a82001SLee Jones } 285d1a82001SLee Jones 28633fb8802SLee Jones static int ab8500_ext_set_voltage(struct regulator_dev *rdev, int min_uV, 28733fb8802SLee Jones int max_uV, unsigned *selector) 28833fb8802SLee Jones { 28933fb8802SLee Jones struct regulation_constraints *regu_constraints = rdev->constraints; 29033fb8802SLee Jones 29133fb8802SLee Jones if (!regu_constraints) { 29233fb8802SLee Jones dev_err(rdev_get_dev(rdev), "No regulator constraints\n"); 29333fb8802SLee Jones return -EINVAL; 29433fb8802SLee Jones } 29533fb8802SLee Jones 29633fb8802SLee Jones if (regu_constraints->min_uV == min_uV && 29733fb8802SLee Jones regu_constraints->max_uV == max_uV) 29833fb8802SLee Jones return 0; 29933fb8802SLee Jones 30033fb8802SLee Jones dev_err(rdev_get_dev(rdev), 30133fb8802SLee Jones "Requested min %duV max %duV != constrained min %duV max %duV\n", 30233fb8802SLee Jones min_uV, max_uV, 30333fb8802SLee Jones regu_constraints->min_uV, regu_constraints->max_uV); 30433fb8802SLee Jones 30533fb8802SLee Jones return -EINVAL; 30633fb8802SLee Jones } 30733fb8802SLee Jones 308d1a82001SLee Jones static int ab8500_ext_list_voltage(struct regulator_dev *rdev, 309d1a82001SLee Jones unsigned selector) 310d1a82001SLee Jones { 311d1a82001SLee Jones struct regulation_constraints *regu_constraints = rdev->constraints; 312d1a82001SLee Jones 313d1a82001SLee Jones if (regu_constraints == NULL) { 314d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n"); 315d1a82001SLee Jones return -EINVAL; 316d1a82001SLee Jones } 317d1a82001SLee Jones /* return the uV for the fixed regulators */ 318d1a82001SLee Jones if (regu_constraints->min_uV && regu_constraints->max_uV) { 319d1a82001SLee Jones if (regu_constraints->min_uV == regu_constraints->max_uV) 320d1a82001SLee Jones return regu_constraints->min_uV; 321d1a82001SLee Jones } 322d1a82001SLee Jones return -EINVAL; 323d1a82001SLee Jones } 324d1a82001SLee Jones 3258e5be4f7SAxel Lin static const struct regulator_ops ab8500_ext_regulator_ops = { 326d1a82001SLee Jones .enable = ab8500_ext_regulator_enable, 327d1a82001SLee Jones .disable = ab8500_ext_regulator_disable, 328d1a82001SLee Jones .is_enabled = ab8500_ext_regulator_is_enabled, 329d1a82001SLee Jones .set_mode = ab8500_ext_regulator_set_mode, 330d1a82001SLee Jones .get_mode = ab8500_ext_regulator_get_mode, 33133fb8802SLee Jones .set_voltage = ab8500_ext_set_voltage, 332d1a82001SLee Jones .list_voltage = ab8500_ext_list_voltage, 333d1a82001SLee Jones }; 334d1a82001SLee Jones 335d1a82001SLee Jones static struct ab8500_ext_regulator_info 336d1a82001SLee Jones ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = { 337d1a82001SLee Jones [AB8500_EXT_SUPPLY1] = { 338d1a82001SLee Jones .desc = { 339d1a82001SLee Jones .name = "VEXTSUPPLY1", 34048cb9737SAxel Lin .of_match = of_match_ptr("ab8500_ext1"), 341d1a82001SLee Jones .ops = &ab8500_ext_regulator_ops, 342d1a82001SLee Jones .type = REGULATOR_VOLTAGE, 343d1a82001SLee Jones .id = AB8500_EXT_SUPPLY1, 344d1a82001SLee Jones .owner = THIS_MODULE, 345d1a82001SLee Jones .n_voltages = 1, 346d1a82001SLee Jones }, 347d1a82001SLee Jones .update_bank = 0x04, 348d1a82001SLee Jones .update_reg = 0x08, 349d1a82001SLee Jones .update_mask = 0x03, 350d1a82001SLee Jones .update_val = 0x01, 351d1a82001SLee Jones .update_val_hp = 0x01, 352d1a82001SLee Jones .update_val_lp = 0x03, 353d1a82001SLee Jones .update_val_hw = 0x02, 354d1a82001SLee Jones }, 355d1a82001SLee Jones [AB8500_EXT_SUPPLY2] = { 356d1a82001SLee Jones .desc = { 357d1a82001SLee Jones .name = "VEXTSUPPLY2", 35848cb9737SAxel Lin .of_match = of_match_ptr("ab8500_ext2"), 359d1a82001SLee Jones .ops = &ab8500_ext_regulator_ops, 360d1a82001SLee Jones .type = REGULATOR_VOLTAGE, 361d1a82001SLee Jones .id = AB8500_EXT_SUPPLY2, 362d1a82001SLee Jones .owner = THIS_MODULE, 363d1a82001SLee Jones .n_voltages = 1, 364d1a82001SLee Jones }, 365d1a82001SLee Jones .update_bank = 0x04, 366d1a82001SLee Jones .update_reg = 0x08, 367d1a82001SLee Jones .update_mask = 0x0c, 368d1a82001SLee Jones .update_val = 0x04, 369d1a82001SLee Jones .update_val_hp = 0x04, 370d1a82001SLee Jones .update_val_lp = 0x0c, 371d1a82001SLee Jones .update_val_hw = 0x08, 372d1a82001SLee Jones }, 373d1a82001SLee Jones [AB8500_EXT_SUPPLY3] = { 374d1a82001SLee Jones .desc = { 375d1a82001SLee Jones .name = "VEXTSUPPLY3", 37648cb9737SAxel Lin .of_match = of_match_ptr("ab8500_ext3"), 377d1a82001SLee Jones .ops = &ab8500_ext_regulator_ops, 378d1a82001SLee Jones .type = REGULATOR_VOLTAGE, 379d1a82001SLee Jones .id = AB8500_EXT_SUPPLY3, 380d1a82001SLee Jones .owner = THIS_MODULE, 381d1a82001SLee Jones .n_voltages = 1, 382d1a82001SLee Jones }, 383d1a82001SLee Jones .update_bank = 0x04, 384d1a82001SLee Jones .update_reg = 0x08, 385d1a82001SLee Jones .update_mask = 0x30, 386d1a82001SLee Jones .update_val = 0x10, 38718bc2b39SBengt Jonsson .update_val_hp = 0x10, 38818bc2b39SBengt Jonsson .update_val_lp = 0x30, 38918bc2b39SBengt Jonsson .update_val_hw = 0x20, 390d1a82001SLee Jones }, 391d1a82001SLee Jones }; 392d1a82001SLee Jones 39308d49f43SSachin Kamat static int ab8500_ext_regulator_probe(struct platform_device *pdev) 394d1a82001SLee Jones { 395d1a82001SLee Jones struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); 396d1a82001SLee Jones struct regulator_config config = { }; 39780a9c22aSAxel Lin struct regulator_dev *rdev; 39848cb9737SAxel Lin int i; 39930aa4b26SLee Jones 400d1a82001SLee Jones if (!ab8500) { 401d1a82001SLee Jones dev_err(&pdev->dev, "null mfd parent\n"); 402d1a82001SLee Jones return -EINVAL; 403d1a82001SLee Jones } 40430aa4b26SLee Jones 405d1a82001SLee Jones /* check for AB8500 2.x */ 406a6324709SBengt Jonsson if (is_ab8500_2p0_or_earlier(ab8500)) { 407d1a82001SLee Jones struct ab8500_ext_regulator_info *info; 408d1a82001SLee Jones 409d1a82001SLee Jones /* VextSupply3LPn is inverted on AB8500 2.x */ 410d1a82001SLee Jones info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3]; 411d1a82001SLee Jones info->update_val = 0x30; 41218bc2b39SBengt Jonsson info->update_val_hp = 0x30; 41318bc2b39SBengt Jonsson info->update_val_lp = 0x10; 414d1a82001SLee Jones } 415d1a82001SLee Jones 416d1a82001SLee Jones /* register all regulators */ 417d1a82001SLee Jones for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { 418d1a82001SLee Jones struct ab8500_ext_regulator_info *info = NULL; 419d1a82001SLee Jones 420d1a82001SLee Jones /* assign per-regulator data */ 421d1a82001SLee Jones info = &ab8500_ext_regulator_info[i]; 422d1a82001SLee Jones info->dev = &pdev->dev; 42318bc2b39SBengt Jonsson info->cfg = (struct ab8500_ext_regulator_cfg *) 424c512150bSLinus Walleij ab8500_ext_regulators[i].driver_data; 425d1a82001SLee Jones 426d1a82001SLee Jones config.dev = &pdev->dev; 427d1a82001SLee Jones config.driver_data = info; 428c512150bSLinus Walleij config.init_data = &ab8500_ext_regulators[i]; 429d1a82001SLee Jones 430d1a82001SLee Jones /* register regulator with framework */ 43180a9c22aSAxel Lin rdev = devm_regulator_register(&pdev->dev, &info->desc, 432a4a6b9deSJingoo Han &config); 43380a9c22aSAxel Lin if (IS_ERR(rdev)) { 434d1a82001SLee Jones dev_err(&pdev->dev, "failed to register regulator %s\n", 435d1a82001SLee Jones info->desc.name); 43680a9c22aSAxel Lin return PTR_ERR(rdev); 437d1a82001SLee Jones } 438d1a82001SLee Jones 43980a9c22aSAxel Lin dev_dbg(&pdev->dev, "%s-probed\n", info->desc.name); 440d1a82001SLee Jones } 441d1a82001SLee Jones 442d1a82001SLee Jones return 0; 443d1a82001SLee Jones } 444d1a82001SLee Jones 4455a49b4a5SLee Jones static struct platform_driver ab8500_ext_regulator_driver = { 4465a49b4a5SLee Jones .probe = ab8500_ext_regulator_probe, 4475a49b4a5SLee Jones .driver = { 4485a49b4a5SLee Jones .name = "ab8500-ext-regulator", 449*259b93b2SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 4505a49b4a5SLee Jones }, 4515a49b4a5SLee Jones }; 4525a49b4a5SLee Jones 4535a49b4a5SLee Jones static int __init ab8500_ext_regulator_init(void) 4545a49b4a5SLee Jones { 4555a49b4a5SLee Jones int ret; 4565a49b4a5SLee Jones 4575a49b4a5SLee Jones ret = platform_driver_register(&ab8500_ext_regulator_driver); 4585a49b4a5SLee Jones if (ret) 4595a49b4a5SLee Jones pr_err("Failed to register ab8500 ext regulator: %d\n", ret); 4605a49b4a5SLee Jones 4615a49b4a5SLee Jones return ret; 4625a49b4a5SLee Jones } 4635a49b4a5SLee Jones subsys_initcall(ab8500_ext_regulator_init); 4645a49b4a5SLee Jones 4655a49b4a5SLee Jones static void __exit ab8500_ext_regulator_exit(void) 4665a49b4a5SLee Jones { 4675a49b4a5SLee Jones platform_driver_unregister(&ab8500_ext_regulator_driver); 4685a49b4a5SLee Jones } 4695a49b4a5SLee Jones module_exit(ab8500_ext_regulator_exit); 4705a49b4a5SLee Jones 471d1a82001SLee Jones MODULE_LICENSE("GPL v2"); 472d1a82001SLee Jones MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>"); 473d1a82001SLee Jones MODULE_DESCRIPTION("AB8500 external regulator driver"); 474d1a82001SLee Jones MODULE_ALIAS("platform:ab8500-ext-regulator"); 475