162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: Bengt Jonsson <bengt.g.jonsson@stericsson.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file is based on drivers/regulator/ab8500.c 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * AB8500 external regulators 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * ab8500-ext supports the following regulators: 1262306a36Sopenharmony_ci * - VextSupply3 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/regulator/driver.h> 2162306a36Sopenharmony_ci#include <linux/regulator/machine.h> 2262306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 2362306a36Sopenharmony_ci#include <linux/mfd/abx500.h> 2462306a36Sopenharmony_ci#include <linux/mfd/abx500/ab8500.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* AB8500 external regulators */ 2762306a36Sopenharmony_cienum ab8500_ext_regulator_id { 2862306a36Sopenharmony_ci AB8500_EXT_SUPPLY1, 2962306a36Sopenharmony_ci AB8500_EXT_SUPPLY2, 3062306a36Sopenharmony_ci AB8500_EXT_SUPPLY3, 3162306a36Sopenharmony_ci AB8500_NUM_EXT_REGULATORS, 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct ab8500_ext_regulator_cfg { 3562306a36Sopenharmony_ci bool hwreq; /* requires hw mode or high power mode */ 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* supply for VextSupply3 */ 3962306a36Sopenharmony_cistatic struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = { 4062306a36Sopenharmony_ci /* SIM supply for 3 V SIM cards */ 4162306a36Sopenharmony_ci REGULATOR_SUPPLY("vinvsim", "sim-detect.0"), 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * AB8500 external regulators 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cistatic struct regulator_init_data ab8500_ext_regulators[] = { 4862306a36Sopenharmony_ci /* fixed Vbat supplies VSMPS1_EXT_1V8 */ 4962306a36Sopenharmony_ci [AB8500_EXT_SUPPLY1] = { 5062306a36Sopenharmony_ci .constraints = { 5162306a36Sopenharmony_ci .name = "ab8500-ext-supply1", 5262306a36Sopenharmony_ci .min_uV = 1800000, 5362306a36Sopenharmony_ci .max_uV = 1800000, 5462306a36Sopenharmony_ci .initial_mode = REGULATOR_MODE_IDLE, 5562306a36Sopenharmony_ci .boot_on = 1, 5662306a36Sopenharmony_ci .always_on = 1, 5762306a36Sopenharmony_ci }, 5862306a36Sopenharmony_ci }, 5962306a36Sopenharmony_ci /* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */ 6062306a36Sopenharmony_ci [AB8500_EXT_SUPPLY2] = { 6162306a36Sopenharmony_ci .constraints = { 6262306a36Sopenharmony_ci .name = "ab8500-ext-supply2", 6362306a36Sopenharmony_ci .min_uV = 1360000, 6462306a36Sopenharmony_ci .max_uV = 1360000, 6562306a36Sopenharmony_ci }, 6662306a36Sopenharmony_ci }, 6762306a36Sopenharmony_ci /* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */ 6862306a36Sopenharmony_ci [AB8500_EXT_SUPPLY3] = { 6962306a36Sopenharmony_ci .constraints = { 7062306a36Sopenharmony_ci .name = "ab8500-ext-supply3", 7162306a36Sopenharmony_ci .min_uV = 3400000, 7262306a36Sopenharmony_ci .max_uV = 3400000, 7362306a36Sopenharmony_ci .valid_ops_mask = REGULATOR_CHANGE_STATUS, 7462306a36Sopenharmony_ci .boot_on = 1, 7562306a36Sopenharmony_ci }, 7662306a36Sopenharmony_ci .num_consumer_supplies = 7762306a36Sopenharmony_ci ARRAY_SIZE(ab8500_ext_supply3_consumers), 7862306a36Sopenharmony_ci .consumer_supplies = ab8500_ext_supply3_consumers, 7962306a36Sopenharmony_ci }, 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/** 8362306a36Sopenharmony_ci * struct ab8500_ext_regulator_info - ab8500 regulator information 8462306a36Sopenharmony_ci * @dev: device pointer 8562306a36Sopenharmony_ci * @desc: regulator description 8662306a36Sopenharmony_ci * @cfg: regulator configuration (extension of regulator FW configuration) 8762306a36Sopenharmony_ci * @update_bank: bank to control on/off 8862306a36Sopenharmony_ci * @update_reg: register to control on/off 8962306a36Sopenharmony_ci * @update_mask: mask to enable/disable and set mode of regulator 9062306a36Sopenharmony_ci * @update_val: bits holding the regulator current mode 9162306a36Sopenharmony_ci * @update_val_hp: bits to set EN pin active (LPn pin deactive) 9262306a36Sopenharmony_ci * normally this means high power mode 9362306a36Sopenharmony_ci * @update_val_lp: bits to set EN pin active and LPn pin active 9462306a36Sopenharmony_ci * normally this means low power mode 9562306a36Sopenharmony_ci * @update_val_hw: bits to set regulator pins in HW control 9662306a36Sopenharmony_ci * SysClkReq pins and logic will choose mode 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_cistruct ab8500_ext_regulator_info { 9962306a36Sopenharmony_ci struct device *dev; 10062306a36Sopenharmony_ci struct regulator_desc desc; 10162306a36Sopenharmony_ci struct ab8500_ext_regulator_cfg *cfg; 10262306a36Sopenharmony_ci u8 update_bank; 10362306a36Sopenharmony_ci u8 update_reg; 10462306a36Sopenharmony_ci u8 update_mask; 10562306a36Sopenharmony_ci u8 update_val; 10662306a36Sopenharmony_ci u8 update_val_hp; 10762306a36Sopenharmony_ci u8 update_val_lp; 10862306a36Sopenharmony_ci u8 update_val_hw; 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int ab8500_ext_regulator_enable(struct regulator_dev *rdev) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci int ret; 11462306a36Sopenharmony_ci struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 11562306a36Sopenharmony_ci u8 regval; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (info == NULL) { 11862306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 11962306a36Sopenharmony_ci return -EINVAL; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * To satisfy both HW high power request and SW request, the regulator 12462306a36Sopenharmony_ci * must be on in high power. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci if (info->cfg && info->cfg->hwreq) 12762306a36Sopenharmony_ci regval = info->update_val_hp; 12862306a36Sopenharmony_ci else 12962306a36Sopenharmony_ci regval = info->update_val; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci ret = abx500_mask_and_set_register_interruptible(info->dev, 13262306a36Sopenharmony_ci info->update_bank, info->update_reg, 13362306a36Sopenharmony_ci info->update_mask, regval); 13462306a36Sopenharmony_ci if (ret < 0) { 13562306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), 13662306a36Sopenharmony_ci "couldn't set enable bits for regulator\n"); 13762306a36Sopenharmony_ci return ret; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci dev_dbg(rdev_get_dev(rdev), 14162306a36Sopenharmony_ci "%s-enable (bank, reg, mask, value): 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 14262306a36Sopenharmony_ci info->desc.name, info->update_bank, info->update_reg, 14362306a36Sopenharmony_ci info->update_mask, regval); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int ab8500_ext_regulator_disable(struct regulator_dev *rdev) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci int ret; 15162306a36Sopenharmony_ci struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 15262306a36Sopenharmony_ci u8 regval; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (info == NULL) { 15562306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 15662306a36Sopenharmony_ci return -EINVAL; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* 16062306a36Sopenharmony_ci * Set the regulator in HW request mode if configured 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci if (info->cfg && info->cfg->hwreq) 16362306a36Sopenharmony_ci regval = info->update_val_hw; 16462306a36Sopenharmony_ci else 16562306a36Sopenharmony_ci regval = 0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ret = abx500_mask_and_set_register_interruptible(info->dev, 16862306a36Sopenharmony_ci info->update_bank, info->update_reg, 16962306a36Sopenharmony_ci info->update_mask, regval); 17062306a36Sopenharmony_ci if (ret < 0) { 17162306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), 17262306a36Sopenharmony_ci "couldn't set disable bits for regulator\n"); 17362306a36Sopenharmony_ci return ret; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):" 17762306a36Sopenharmony_ci " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 17862306a36Sopenharmony_ci info->desc.name, info->update_bank, info->update_reg, 17962306a36Sopenharmony_ci info->update_mask, regval); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return 0; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci int ret; 18762306a36Sopenharmony_ci struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 18862306a36Sopenharmony_ci u8 regval; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (info == NULL) { 19162306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 19262306a36Sopenharmony_ci return -EINVAL; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ret = abx500_get_register_interruptible(info->dev, 19662306a36Sopenharmony_ci info->update_bank, info->update_reg, ®val); 19762306a36Sopenharmony_ci if (ret < 0) { 19862306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), 19962306a36Sopenharmony_ci "couldn't read 0x%x register\n", info->update_reg); 20062306a36Sopenharmony_ci return ret; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci dev_dbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value):" 20462306a36Sopenharmony_ci " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 20562306a36Sopenharmony_ci info->desc.name, info->update_bank, info->update_reg, 20662306a36Sopenharmony_ci info->update_mask, regval); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (((regval & info->update_mask) == info->update_val_lp) || 20962306a36Sopenharmony_ci ((regval & info->update_mask) == info->update_val_hp)) 21062306a36Sopenharmony_ci return 1; 21162306a36Sopenharmony_ci else 21262306a36Sopenharmony_ci return 0; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int ab8500_ext_regulator_set_mode(struct regulator_dev *rdev, 21662306a36Sopenharmony_ci unsigned int mode) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci int ret = 0; 21962306a36Sopenharmony_ci struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 22062306a36Sopenharmony_ci u8 regval; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (info == NULL) { 22362306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 22462306a36Sopenharmony_ci return -EINVAL; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci switch (mode) { 22862306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 22962306a36Sopenharmony_ci regval = info->update_val_hp; 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci case REGULATOR_MODE_IDLE: 23262306a36Sopenharmony_ci regval = info->update_val_lp; 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci default: 23662306a36Sopenharmony_ci return -EINVAL; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* If regulator is enabled and info->cfg->hwreq is set, the regulator 24062306a36Sopenharmony_ci must be on in high power, so we don't need to write the register with 24162306a36Sopenharmony_ci the same value. 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_ci if (ab8500_ext_regulator_is_enabled(rdev) && 24462306a36Sopenharmony_ci !(info->cfg && info->cfg->hwreq)) { 24562306a36Sopenharmony_ci ret = abx500_mask_and_set_register_interruptible(info->dev, 24662306a36Sopenharmony_ci info->update_bank, info->update_reg, 24762306a36Sopenharmony_ci info->update_mask, regval); 24862306a36Sopenharmony_ci if (ret < 0) { 24962306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), 25062306a36Sopenharmony_ci "Could not set regulator mode.\n"); 25162306a36Sopenharmony_ci return ret; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci dev_dbg(rdev_get_dev(rdev), 25562306a36Sopenharmony_ci "%s-set_mode (bank, reg, mask, value): " 25662306a36Sopenharmony_ci "0x%x, 0x%x, 0x%x, 0x%x\n", 25762306a36Sopenharmony_ci info->desc.name, info->update_bank, info->update_reg, 25862306a36Sopenharmony_ci info->update_mask, regval); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci info->update_val = regval; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 26962306a36Sopenharmony_ci int ret; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (info == NULL) { 27262306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 27362306a36Sopenharmony_ci return -EINVAL; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (info->update_val == info->update_val_hp) 27762306a36Sopenharmony_ci ret = REGULATOR_MODE_NORMAL; 27862306a36Sopenharmony_ci else if (info->update_val == info->update_val_lp) 27962306a36Sopenharmony_ci ret = REGULATOR_MODE_IDLE; 28062306a36Sopenharmony_ci else 28162306a36Sopenharmony_ci ret = -EINVAL; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return ret; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int ab8500_ext_set_voltage(struct regulator_dev *rdev, int min_uV, 28762306a36Sopenharmony_ci int max_uV, unsigned *selector) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct regulation_constraints *regu_constraints = rdev->constraints; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (!regu_constraints) { 29262306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), "No regulator constraints\n"); 29362306a36Sopenharmony_ci return -EINVAL; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (regu_constraints->min_uV == min_uV && 29762306a36Sopenharmony_ci regu_constraints->max_uV == max_uV) 29862306a36Sopenharmony_ci return 0; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), 30162306a36Sopenharmony_ci "Requested min %duV max %duV != constrained min %duV max %duV\n", 30262306a36Sopenharmony_ci min_uV, max_uV, 30362306a36Sopenharmony_ci regu_constraints->min_uV, regu_constraints->max_uV); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return -EINVAL; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int ab8500_ext_list_voltage(struct regulator_dev *rdev, 30962306a36Sopenharmony_ci unsigned selector) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct regulation_constraints *regu_constraints = rdev->constraints; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (regu_constraints == NULL) { 31462306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n"); 31562306a36Sopenharmony_ci return -EINVAL; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci /* return the uV for the fixed regulators */ 31862306a36Sopenharmony_ci if (regu_constraints->min_uV && regu_constraints->max_uV) { 31962306a36Sopenharmony_ci if (regu_constraints->min_uV == regu_constraints->max_uV) 32062306a36Sopenharmony_ci return regu_constraints->min_uV; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci return -EINVAL; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic const struct regulator_ops ab8500_ext_regulator_ops = { 32662306a36Sopenharmony_ci .enable = ab8500_ext_regulator_enable, 32762306a36Sopenharmony_ci .disable = ab8500_ext_regulator_disable, 32862306a36Sopenharmony_ci .is_enabled = ab8500_ext_regulator_is_enabled, 32962306a36Sopenharmony_ci .set_mode = ab8500_ext_regulator_set_mode, 33062306a36Sopenharmony_ci .get_mode = ab8500_ext_regulator_get_mode, 33162306a36Sopenharmony_ci .set_voltage = ab8500_ext_set_voltage, 33262306a36Sopenharmony_ci .list_voltage = ab8500_ext_list_voltage, 33362306a36Sopenharmony_ci}; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic struct ab8500_ext_regulator_info 33662306a36Sopenharmony_ci ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = { 33762306a36Sopenharmony_ci [AB8500_EXT_SUPPLY1] = { 33862306a36Sopenharmony_ci .desc = { 33962306a36Sopenharmony_ci .name = "VEXTSUPPLY1", 34062306a36Sopenharmony_ci .of_match = of_match_ptr("ab8500_ext1"), 34162306a36Sopenharmony_ci .ops = &ab8500_ext_regulator_ops, 34262306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 34362306a36Sopenharmony_ci .id = AB8500_EXT_SUPPLY1, 34462306a36Sopenharmony_ci .owner = THIS_MODULE, 34562306a36Sopenharmony_ci .n_voltages = 1, 34662306a36Sopenharmony_ci }, 34762306a36Sopenharmony_ci .update_bank = 0x04, 34862306a36Sopenharmony_ci .update_reg = 0x08, 34962306a36Sopenharmony_ci .update_mask = 0x03, 35062306a36Sopenharmony_ci .update_val = 0x01, 35162306a36Sopenharmony_ci .update_val_hp = 0x01, 35262306a36Sopenharmony_ci .update_val_lp = 0x03, 35362306a36Sopenharmony_ci .update_val_hw = 0x02, 35462306a36Sopenharmony_ci }, 35562306a36Sopenharmony_ci [AB8500_EXT_SUPPLY2] = { 35662306a36Sopenharmony_ci .desc = { 35762306a36Sopenharmony_ci .name = "VEXTSUPPLY2", 35862306a36Sopenharmony_ci .of_match = of_match_ptr("ab8500_ext2"), 35962306a36Sopenharmony_ci .ops = &ab8500_ext_regulator_ops, 36062306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 36162306a36Sopenharmony_ci .id = AB8500_EXT_SUPPLY2, 36262306a36Sopenharmony_ci .owner = THIS_MODULE, 36362306a36Sopenharmony_ci .n_voltages = 1, 36462306a36Sopenharmony_ci }, 36562306a36Sopenharmony_ci .update_bank = 0x04, 36662306a36Sopenharmony_ci .update_reg = 0x08, 36762306a36Sopenharmony_ci .update_mask = 0x0c, 36862306a36Sopenharmony_ci .update_val = 0x04, 36962306a36Sopenharmony_ci .update_val_hp = 0x04, 37062306a36Sopenharmony_ci .update_val_lp = 0x0c, 37162306a36Sopenharmony_ci .update_val_hw = 0x08, 37262306a36Sopenharmony_ci }, 37362306a36Sopenharmony_ci [AB8500_EXT_SUPPLY3] = { 37462306a36Sopenharmony_ci .desc = { 37562306a36Sopenharmony_ci .name = "VEXTSUPPLY3", 37662306a36Sopenharmony_ci .of_match = of_match_ptr("ab8500_ext3"), 37762306a36Sopenharmony_ci .ops = &ab8500_ext_regulator_ops, 37862306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 37962306a36Sopenharmony_ci .id = AB8500_EXT_SUPPLY3, 38062306a36Sopenharmony_ci .owner = THIS_MODULE, 38162306a36Sopenharmony_ci .n_voltages = 1, 38262306a36Sopenharmony_ci }, 38362306a36Sopenharmony_ci .update_bank = 0x04, 38462306a36Sopenharmony_ci .update_reg = 0x08, 38562306a36Sopenharmony_ci .update_mask = 0x30, 38662306a36Sopenharmony_ci .update_val = 0x10, 38762306a36Sopenharmony_ci .update_val_hp = 0x10, 38862306a36Sopenharmony_ci .update_val_lp = 0x30, 38962306a36Sopenharmony_ci .update_val_hw = 0x20, 39062306a36Sopenharmony_ci }, 39162306a36Sopenharmony_ci}; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int ab8500_ext_regulator_probe(struct platform_device *pdev) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); 39662306a36Sopenharmony_ci struct regulator_config config = { }; 39762306a36Sopenharmony_ci struct regulator_dev *rdev; 39862306a36Sopenharmony_ci int i; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (!ab8500) { 40162306a36Sopenharmony_ci dev_err(&pdev->dev, "null mfd parent\n"); 40262306a36Sopenharmony_ci return -EINVAL; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* check for AB8500 2.x */ 40662306a36Sopenharmony_ci if (is_ab8500_2p0_or_earlier(ab8500)) { 40762306a36Sopenharmony_ci struct ab8500_ext_regulator_info *info; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* VextSupply3LPn is inverted on AB8500 2.x */ 41062306a36Sopenharmony_ci info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3]; 41162306a36Sopenharmony_ci info->update_val = 0x30; 41262306a36Sopenharmony_ci info->update_val_hp = 0x30; 41362306a36Sopenharmony_ci info->update_val_lp = 0x10; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* register all regulators */ 41762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { 41862306a36Sopenharmony_ci struct ab8500_ext_regulator_info *info = NULL; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* assign per-regulator data */ 42162306a36Sopenharmony_ci info = &ab8500_ext_regulator_info[i]; 42262306a36Sopenharmony_ci info->dev = &pdev->dev; 42362306a36Sopenharmony_ci info->cfg = (struct ab8500_ext_regulator_cfg *) 42462306a36Sopenharmony_ci ab8500_ext_regulators[i].driver_data; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci config.dev = &pdev->dev; 42762306a36Sopenharmony_ci config.driver_data = info; 42862306a36Sopenharmony_ci config.init_data = &ab8500_ext_regulators[i]; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* register regulator with framework */ 43162306a36Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, &info->desc, 43262306a36Sopenharmony_ci &config); 43362306a36Sopenharmony_ci if (IS_ERR(rdev)) { 43462306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register regulator %s\n", 43562306a36Sopenharmony_ci info->desc.name); 43662306a36Sopenharmony_ci return PTR_ERR(rdev); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci dev_dbg(&pdev->dev, "%s-probed\n", info->desc.name); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic struct platform_driver ab8500_ext_regulator_driver = { 44662306a36Sopenharmony_ci .probe = ab8500_ext_regulator_probe, 44762306a36Sopenharmony_ci .driver = { 44862306a36Sopenharmony_ci .name = "ab8500-ext-regulator", 44962306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 45062306a36Sopenharmony_ci }, 45162306a36Sopenharmony_ci}; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int __init ab8500_ext_regulator_init(void) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci int ret; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci ret = platform_driver_register(&ab8500_ext_regulator_driver); 45862306a36Sopenharmony_ci if (ret) 45962306a36Sopenharmony_ci pr_err("Failed to register ab8500 ext regulator: %d\n", ret); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return ret; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_cisubsys_initcall(ab8500_ext_regulator_init); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic void __exit ab8500_ext_regulator_exit(void) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci platform_driver_unregister(&ab8500_ext_regulator_driver); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_cimodule_exit(ab8500_ext_regulator_exit); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 47262306a36Sopenharmony_ciMODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>"); 47362306a36Sopenharmony_ciMODULE_DESCRIPTION("AB8500 external regulator driver"); 47462306a36Sopenharmony_ciMODULE_ALIAS("platform:ab8500-ext-regulator"); 475