1d1a82001SLee Jones /* 2d1a82001SLee Jones * Copyright (C) ST-Ericsson SA 2010 3d1a82001SLee Jones * 4d1a82001SLee Jones * License Terms: GNU General Public License v2 5d1a82001SLee Jones * 6d1a82001SLee Jones * Authors: Bengt Jonsson <bengt.g.jonsson@stericsson.com> 7d1a82001SLee Jones * 8d1a82001SLee Jones * This file is based on drivers/regulator/ab8500.c 9d1a82001SLee Jones * 10d1a82001SLee Jones * AB8500 external regulators 11d1a82001SLee Jones * 12d1a82001SLee Jones * ab8500-ext supports the following regulators: 13d1a82001SLee Jones * - VextSupply3 14d1a82001SLee Jones */ 15d1a82001SLee Jones #include <linux/init.h> 16d1a82001SLee Jones #include <linux/kernel.h> 17d1a82001SLee Jones #include <linux/err.h> 18d1a82001SLee Jones #include <linux/module.h> 19d1a82001SLee Jones #include <linux/platform_device.h> 20d1a82001SLee Jones #include <linux/regulator/driver.h> 21d1a82001SLee Jones #include <linux/regulator/machine.h> 22d1a82001SLee Jones #include <linux/mfd/abx500.h> 23d1a82001SLee Jones #include <linux/mfd/abx500/ab8500.h> 24d1a82001SLee Jones #include <linux/regulator/ab8500.h> 25d1a82001SLee Jones 26d1a82001SLee Jones /** 27d1a82001SLee Jones * struct ab8500_ext_regulator_info - ab8500 regulator information 28d1a82001SLee Jones * @dev: device pointer 29d1a82001SLee Jones * @desc: regulator description 30d1a82001SLee Jones * @rdev: regulator device 3118bc2b39SBengt Jonsson * @cfg: regulator configuration (extension of regulator FW configuration) 32d1a82001SLee Jones * @update_bank: bank to control on/off 33d1a82001SLee Jones * @update_reg: register to control on/off 34d1a82001SLee Jones * @update_mask: mask to enable/disable and set mode of regulator 35d1a82001SLee Jones * @update_val: bits holding the regulator current mode 3618bc2b39SBengt Jonsson * @update_val_hp: bits to set EN pin active (LPn pin deactive) 37d1a82001SLee Jones * normally this means high power mode 3818bc2b39SBengt Jonsson * @update_val_lp: bits to set EN pin active and LPn pin active 39d1a82001SLee Jones * normally this means low power mode 4018bc2b39SBengt Jonsson * @update_val_hw: bits to set regulator pins in HW control 4118bc2b39SBengt Jonsson * SysClkReq pins and logic will choose mode 42d1a82001SLee Jones */ 43d1a82001SLee Jones struct ab8500_ext_regulator_info { 44d1a82001SLee Jones struct device *dev; 45d1a82001SLee Jones struct regulator_desc desc; 46d1a82001SLee Jones struct regulator_dev *rdev; 4718bc2b39SBengt Jonsson struct ab8500_ext_regulator_cfg *cfg; 48d1a82001SLee Jones u8 update_bank; 49d1a82001SLee Jones u8 update_reg; 50d1a82001SLee Jones u8 update_mask; 51d1a82001SLee Jones u8 update_val; 5218bc2b39SBengt Jonsson u8 update_val_hp; 5318bc2b39SBengt Jonsson u8 update_val_lp; 5418bc2b39SBengt Jonsson u8 update_val_hw; 55d1a82001SLee Jones }; 56d1a82001SLee Jones 5718bc2b39SBengt Jonsson static int ab8500_ext_regulator_enable(struct regulator_dev *rdev) 5818bc2b39SBengt Jonsson { 5918bc2b39SBengt Jonsson int ret; 6018bc2b39SBengt Jonsson struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 6118bc2b39SBengt Jonsson u8 regval; 6218bc2b39SBengt Jonsson 6318bc2b39SBengt Jonsson if (info == NULL) { 6418bc2b39SBengt Jonsson dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 6518bc2b39SBengt Jonsson return -EINVAL; 6618bc2b39SBengt Jonsson } 6718bc2b39SBengt Jonsson 6818bc2b39SBengt Jonsson /* 697384744dSAxel Lin * To satisfy both HW high power request and SW request, the regulator 707384744dSAxel Lin * must be on in high power. 7118bc2b39SBengt Jonsson */ 7218bc2b39SBengt Jonsson if (info->cfg && info->cfg->hwreq) 737384744dSAxel Lin regval = info->update_val_hp; 747384744dSAxel Lin else 757384744dSAxel Lin regval = info->update_val; 7618bc2b39SBengt Jonsson 7718bc2b39SBengt Jonsson ret = abx500_mask_and_set_register_interruptible(info->dev, 7818bc2b39SBengt Jonsson info->update_bank, info->update_reg, 797384744dSAxel Lin info->update_mask, regval); 8037daa8aeSAxel Lin if (ret < 0) { 8118bc2b39SBengt Jonsson dev_err(rdev_get_dev(info->rdev), 827384744dSAxel Lin "couldn't set enable bits for regulator\n"); 8337daa8aeSAxel Lin return ret; 8437daa8aeSAxel Lin } 8518bc2b39SBengt Jonsson 867384744dSAxel Lin dev_dbg(rdev_get_dev(rdev), 877384744dSAxel Lin "%s-enable (bank, reg, mask, value): 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 887384744dSAxel Lin info->desc.name, info->update_bank, info->update_reg, 897384744dSAxel Lin info->update_mask, regval); 907384744dSAxel Lin 917384744dSAxel Lin return 0; 92d1a82001SLee Jones } 93d1a82001SLee Jones 94d1a82001SLee Jones static int ab8500_ext_regulator_disable(struct regulator_dev *rdev) 95d1a82001SLee Jones { 96d1a82001SLee Jones int ret; 97d1a82001SLee Jones struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 9818bc2b39SBengt Jonsson u8 regval; 99d1a82001SLee Jones 100d1a82001SLee Jones if (info == NULL) { 101d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 102d1a82001SLee Jones return -EINVAL; 103d1a82001SLee Jones } 104d1a82001SLee Jones 1057384744dSAxel Lin /* 1067384744dSAxel Lin * Set the regulator in HW request mode if configured 1077384744dSAxel Lin */ 1087384744dSAxel Lin if (info->cfg && info->cfg->hwreq) 1097384744dSAxel Lin regval = info->update_val_hw; 1107384744dSAxel Lin else 1117384744dSAxel Lin regval = 0; 1127384744dSAxel Lin 1137384744dSAxel Lin ret = abx500_mask_and_set_register_interruptible(info->dev, 1147384744dSAxel Lin info->update_bank, info->update_reg, 1157384744dSAxel Lin info->update_mask, regval); 1167384744dSAxel Lin if (ret < 0) { 1177384744dSAxel Lin dev_err(rdev_get_dev(info->rdev), 1187384744dSAxel Lin "couldn't set disable bits for regulator\n"); 1197384744dSAxel Lin return ret; 1207384744dSAxel Lin } 121d1a82001SLee Jones 122d1a82001SLee Jones dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):" 123d1a82001SLee Jones " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 124d1a82001SLee Jones info->desc.name, info->update_bank, info->update_reg, 12518bc2b39SBengt Jonsson info->update_mask, regval); 126d1a82001SLee Jones 1277384744dSAxel Lin return 0; 128d1a82001SLee Jones } 129d1a82001SLee Jones 130d1a82001SLee Jones static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev) 131d1a82001SLee Jones { 132d1a82001SLee Jones int ret; 133d1a82001SLee Jones struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 134d1a82001SLee Jones u8 regval; 135d1a82001SLee Jones 136d1a82001SLee Jones if (info == NULL) { 137d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 138d1a82001SLee Jones return -EINVAL; 139d1a82001SLee Jones } 140d1a82001SLee Jones 141d1a82001SLee Jones ret = abx500_get_register_interruptible(info->dev, 142d1a82001SLee Jones info->update_bank, info->update_reg, ®val); 143d1a82001SLee Jones if (ret < 0) { 144d1a82001SLee Jones dev_err(rdev_get_dev(rdev), 145d1a82001SLee Jones "couldn't read 0x%x register\n", info->update_reg); 146d1a82001SLee Jones return ret; 147d1a82001SLee Jones } 148d1a82001SLee Jones 149d1a82001SLee Jones dev_dbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value):" 150d1a82001SLee Jones " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 151d1a82001SLee Jones info->desc.name, info->update_bank, info->update_reg, 152d1a82001SLee Jones info->update_mask, regval); 153d1a82001SLee Jones 15418bc2b39SBengt Jonsson if (((regval & info->update_mask) == info->update_val_lp) || 15518bc2b39SBengt Jonsson ((regval & info->update_mask) == info->update_val_hp)) 1569ab51a0eSAxel Lin return 1; 157d1a82001SLee Jones else 1589ab51a0eSAxel Lin return 0; 159d1a82001SLee Jones } 160d1a82001SLee Jones 161d1a82001SLee Jones static int ab8500_ext_regulator_set_mode(struct regulator_dev *rdev, 162d1a82001SLee Jones unsigned int mode) 163d1a82001SLee Jones { 164d1a82001SLee Jones int ret = 0; 165d1a82001SLee Jones struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 16666511fa4SAxel Lin u8 regval; 167d1a82001SLee Jones 168d1a82001SLee Jones if (info == NULL) { 169d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 170d1a82001SLee Jones return -EINVAL; 171d1a82001SLee Jones } 172d1a82001SLee Jones 173d1a82001SLee Jones switch (mode) { 174d1a82001SLee Jones case REGULATOR_MODE_NORMAL: 17566511fa4SAxel Lin regval = info->update_val_hp; 176d1a82001SLee Jones break; 177d1a82001SLee Jones case REGULATOR_MODE_IDLE: 17866511fa4SAxel Lin regval = info->update_val_lp; 179d1a82001SLee Jones break; 180d1a82001SLee Jones 181d1a82001SLee Jones default: 182d1a82001SLee Jones return -EINVAL; 183d1a82001SLee Jones } 184d1a82001SLee Jones 18566511fa4SAxel Lin /* If regulator is enabled and info->cfg->hwreq is set, the regulator 18666511fa4SAxel Lin must be on in high power, so we don't need to write the register with 18766511fa4SAxel Lin the same value. 18866511fa4SAxel Lin */ 18966511fa4SAxel Lin if (ab8500_ext_regulator_is_enabled(rdev) && 19066511fa4SAxel Lin !(info->cfg && info->cfg->hwreq)) { 19166511fa4SAxel Lin ret = abx500_mask_and_set_register_interruptible(info->dev, 19266511fa4SAxel Lin info->update_bank, info->update_reg, 19366511fa4SAxel Lin info->update_mask, regval); 19466511fa4SAxel Lin if (ret < 0) { 195d1a82001SLee Jones dev_err(rdev_get_dev(rdev), 196d1a82001SLee Jones "Could not set regulator mode.\n"); 19766511fa4SAxel Lin return ret; 19866511fa4SAxel Lin } 199d1a82001SLee Jones 200d1a82001SLee Jones dev_dbg(rdev_get_dev(rdev), 201d1a82001SLee Jones "%s-set_mode (bank, reg, mask, value): " 202d1a82001SLee Jones "0x%x, 0x%x, 0x%x, 0x%x\n", 203d1a82001SLee Jones info->desc.name, info->update_bank, info->update_reg, 204d1a82001SLee Jones info->update_mask, regval); 205d1a82001SLee Jones } 206d1a82001SLee Jones 20766511fa4SAxel Lin info->update_val = regval; 20866511fa4SAxel Lin 20966511fa4SAxel Lin return 0; 210d1a82001SLee Jones } 211d1a82001SLee Jones 212d1a82001SLee Jones static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev) 213d1a82001SLee Jones { 214d1a82001SLee Jones struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 215d1a82001SLee Jones int ret; 216d1a82001SLee Jones 217d1a82001SLee Jones if (info == NULL) { 218d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 219d1a82001SLee Jones return -EINVAL; 220d1a82001SLee Jones } 221d1a82001SLee Jones 222d1a82001SLee Jones if (info->update_val == info->update_val_hp) 223d1a82001SLee Jones ret = REGULATOR_MODE_NORMAL; 224d1a82001SLee Jones else if (info->update_val == info->update_val_lp) 225d1a82001SLee Jones ret = REGULATOR_MODE_IDLE; 226d1a82001SLee Jones else 227d1a82001SLee Jones ret = -EINVAL; 228d1a82001SLee Jones 229d1a82001SLee Jones return ret; 230d1a82001SLee Jones } 231d1a82001SLee Jones 23233fb8802SLee Jones static int ab8500_ext_set_voltage(struct regulator_dev *rdev, int min_uV, 23333fb8802SLee Jones int max_uV, unsigned *selector) 23433fb8802SLee Jones { 23533fb8802SLee Jones struct regulation_constraints *regu_constraints = rdev->constraints; 23633fb8802SLee Jones 23733fb8802SLee Jones if (!regu_constraints) { 23833fb8802SLee Jones dev_err(rdev_get_dev(rdev), "No regulator constraints\n"); 23933fb8802SLee Jones return -EINVAL; 24033fb8802SLee Jones } 24133fb8802SLee Jones 24233fb8802SLee Jones if (regu_constraints->min_uV == min_uV && 24333fb8802SLee Jones regu_constraints->max_uV == max_uV) 24433fb8802SLee Jones return 0; 24533fb8802SLee Jones 24633fb8802SLee Jones dev_err(rdev_get_dev(rdev), 24733fb8802SLee Jones "Requested min %duV max %duV != constrained min %duV max %duV\n", 24833fb8802SLee Jones min_uV, max_uV, 24933fb8802SLee Jones regu_constraints->min_uV, regu_constraints->max_uV); 25033fb8802SLee Jones 25133fb8802SLee Jones return -EINVAL; 25233fb8802SLee Jones } 25333fb8802SLee Jones 254d1a82001SLee Jones static int ab8500_ext_list_voltage(struct regulator_dev *rdev, 255d1a82001SLee Jones unsigned selector) 256d1a82001SLee Jones { 257d1a82001SLee Jones struct regulation_constraints *regu_constraints = rdev->constraints; 258d1a82001SLee Jones 259d1a82001SLee Jones if (regu_constraints == NULL) { 260d1a82001SLee Jones dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n"); 261d1a82001SLee Jones return -EINVAL; 262d1a82001SLee Jones } 263d1a82001SLee Jones /* return the uV for the fixed regulators */ 264d1a82001SLee Jones if (regu_constraints->min_uV && regu_constraints->max_uV) { 265d1a82001SLee Jones if (regu_constraints->min_uV == regu_constraints->max_uV) 266d1a82001SLee Jones return regu_constraints->min_uV; 267d1a82001SLee Jones } 268d1a82001SLee Jones return -EINVAL; 269d1a82001SLee Jones } 270d1a82001SLee Jones 271d1a82001SLee Jones static struct regulator_ops ab8500_ext_regulator_ops = { 272d1a82001SLee Jones .enable = ab8500_ext_regulator_enable, 273d1a82001SLee Jones .disable = ab8500_ext_regulator_disable, 274d1a82001SLee Jones .is_enabled = ab8500_ext_regulator_is_enabled, 275d1a82001SLee Jones .set_mode = ab8500_ext_regulator_set_mode, 276d1a82001SLee Jones .get_mode = ab8500_ext_regulator_get_mode, 27733fb8802SLee Jones .set_voltage = ab8500_ext_set_voltage, 278d1a82001SLee Jones .list_voltage = ab8500_ext_list_voltage, 279d1a82001SLee Jones }; 280d1a82001SLee Jones 281d1a82001SLee Jones static struct ab8500_ext_regulator_info 282d1a82001SLee Jones ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = { 283d1a82001SLee Jones [AB8500_EXT_SUPPLY1] = { 284d1a82001SLee Jones .desc = { 285d1a82001SLee Jones .name = "VEXTSUPPLY1", 286d1a82001SLee Jones .ops = &ab8500_ext_regulator_ops, 287d1a82001SLee Jones .type = REGULATOR_VOLTAGE, 288d1a82001SLee Jones .id = AB8500_EXT_SUPPLY1, 289d1a82001SLee Jones .owner = THIS_MODULE, 290d1a82001SLee Jones .n_voltages = 1, 291d1a82001SLee Jones }, 292d1a82001SLee Jones .update_bank = 0x04, 293d1a82001SLee Jones .update_reg = 0x08, 294d1a82001SLee Jones .update_mask = 0x03, 295d1a82001SLee Jones .update_val = 0x01, 296d1a82001SLee Jones .update_val_hp = 0x01, 297d1a82001SLee Jones .update_val_lp = 0x03, 298d1a82001SLee Jones .update_val_hw = 0x02, 299d1a82001SLee Jones }, 300d1a82001SLee Jones [AB8500_EXT_SUPPLY2] = { 301d1a82001SLee Jones .desc = { 302d1a82001SLee Jones .name = "VEXTSUPPLY2", 303d1a82001SLee Jones .ops = &ab8500_ext_regulator_ops, 304d1a82001SLee Jones .type = REGULATOR_VOLTAGE, 305d1a82001SLee Jones .id = AB8500_EXT_SUPPLY2, 306d1a82001SLee Jones .owner = THIS_MODULE, 307d1a82001SLee Jones .n_voltages = 1, 308d1a82001SLee Jones }, 309d1a82001SLee Jones .update_bank = 0x04, 310d1a82001SLee Jones .update_reg = 0x08, 311d1a82001SLee Jones .update_mask = 0x0c, 312d1a82001SLee Jones .update_val = 0x04, 313d1a82001SLee Jones .update_val_hp = 0x04, 314d1a82001SLee Jones .update_val_lp = 0x0c, 315d1a82001SLee Jones .update_val_hw = 0x08, 316d1a82001SLee Jones }, 317d1a82001SLee Jones [AB8500_EXT_SUPPLY3] = { 318d1a82001SLee Jones .desc = { 319d1a82001SLee Jones .name = "VEXTSUPPLY3", 320d1a82001SLee Jones .ops = &ab8500_ext_regulator_ops, 321d1a82001SLee Jones .type = REGULATOR_VOLTAGE, 322d1a82001SLee Jones .id = AB8500_EXT_SUPPLY3, 323d1a82001SLee Jones .owner = THIS_MODULE, 324d1a82001SLee Jones .n_voltages = 1, 325d1a82001SLee Jones }, 326d1a82001SLee Jones .update_bank = 0x04, 327d1a82001SLee Jones .update_reg = 0x08, 328d1a82001SLee Jones .update_mask = 0x30, 329d1a82001SLee Jones .update_val = 0x10, 33018bc2b39SBengt Jonsson .update_val_hp = 0x10, 33118bc2b39SBengt Jonsson .update_val_lp = 0x30, 33218bc2b39SBengt Jonsson .update_val_hw = 0x20, 333d1a82001SLee Jones }, 334d1a82001SLee Jones }; 335d1a82001SLee Jones 336*5a49b4a5SLee Jones int ab8500_ext_regulator_probe(struct platform_device *pdev) 337d1a82001SLee Jones { 338d1a82001SLee Jones struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); 339d1a82001SLee Jones struct ab8500_platform_data *ppdata; 340d1a82001SLee Jones struct ab8500_regulator_platform_data *pdata; 341d1a82001SLee Jones struct regulator_config config = { }; 342d1a82001SLee Jones int i, err; 343d1a82001SLee Jones 344d1a82001SLee Jones if (!ab8500) { 345d1a82001SLee Jones dev_err(&pdev->dev, "null mfd parent\n"); 346d1a82001SLee Jones return -EINVAL; 347d1a82001SLee Jones } 348d1a82001SLee Jones ppdata = dev_get_platdata(ab8500->dev); 349d1a82001SLee Jones if (!ppdata) { 350d1a82001SLee Jones dev_err(&pdev->dev, "null parent pdata\n"); 351d1a82001SLee Jones return -EINVAL; 352d1a82001SLee Jones } 353d1a82001SLee Jones 354d1a82001SLee Jones pdata = ppdata->regulator; 355d1a82001SLee Jones if (!pdata) { 356d1a82001SLee Jones dev_err(&pdev->dev, "null pdata\n"); 357d1a82001SLee Jones return -EINVAL; 358d1a82001SLee Jones } 359d1a82001SLee Jones 360d1a82001SLee Jones /* make sure the platform data has the correct size */ 361d1a82001SLee Jones if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) { 362d1a82001SLee Jones dev_err(&pdev->dev, "Configuration error: size mismatch.\n"); 363d1a82001SLee Jones return -EINVAL; 364d1a82001SLee Jones } 365d1a82001SLee Jones 366d1a82001SLee Jones /* check for AB8500 2.x */ 367a6324709SBengt Jonsson if (is_ab8500_2p0_or_earlier(ab8500)) { 368d1a82001SLee Jones struct ab8500_ext_regulator_info *info; 369d1a82001SLee Jones 370d1a82001SLee Jones /* VextSupply3LPn is inverted on AB8500 2.x */ 371d1a82001SLee Jones info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3]; 372d1a82001SLee Jones info->update_val = 0x30; 37318bc2b39SBengt Jonsson info->update_val_hp = 0x30; 37418bc2b39SBengt Jonsson info->update_val_lp = 0x10; 375d1a82001SLee Jones } 376d1a82001SLee Jones 377d1a82001SLee Jones /* register all regulators */ 378d1a82001SLee Jones for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { 379d1a82001SLee Jones struct ab8500_ext_regulator_info *info = NULL; 380d1a82001SLee Jones 381d1a82001SLee Jones /* assign per-regulator data */ 382d1a82001SLee Jones info = &ab8500_ext_regulator_info[i]; 383d1a82001SLee Jones info->dev = &pdev->dev; 38418bc2b39SBengt Jonsson info->cfg = (struct ab8500_ext_regulator_cfg *) 38518bc2b39SBengt Jonsson pdata->ext_regulator[i].driver_data; 386d1a82001SLee Jones 387d1a82001SLee Jones config.dev = &pdev->dev; 388d1a82001SLee Jones config.init_data = &pdata->ext_regulator[i]; 389d1a82001SLee Jones config.driver_data = info; 390d1a82001SLee Jones 391d1a82001SLee Jones /* register regulator with framework */ 392d1a82001SLee Jones info->rdev = regulator_register(&info->desc, &config); 393d1a82001SLee Jones if (IS_ERR(info->rdev)) { 394d1a82001SLee Jones err = PTR_ERR(info->rdev); 395d1a82001SLee Jones dev_err(&pdev->dev, "failed to register regulator %s\n", 396d1a82001SLee Jones info->desc.name); 397d1a82001SLee Jones /* when we fail, un-register all earlier regulators */ 398d1a82001SLee Jones while (--i >= 0) { 399d1a82001SLee Jones info = &ab8500_ext_regulator_info[i]; 400d1a82001SLee Jones regulator_unregister(info->rdev); 401d1a82001SLee Jones } 402d1a82001SLee Jones return err; 403d1a82001SLee Jones } 404d1a82001SLee Jones 405d1a82001SLee Jones dev_dbg(rdev_get_dev(info->rdev), 406d1a82001SLee Jones "%s-probed\n", info->desc.name); 407d1a82001SLee Jones } 408d1a82001SLee Jones 409d1a82001SLee Jones return 0; 410d1a82001SLee Jones } 411d1a82001SLee Jones 412*5a49b4a5SLee Jones int ab8500_ext_regulator_remove(struct platform_device *pdev) 413d1a82001SLee Jones { 414d1a82001SLee Jones int i; 415d1a82001SLee Jones 416d1a82001SLee Jones for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { 417d1a82001SLee Jones struct ab8500_ext_regulator_info *info = NULL; 418d1a82001SLee Jones info = &ab8500_ext_regulator_info[i]; 419d1a82001SLee Jones 420d1a82001SLee Jones dev_vdbg(rdev_get_dev(info->rdev), 421d1a82001SLee Jones "%s-remove\n", info->desc.name); 422d1a82001SLee Jones 423d1a82001SLee Jones regulator_unregister(info->rdev); 424d1a82001SLee Jones } 425*5a49b4a5SLee Jones 426*5a49b4a5SLee Jones return 0; 427d1a82001SLee Jones } 428d1a82001SLee Jones 429*5a49b4a5SLee Jones static struct platform_driver ab8500_ext_regulator_driver = { 430*5a49b4a5SLee Jones .probe = ab8500_ext_regulator_probe, 431*5a49b4a5SLee Jones .remove = ab8500_ext_regulator_remove, 432*5a49b4a5SLee Jones .driver = { 433*5a49b4a5SLee Jones .name = "ab8500-ext-regulator", 434*5a49b4a5SLee Jones .owner = THIS_MODULE, 435*5a49b4a5SLee Jones }, 436*5a49b4a5SLee Jones }; 437*5a49b4a5SLee Jones 438*5a49b4a5SLee Jones static int __init ab8500_ext_regulator_init(void) 439*5a49b4a5SLee Jones { 440*5a49b4a5SLee Jones int ret; 441*5a49b4a5SLee Jones 442*5a49b4a5SLee Jones ret = platform_driver_register(&ab8500_ext_regulator_driver); 443*5a49b4a5SLee Jones if (ret) 444*5a49b4a5SLee Jones pr_err("Failed to register ab8500 ext regulator: %d\n", ret); 445*5a49b4a5SLee Jones 446*5a49b4a5SLee Jones return ret; 447*5a49b4a5SLee Jones } 448*5a49b4a5SLee Jones subsys_initcall(ab8500_ext_regulator_init); 449*5a49b4a5SLee Jones 450*5a49b4a5SLee Jones static void __exit ab8500_ext_regulator_exit(void) 451*5a49b4a5SLee Jones { 452*5a49b4a5SLee Jones platform_driver_unregister(&ab8500_ext_regulator_driver); 453*5a49b4a5SLee Jones } 454*5a49b4a5SLee Jones module_exit(ab8500_ext_regulator_exit); 455*5a49b4a5SLee Jones 456d1a82001SLee Jones MODULE_LICENSE("GPL v2"); 457d1a82001SLee Jones MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>"); 458d1a82001SLee Jones MODULE_DESCRIPTION("AB8500 external regulator driver"); 459d1a82001SLee Jones MODULE_ALIAS("platform:ab8500-ext-regulator"); 460