From c8801a8e715d7793e1e7bcd2f6fe132234741753 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 19 Mar 2012 16:35:48 +0000 Subject: regulator: core: Mark all get and enable calls as __must_check It's generally important that devices have power when they expect it so drivers really ought to be checking for errors on the power up paths. Signed-off-by: Mark Brown --- include/linux/regulator/consumer.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 7bc732ce6e50..145022a83085 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -141,18 +141,18 @@ void regulator_put(struct regulator *regulator); void devm_regulator_put(struct regulator *regulator); /* regulator output control and status */ -int regulator_enable(struct regulator *regulator); +int __must_check regulator_enable(struct regulator *regulator); int regulator_disable(struct regulator *regulator); int regulator_force_disable(struct regulator *regulator); int regulator_is_enabled(struct regulator *regulator); int regulator_disable_deferred(struct regulator *regulator, int ms); -int regulator_bulk_get(struct device *dev, int num_consumers, - struct regulator_bulk_data *consumers); -int devm_regulator_bulk_get(struct device *dev, int num_consumers, - struct regulator_bulk_data *consumers); -int regulator_bulk_enable(int num_consumers, - struct regulator_bulk_data *consumers); +int __must_check regulator_bulk_get(struct device *dev, int num_consumers, + struct regulator_bulk_data *consumers); +int __must_check devm_regulator_bulk_get(struct device *dev, int num_consumers, + struct regulator_bulk_data *consumers); +int __must_check regulator_bulk_enable(int num_consumers, + struct regulator_bulk_data *consumers); int regulator_bulk_disable(int num_consumers, struct regulator_bulk_data *consumers); int regulator_bulk_force_disable(int num_consumers, -- cgit v1.2.3 From f19b00da8ed37db4e3891fe534fcf3a605a0e562 Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Mon, 18 Feb 2013 06:50:39 +0000 Subject: regulator: core: support shared enable GPIO concept A Regulator can be enabled by external GPIO pin. This is configurable in the regulator_config. At this moment, the GPIO can be owned by only one regulator device. In some devices, multiple regulators are enabled by shared one GPIO pin. This patch extends this limitation, enabling shared enable GPIO of regulators. New list for enable GPIO: 'regulator_ena_gpio_list' This manages enable GPIO list. New structure for supporting shared enable GPIO: 'regulator_enable_gpio' The enable count is used for balancing GPIO control count. This count is incremented when GPIO is enabled. On the other hand, it's decremented when GPIO is disabled. Reference count: 'request_count' The reference count, 'request_count' is incremented/decremented on requesting/freeing the GPIO. This count makes sure only free the GPIO when it has no users. How it works If the GPIO is already used, skip requesting new GPIO usage. The GPIO is new one, request GPIO function and add it to the list of enable GPIO. This list is used for balancing enable GPIO count and pin control. Updating a GPIO and invert code moved 'ena_gpio' and 'ena_gpio_invert' of the regulator_config were moved to new function, regulator_ena_gpio_request(). Use regulator_enable_pin structure rather than regulator_dev. Signed-off-by: Milo(Woogyom) Kim Reviewed-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/core.c | 86 +++++++++++++++++++++++++++++++++++----- include/linux/regulator/driver.h | 2 + 2 files changed, 78 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index da9782bd27d0..71d6adc4eeab 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -51,6 +51,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); +static LIST_HEAD(regulator_ena_gpio_list); static bool has_full_constraints; static bool board_wants_dummy_regulator; @@ -68,6 +69,19 @@ struct regulator_map { struct regulator_dev *regulator; }; +/* + * struct regulator_enable_gpio + * + * Management for shared enable GPIO pin + */ +struct regulator_enable_gpio { + struct list_head list; + int gpio; + u32 enable_count; /* a number of enabled shared GPIO */ + u32 request_count; /* a number of requested shared GPIO */ + unsigned int ena_gpio_invert:1; +}; + /* * struct regulator * @@ -1456,6 +1470,65 @@ void devm_regulator_put(struct regulator *regulator) } EXPORT_SYMBOL_GPL(devm_regulator_put); +/* Manage enable GPIO list. Same GPIO pin can be shared among regulators */ +static int regulator_ena_gpio_request(struct regulator_dev *rdev, + const struct regulator_config *config) +{ + struct regulator_enable_gpio *pin; + int ret; + + list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { + if (pin->gpio == config->ena_gpio) { + rdev_dbg(rdev, "GPIO %d is already used\n", + config->ena_gpio); + goto update_ena_gpio_to_rdev; + } + } + + ret = gpio_request_one(config->ena_gpio, + GPIOF_DIR_OUT | config->ena_gpio_flags, + rdev_get_name(rdev)); + if (ret) + return ret; + + pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL); + if (pin == NULL) { + gpio_free(config->ena_gpio); + return -ENOMEM; + } + + pin->gpio = config->ena_gpio; + pin->ena_gpio_invert = config->ena_gpio_invert; + list_add(&pin->list, ®ulator_ena_gpio_list); + +update_ena_gpio_to_rdev: + pin->request_count++; + rdev->ena_pin = pin; + return 0; +} + +static void regulator_ena_gpio_free(struct regulator_dev *rdev) +{ + struct regulator_enable_gpio *pin, *n; + + if (!rdev->ena_pin) + return; + + /* Free the GPIO only in case of no use */ + list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) { + if (pin->gpio == rdev->ena_pin->gpio) { + if (pin->request_count <= 1) { + pin->request_count = 0; + gpio_free(pin->gpio); + list_del(&pin->list); + kfree(pin); + } else { + pin->request_count--; + } + } + } +} + static int _regulator_do_enable(struct regulator_dev *rdev) { int ret, delay; @@ -3435,18 +3508,13 @@ regulator_register(const struct regulator_desc *regulator_desc, dev_set_drvdata(&rdev->dev, rdev); if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) { - ret = gpio_request_one(config->ena_gpio, - GPIOF_DIR_OUT | config->ena_gpio_flags, - rdev_get_name(rdev)); + ret = regulator_ena_gpio_request(rdev, config); if (ret != 0) { rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", config->ena_gpio, ret); goto wash; } - rdev->ena_gpio = config->ena_gpio; - rdev->ena_gpio_invert = config->ena_gpio_invert; - if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH) rdev->ena_gpio_state = 1; @@ -3522,8 +3590,7 @@ unset_supplies: scrub: if (rdev->supply) _regulator_put(rdev->supply); - if (rdev->ena_gpio) - gpio_free(rdev->ena_gpio); + regulator_ena_gpio_free(rdev); kfree(rdev->constraints); wash: device_unregister(&rdev->dev); @@ -3558,8 +3625,7 @@ void regulator_unregister(struct regulator_dev *rdev) unset_regulator_supplies(rdev); list_del(&rdev->list); kfree(rdev->constraints); - if (rdev->ena_gpio) - gpio_free(rdev->ena_gpio); + regulator_ena_gpio_free(rdev); device_unregister(&rdev->dev); mutex_unlock(®ulator_list_mutex); } diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 23070fd83872..a467d11dd67d 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -22,6 +22,7 @@ struct regmap; struct regulator_dev; struct regulator_init_data; +struct regulator_enable_gpio; enum regulator_status { REGULATOR_STATUS_OFF, @@ -300,6 +301,7 @@ struct regulator_dev { struct dentry *debugfs; + struct regulator_enable_gpio *ena_pin; int ena_gpio; unsigned int ena_gpio_invert:1; unsigned int ena_gpio_state:1; -- cgit v1.2.3 From 7b74d149247c8972da1cec3e4c70b67049aaeb69 Mon Sep 17 00:00:00 2001 From: "Kim, Milo" Date: Mon, 18 Feb 2013 06:50:55 +0000 Subject: regulator: core: use regulator_ena_pin member The regulator_dev has regulator_enable_gpio structure. 'ena_gpio' and 'ena_gpio_invert' were moved to in regulator_enable_gpio. regulator_dev ---> regulator_enable_gpio .ena_gpio .gpio .ena_gpio_invert .ena_gpio_invert Pointer, 'ena_pin' is used for checking valid enable GPIO pin. Signed-off-by: Milo(Woogyom) Kim Reviewed-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/core.c | 6 +++--- include/linux/regulator/driver.h | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 57d434d3145a..6c8c82406cd9 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1945,7 +1945,7 @@ EXPORT_SYMBOL_GPL(regulator_disable_regmap); static int _regulator_is_enabled(struct regulator_dev *rdev) { /* A GPIO control always takes precedence */ - if (rdev->ena_gpio) + if (rdev->ena_pin) return rdev->ena_gpio_state; /* If we don't know then assume that the regulator is always on */ @@ -3344,7 +3344,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) if (status < 0) return status; } - if (rdev->ena_gpio || ops->is_enabled) { + if (rdev->ena_pin || ops->is_enabled) { status = device_create_file(dev, &dev_attr_state); if (status < 0) return status; @@ -3556,7 +3556,7 @@ regulator_register(const struct regulator_desc *regulator_desc, if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH) rdev->ena_gpio_state = 1; - if (rdev->ena_gpio_invert) + if (config->ena_gpio_invert) rdev->ena_gpio_state = !rdev->ena_gpio_state; } diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index a467d11dd67d..7b7aeec04f86 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -302,8 +302,6 @@ struct regulator_dev { struct dentry *debugfs; struct regulator_enable_gpio *ena_pin; - int ena_gpio; - unsigned int ena_gpio_invert:1; unsigned int ena_gpio_state:1; }; -- cgit v1.2.3 From 51dcdafcb720a9d1fd73b597d0ccf48837abc59f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 5 Mar 2013 14:16:00 +0800 Subject: regulator: core: Add enable_is_inverted flag to indicate set enable_mask bits to disable Add enable_is_inverted flag to indicate set enable_mask bits to disable when using regulator_enable_regmap and friends APIs. Signed-off-by: Axel Lin Reviewed-by: Haojian Zhuang Signed-off-by: Mark Brown --- drivers/regulator/core.c | 24 ++++++++++++++++++++---- include/linux/regulator/driver.h | 3 +++ 2 files changed, 23 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 154bc8f0c1a0..d887b9f5b213 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1794,7 +1794,10 @@ int regulator_is_enabled_regmap(struct regulator_dev *rdev) if (ret != 0) return ret; - return (val & rdev->desc->enable_mask) != 0; + if (rdev->desc->enable_is_inverted) + return (val & rdev->desc->enable_mask) == 0; + else + return (val & rdev->desc->enable_mask) != 0; } EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); @@ -1809,9 +1812,15 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); */ int regulator_enable_regmap(struct regulator_dev *rdev) { + unsigned int val; + + if (rdev->desc->enable_is_inverted) + val = 0; + else + val = rdev->desc->enable_mask; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, - rdev->desc->enable_mask); + rdev->desc->enable_mask, val); } EXPORT_SYMBOL_GPL(regulator_enable_regmap); @@ -1826,8 +1835,15 @@ EXPORT_SYMBOL_GPL(regulator_enable_regmap); */ int regulator_disable_regmap(struct regulator_dev *rdev) { + unsigned int val; + + if (rdev->desc->enable_is_inverted) + val = rdev->desc->enable_mask; + else + val = 0; + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, - rdev->desc->enable_mask, 0); + rdev->desc->enable_mask, val); } EXPORT_SYMBOL_GPL(regulator_disable_regmap); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 7df93f52db08..07ea8f1a127e 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -199,6 +199,8 @@ enum regulator_type { * output when using regulator_set_voltage_sel_regmap * @enable_reg: Register for control when using regmap enable/disable ops * @enable_mask: Mask for control when using regmap enable/disable ops + * @enable_is_inverted: A flag to indicate set enable_mask bits to disable + * when using regulator_enable_regmap and friends APIs. * @bypass_reg: Register for control when using regmap set_bypass * @bypass_mask: Mask for control when using regmap set_bypass * @@ -228,6 +230,7 @@ struct regulator_desc { unsigned int apply_bit; unsigned int enable_reg; unsigned int enable_mask; + bool enable_is_inverted; unsigned int bypass_reg; unsigned int bypass_mask; -- cgit v1.2.3 From d79df329d0bd425c00856915b7b12f54dd100154 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 21 Mar 2013 15:58:58 +0000 Subject: regulator: ab8500: Further populate initialisation registers This patch supplies access to some extra settings provided by the AB8500 regulator device. We also update some of the existing initialisation values in accordance with internal ST-Ericsson code submissions. This single patch was originally a collection of updates which have been squashed together to aid with clarity. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- arch/arm/mach-ux500/board-mop500-regulators.c | 40 +++++++++++++++++++++++++-- drivers/regulator/ab8500.c | 39 ++++++++++++++++++++++++-- include/linux/regulator/ab8500.h | 8 ++++++ 3 files changed, 81 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index 2a17bc506cff..4b3c51905071 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -126,6 +126,7 @@ struct ab8500_regulator_reg_init ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { /* * VanaRequestCtrl = HP/LP depending on VxRequest + * VpllRequestCtrl = HP/LP depending on VxRequest * VextSupply1RequestCtrl = HP/LP depending on VxRequest */ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0x00), @@ -142,12 +143,16 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { */ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x00), /* + * Vsmps1SysClkReq1HPValid = enabled + * Vsmps2SysClkReq1HPValid = enabled + * Vsmps3SysClkReq1HPValid = enabled * VanaSysClkReq1HPValid = disabled + * VpllSysClkReq1HPValid = enabled * Vaux1SysClkReq1HPValid = disabled * Vaux2SysClkReq1HPValid = disabled * Vaux3SysClkReq1HPValid = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0x17), /* * VextSupply1SysClkReq1HPValid = disabled * VextSupply2SysClkReq1HPValid = disabled @@ -233,6 +238,34 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * Vamic2_dzout = high-Z when Vamic2 is disabled */ INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x00), + /* + * VBBN = force OFF + * VBBP = force OFF + * NOTE! PRCMU register + */ + INIT_REGULATOR_REGISTER(AB8500_ARMREGU2, 0x00), + /* + * VBBNSel1 = VBBP = VBBPFB + * VBBPSel1 = 0 V + * NOTE! PRCMU register + */ + INIT_REGULATOR_REGISTER(AB8500_VBBSEL1, 0x00), + /* + * VBBNSel2 = VBBP = VBBPFB + * VBBPSel2 = 0 V + * NOTE! PRCMU register + */ + INIT_REGULATOR_REGISTER(AB8500_VBBSEL2, 0x00), + /* + * Vsmps1Regu = HW control + * Vsmps1SelCtrl = Vsmps1 voltage defined by Vsmsp1Sel2 + */ + INIT_REGULATOR_REGISTER(AB8500_VSMPS1REGU, 0x06), + /* + * Vsmps2Regu = HW control + * Vsmps2SelCtrl = Vsmps2 voltage defined by Vsmsp2Sel2 + */ + INIT_REGULATOR_REGISTER(AB8500_VSMPS2REGU, 0x06), /* * VPll = Hw controlled * VanaRegu = force off @@ -257,9 +290,10 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { */ INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x01), /* - * Vaux3regu = force off + * Vrf1Regu = HW control + * Vaux3Regu = force off */ - INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x00), + INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x08), /* * Vsmps1 = 1.15V */ diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 09014f38a948..4d9d556a47cc 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -477,7 +477,7 @@ struct ab8500_reg_init { static struct ab8500_reg_init ab8500_reg_init[] = { /* * 0x30, VanaRequestCtrl - * 0x0C, VpllRequestCtrl + * 0x0c, VpllRequestCtrl * 0xc0, VextSupply1RequestCtrl */ REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xfc), @@ -494,12 +494,16 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), /* + * 0x01, Vsmps1SysClkReq1HPValid + * 0x02, Vsmps2SysClkReq1HPValid + * 0x04, Vsmps3SysClkReq1HPValid * 0x08, VanaSysClkReq1HPValid + * 0x10, VpllSysClkReq1HPValid * 0x20, Vaux1SysClkReq1HPValid * 0x40, Vaux2SysClkReq1HPValid * 0x80, Vaux3SysClkReq1HPValid */ - REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xe8), + REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), /* * 0x10, VextSupply1SysClkReq1HPValid * 0x20, VextSupply2SysClkReq1HPValid @@ -577,6 +581,34 @@ static struct ab8500_reg_init ab8500_reg_init[] = { * 0x02, Vamic2_dzout */ REG_INIT(AB8500_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), + /* + * 0x0c, VBBNRegu + * 0x03, VBBPRegu + * NOTE! PRCMU register + */ + REG_INIT(AB8500_ARMREGU2, 0x04, 0x01, 0x0f), + /* + * 0x0c, VBBPSel1 + * 0x03, VBBNSel1 + * NOTE! PRCMU register + */ + REG_INIT(AB8500_VBBSEL1, 0x04, 0x11, 0x0f), + /* + * 0x0c, VBBNSel2 + * 0x03, VBBPSel2 + * NOTE! PRCMU register + */ + REG_INIT(AB8500_VBBSEL2, 0x04, 0x12, 0x0f), + /* + * 0x03, Vsmps1Regu + * 0x0c, Vsmps1SelCtrl + */ + REG_INIT(AB8500_VSMPS1REGU, 0x04, 0x03, 0x0f), + /* + * 0x03, Vsmps2Regu + * 0x0c, Vsmps2SelCtrl + */ + REG_INIT(AB8500_VSMPS2REGU, 0x04, 0x04, 0x0f), /* * 0x0c, VanaRegu * 0x03, VpllRegu @@ -601,9 +633,10 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_VAUX12REGU, 0x04, 0x09, 0x0f), /* + * 0x0c, Vrf1Regu * 0x03, Vaux3Regu */ - REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x03), + REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), /* * 0x3f, Vsmps1Sel1 */ diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 7bd73bbdfd1b..2c6c9625013c 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -86,7 +86,15 @@ enum ab8500_regulator_reg { AB8500_REGUCTRL2SPARE, AB8500_REGUCTRLDISCH, AB8500_REGUCTRLDISCH2, + AB8500_ARMREGU2, /* NOTE! PRCMU register */ + AB8500_VBBSEL1, /* NOTE! PRCMU register */ + AB8500_VBBSEL2, /* NOTE! PRCMU register */ + AB8500_VSMPS1REGU, + AB8500_VSMPS2REGU, + AB8500_VSMPS3REGU, /* NOTE! PRCMU register */ AB8500_VSMPS1SEL1, + AB8500_VSMPS3SEL1, /* NOTE! PRCMU register */ + AB8500_VSMPS3SEL2, /* NOTE! PRCMU register */ AB8500_NUM_REGULATOR_REGISTERS, }; -- cgit v1.2.3 From 3c1b8438d4bc99269aba560739e3e6cb640584f4 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 21 Mar 2013 15:59:01 +0000 Subject: ARM: ux500: regulators: Add mask for configuration There is already before a register mask in the regulator driver to allow some bits of a register to be initialized. The register value is defined in the board configuration. This patch puts a mask in the board configuration to specify which bits should actually be altered. The purpose with this patch is to avoid future mistakes when updating the allowed bits in the regulator driver. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- arch/arm/mach-ux500/board-mop500-regulators.c | 66 +++++++++++++-------------- drivers/regulator/ab8500.c | 36 ++++++--------- include/linux/regulator/ab8500.h | 10 ++-- 3 files changed, 53 insertions(+), 59 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index 4b3c51905071..96dd17490bea 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -129,19 +129,19 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * VpllRequestCtrl = HP/LP depending on VxRequest * VextSupply1RequestCtrl = HP/LP depending on VxRequest */ - INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xfc, 0x00), /* * VextSupply2RequestCtrl = HP/LP depending on VxRequest * VextSupply3RequestCtrl = HP/LP depending on VxRequest * Vaux1RequestCtrl = HP/LP depending on VxRequest * Vaux2RequestCtrl = HP/LP depending on VxRequest */ - INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0xff, 0x00), /* * Vaux3RequestCtrl = HP/LP depending on VxRequest * SwHPReq = Control through SWValid disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x07, 0x00), /* * Vsmps1SysClkReq1HPValid = enabled * Vsmps2SysClkReq1HPValid = enabled @@ -152,44 +152,44 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * Vaux2SysClkReq1HPValid = disabled * Vaux3SysClkReq1HPValid = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0x17), + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xff, 0x17), /* * VextSupply1SysClkReq1HPValid = disabled * VextSupply2SysClkReq1HPValid = disabled * VextSupply3SysClkReq1HPValid = SysClkReq1 controlled */ - INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x40), + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x70, 0x40), /* * VanaHwHPReq1Valid = disabled * Vaux1HwHPreq1Valid = disabled * Vaux2HwHPReq1Valid = disabled * Vaux3HwHPReqValid = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0xe8, 0x00), /* * VextSupply1HwHPReq1Valid = disabled * VextSupply2HwHPReq1Valid = disabled * VextSupply3HwHPReq1Valid = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x07, 0x00), /* * VanaHwHPReq2Valid = disabled * Vaux1HwHPReq2Valid = disabled * Vaux2HwHPReq2Valid = disabled * Vaux3HwHPReq2Valid = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0xe8, 0x00), /* * VextSupply1HwHPReq2Valid = disabled * VextSupply2HwHPReq2Valid = disabled * VextSupply3HwHPReq2Valid = HWReq2 controlled */ - INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x04), + INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x07, 0x04), /* * VanaSwHPReqValid = disabled * Vaux1SwHPReqValid = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0xa0, 0x00), /* * Vaux2SwHPReqValid = disabled * Vaux3SwHPReqValid = disabled @@ -197,7 +197,7 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * VextSupply2SwHPReqValid = disabled * VextSupply3SwHPReqValid = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x1f, 0x00), /* * SysClkReq2Valid1 = SysClkReq2 controlled * SysClkReq3Valid1 = disabled @@ -207,7 +207,7 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * SysClkReq7Valid1 = disabled * SysClkReq8Valid1 = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0x2a), + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0xfe, 0x2a), /* * SysClkReq2Valid2 = disabled * SysClkReq3Valid2 = disabled @@ -217,7 +217,7 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * SysClkReq7Valid2 = disabled * SysClkReq8Valid2 = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0x20), + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0xfe, 0x20), /* * VTVoutEna = disabled * Vintcore12Ena = disabled @@ -225,57 +225,57 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * Vintcore12LP = inactive (HP) * VTVoutLP = inactive (HP) */ - INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0x10), + INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0xfe, 0x10), /* * VaudioEna = disabled * VdmicEna = disabled * Vamic1Ena = disabled * Vamic2Ena = disabled */ - INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x00), + INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x1e, 0x00), /* * Vamic1_dzout = high-Z when Vamic1 is disabled * Vamic2_dzout = high-Z when Vamic2 is disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00), /* * VBBN = force OFF * VBBP = force OFF * NOTE! PRCMU register */ - INIT_REGULATOR_REGISTER(AB8500_ARMREGU2, 0x00), + INIT_REGULATOR_REGISTER(AB8500_ARMREGU2, 0x0f, 0x00), /* * VBBNSel1 = VBBP = VBBPFB * VBBPSel1 = 0 V * NOTE! PRCMU register */ - INIT_REGULATOR_REGISTER(AB8500_VBBSEL1, 0x00), + INIT_REGULATOR_REGISTER(AB8500_VBBSEL1, 0x0f, 0x00), /* * VBBNSel2 = VBBP = VBBPFB * VBBPSel2 = 0 V * NOTE! PRCMU register */ - INIT_REGULATOR_REGISTER(AB8500_VBBSEL2, 0x00), + INIT_REGULATOR_REGISTER(AB8500_VBBSEL2, 0x0f, 0x00), /* * Vsmps1Regu = HW control * Vsmps1SelCtrl = Vsmps1 voltage defined by Vsmsp1Sel2 */ - INIT_REGULATOR_REGISTER(AB8500_VSMPS1REGU, 0x06), + INIT_REGULATOR_REGISTER(AB8500_VSMPS1REGU, 0x0f, 0x06), /* * Vsmps2Regu = HW control * Vsmps2SelCtrl = Vsmps2 voltage defined by Vsmsp2Sel2 */ - INIT_REGULATOR_REGISTER(AB8500_VSMPS2REGU, 0x06), + INIT_REGULATOR_REGISTER(AB8500_VSMPS2REGU, 0x0f, 0x06), /* * VPll = Hw controlled * VanaRegu = force off */ - INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x02), + INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x0f, 0x02), /* * VrefDDREna = disabled * VrefDDRSleepMode = inactive (no pulldown) */ - INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x00), + INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x03, 0x00), /* * VextSupply1Regu = HW control * VextSupply2Regu = HW control @@ -283,37 +283,37 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0 * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0 */ - INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0x2a), + INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0xff, 0x1a), /* * Vaux1Regu = force HP * Vaux2Regu = force off */ - INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x01), + INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x0f, 0x01), /* * Vrf1Regu = HW control * Vaux3Regu = force off */ - INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x08), + INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x0f, 0x08), /* * Vsmps1 = 1.15V */ - INIT_REGULATOR_REGISTER(AB8500_VSMPS1SEL1, 0x24), + INIT_REGULATOR_REGISTER(AB8500_VSMPS1SEL1, 0x3f, 0x24), /* * Vaux1Sel = 2.5 V */ - INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x08), + INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x0f, 0x08), /* * Vaux2Sel = 2.9 V */ - INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0d), + INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0f, 0x0d), /* * Vaux3Sel = 2.91 V */ - INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07), + INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07, 0x07), /* * VextSupply12LP = disabled (no LP) */ - INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x01, 0x00), /* * Vaux1Disch = short discharge time * Vaux2Disch = short discharge time @@ -322,13 +322,13 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * VTVoutDisch = short discharge time * VaudioDisch = short discharge time */ - INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0xfc, 0x00), /* * VanaDisch = short discharge time * VdmicPullDownEna = pulldown disabled when Vdmic is disabled * VdmicDisch = short discharge time */ - INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x16, 0x00), }; /* AB8500 regulators */ diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 3465ac38bffe..a847744f8c20 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -811,23 +811,20 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), }; -static int -ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value) +static int ab8500_regulator_init_registers(struct platform_device *pdev, + int id, int mask, int value) { int err; - if (value & ~ab8500_reg_init[id].mask) { - dev_err(&pdev->dev, - "Configuration error: value outside mask.\n"); - return -EINVAL; - } + BUG_ON(value & ~mask); + BUG_ON(mask & ~ab8500_reg_init[id].mask); + /* initialize register */ err = abx500_mask_and_set_register_interruptible( &pdev->dev, ab8500_reg_init[id].bank, ab8500_reg_init[id].addr, - ab8500_reg_init[id].mask, - value); + mask, value); if (err < 0) { dev_err(&pdev->dev, "Failed to initialize 0x%02x, 0x%02x.\n", @@ -835,13 +832,11 @@ ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value) ab8500_reg_init[id].addr); return err; } - dev_vdbg(&pdev->dev, - "init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", - ab8500_reg_init[id].bank, - ab8500_reg_init[id].addr, - ab8500_reg_init[id].mask, - value); + " init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + ab8500_reg_init[id].bank, + ab8500_reg_init[id].addr, + mask, value); return 0; } @@ -960,19 +955,16 @@ static int ab8500_regulator_probe(struct platform_device *pdev) /* initialize registers */ for (i = 0; i < pdata->num_regulator_reg_init; i++) { - int id, value; + int id, mask, value; id = pdata->regulator_reg_init[i].id; + mask = pdata->regulator_reg_init[i].mask; value = pdata->regulator_reg_init[i].value; /* check for configuration errors */ - if (id >= AB8500_NUM_REGULATOR_REGISTERS) { - dev_err(&pdev->dev, - "Configuration error: id outside range.\n"); - return -EINVAL; - } + BUG_ON(id >= AB8500_NUM_REGULATOR_REGISTERS); - err = ab8500_regulator_init_registers(pdev, id, value); + err = ab8500_regulator_init_registers(pdev, id, mask, value); if (err < 0) return err; } diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 2c6c9625013c..a1d245f13d9c 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -48,13 +48,15 @@ enum ab9540_regulator_id { /* AB8500 and AB9540 register initialization */ struct ab8500_regulator_reg_init { int id; + u8 mask; u8 value; }; -#define INIT_REGULATOR_REGISTER(_id, _value) \ - { \ - .id = _id, \ - .value = _value, \ +#define INIT_REGULATOR_REGISTER(_id, _mask, _value) \ + { \ + .id = _id, \ + .mask = _mask, \ + .value = _value, \ } /* AB8500 registers */ -- cgit v1.2.3 From 33bc8f46a8ee3fc1836def9713933435b7ff0b90 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 21 Mar 2013 15:59:02 +0000 Subject: regulator: ab8500: Another push to synchronise recent AB8500 developments This patch ensures that many of the recent developments pertaining to the AB8500 regulator device are propagated out into the public arena. It aims to update some of the existing initialisation values in accordance with internal ST-Ericsson code submissions. This single patch was originally a collection of updates which have been squashed together to aid with clarity. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- arch/arm/mach-ux500/board-mop500-regulators.c | 18 ------ drivers/regulator/ab8500.c | 86 +++++++++++++++++---------- include/linux/regulator/ab8500.h | 21 ++++--- 3 files changed, 65 insertions(+), 60 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index 96dd17490bea..a8141e3e8ca1 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -238,24 +238,6 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { * Vamic2_dzout = high-Z when Vamic2 is disabled */ INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00), - /* - * VBBN = force OFF - * VBBP = force OFF - * NOTE! PRCMU register - */ - INIT_REGULATOR_REGISTER(AB8500_ARMREGU2, 0x0f, 0x00), - /* - * VBBNSel1 = VBBP = VBBPFB - * VBBPSel1 = 0 V - * NOTE! PRCMU register - */ - INIT_REGULATOR_REGISTER(AB8500_VBBSEL1, 0x0f, 0x00), - /* - * VBBNSel2 = VBBP = VBBPFB - * VBBPSel2 = 0 V - * NOTE! PRCMU register - */ - INIT_REGULATOR_REGISTER(AB8500_VBBSEL2, 0x0f, 0x00), /* * Vsmps1Regu = HW control * Vsmps1SelCtrl = Vsmps1 voltage defined by Vsmsp1Sel2 diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index a847744f8c20..c7784c4bff4f 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -613,11 +613,19 @@ struct ab8500_reg_init { static struct ab8500_reg_init ab8500_reg_init[] = { /* - * 0x30, VanaRequestCtrl + * 0x03, VarmRequestCtrl + * 0x0c, VapeRequestCtrl + * 0x30, Vsmps1RequestCtrl + * 0xc0, Vsmps2RequestCtrl + */ + REG_INIT(AB8500_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), + /* + * 0x03, Vsmps3RequestCtrl * 0x0c, VpllRequestCtrl + * 0x30, VanaRequestCtrl * 0xc0, VextSupply1RequestCtrl */ - REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xfc), + REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xff), /* * 0x03, VextSupply2RequestCtrl * 0x0c, VextSupply3RequestCtrl @@ -642,50 +650,71 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), /* + * 0x01, VapeSysClkReq1HPValid + * 0x02, VarmSysClkReq1HPValid + * 0x04, VbbSysClkReq1HPValid + * 0x08, VmodSysClkReq1HPValid * 0x10, VextSupply1SysClkReq1HPValid * 0x20, VextSupply2SysClkReq1HPValid * 0x40, VextSupply3SysClkReq1HPValid */ - REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x70), + REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x7f), /* + * 0x01, Vsmps1HwHPReq1Valid + * 0x02, Vsmps2HwHPReq1Valid + * 0x04, Vsmps3HwHPReq1Valid * 0x08, VanaHwHPReq1Valid + * 0x10, VpllHwHPReq1Valid * 0x20, Vaux1HwHPReq1Valid * 0x40, Vaux2HwHPReq1Valid * 0x80, Vaux3HwHPReq1Valid */ - REG_INIT(AB8500_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xe8), + REG_INIT(AB8500_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), /* * 0x01, VextSupply1HwHPReq1Valid * 0x02, VextSupply2HwHPReq1Valid * 0x04, VextSupply3HwHPReq1Valid + * 0x08, VmodHwHPReq1Valid */ - REG_INIT(AB8500_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07), + REG_INIT(AB8500_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x0f), /* + * 0x01, Vsmps1HwHPReq2Valid + * 0x02, Vsmps2HwHPReq2Valid + * 0x03, Vsmps3HwHPReq2Valid * 0x08, VanaHwHPReq2Valid + * 0x10, VpllHwHPReq2Valid * 0x20, Vaux1HwHPReq2Valid * 0x40, Vaux2HwHPReq2Valid * 0x80, Vaux3HwHPReq2Valid */ - REG_INIT(AB8500_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xe8), + REG_INIT(AB8500_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), /* * 0x01, VextSupply1HwHPReq2Valid * 0x02, VextSupply2HwHPReq2Valid * 0x04, VextSupply3HwHPReq2Valid + * 0x08, VmodHwHPReq2Valid */ - REG_INIT(AB8500_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07), + REG_INIT(AB8500_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x0f), /* + * 0x01, VapeSwHPReqValid + * 0x02, VarmSwHPReqValid + * 0x04, Vsmps1SwHPReqValid + * 0x08, Vsmps2SwHPReqValid + * 0x10, Vsmps3SwHPReqValid * 0x20, VanaSwHPReqValid + * 0x40, VpllSwHPReqValid * 0x80, Vaux1SwHPReqValid */ - REG_INIT(AB8500_REGUSWHPREQVALID1, 0x03, 0x0d, 0xa0), + REG_INIT(AB8500_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), /* * 0x01, Vaux2SwHPReqValid * 0x02, Vaux3SwHPReqValid * 0x04, VextSupply1SwHPReqValid * 0x08, VextSupply2SwHPReqValid * 0x10, VextSupply3SwHPReqValid + * 0x20, VmodSwHPReqValid */ - REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f), + REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x3f), /* * 0x02, SysClkReq2Valid1 * ... @@ -718,37 +747,23 @@ static struct ab8500_reg_init ab8500_reg_init[] = { * 0x02, Vamic2_dzout */ REG_INIT(AB8500_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), - /* - * 0x0c, VBBNRegu - * 0x03, VBBPRegu - * NOTE! PRCMU register - */ - REG_INIT(AB8500_ARMREGU2, 0x04, 0x01, 0x0f), - /* - * 0x0c, VBBPSel1 - * 0x03, VBBNSel1 - * NOTE! PRCMU register - */ - REG_INIT(AB8500_VBBSEL1, 0x04, 0x11, 0x0f), - /* - * 0x0c, VBBNSel2 - * 0x03, VBBPSel2 - * NOTE! PRCMU register - */ - REG_INIT(AB8500_VBBSEL2, 0x04, 0x12, 0x0f), /* * 0x03, Vsmps1Regu * 0x0c, Vsmps1SelCtrl + * 0x10, Vsmps1AutoMode + * 0x20, Vsmps1PWMMode */ - REG_INIT(AB8500_VSMPS1REGU, 0x04, 0x03, 0x0f), + REG_INIT(AB8500_VSMPS1REGU, 0x04, 0x03, 0x3f), /* * 0x03, Vsmps2Regu * 0x0c, Vsmps2SelCtrl + * 0x10, Vsmps2AutoMode + * 0x20, Vsmps2PWMMode */ - REG_INIT(AB8500_VSMPS2REGU, 0x04, 0x04, 0x0f), + REG_INIT(AB8500_VSMPS2REGU, 0x04, 0x04, 0x3f), /* - * 0x0c, VanaRegu * 0x03, VpllRegu + * 0x0c, VanaRegu */ REG_INIT(AB8500_VPLLVANAREGU, 0x04, 0x06, 0x0f), /* @@ -788,13 +803,16 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_VAUX2SEL, 0x04, 0x20, 0x0f), /* * 0x07, Vaux3Sel + * 0x30, Vrf1Sel */ - REG_INIT(AB8500_VRF1VAUX3SEL, 0x04, 0x21, 0x07), + REG_INIT(AB8500_VRF1VAUX3SEL, 0x04, 0x21, 0x37), /* * 0x01, VextSupply12LP */ REG_INIT(AB8500_REGUCTRL2SPARE, 0x04, 0x22, 0x01), /* + * 0x01, VpllDisch + * 0x02, Vrf1Disch * 0x04, Vaux1Disch * 0x08, Vaux2Disch * 0x10, Vaux3Disch @@ -802,13 +820,15 @@ static struct ab8500_reg_init ab8500_reg_init[] = { * 0x40, VTVoutDisch * 0x80, VaudioDisch */ - REG_INIT(AB8500_REGUCTRLDISCH, 0x04, 0x43, 0xfc), + REG_INIT(AB8500_REGUCTRLDISCH, 0x04, 0x43, 0xff), /* + * 0x01, VsimDisch * 0x02, VanaDisch * 0x04, VdmicPullDownEna + * 0x08, VpllPullDownEna * 0x10, VdmicDisch */ - REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), + REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x1f), }; static int ab8500_regulator_init_registers(struct platform_device *pdev, diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index a1d245f13d9c..dd7944f735d8 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -61,6 +61,7 @@ struct ab8500_regulator_reg_init { /* AB8500 registers */ enum ab8500_regulator_reg { + AB8500_REGUREQUESTCTRL1, AB8500_REGUREQUESTCTRL2, AB8500_REGUREQUESTCTRL3, AB8500_REGUREQUESTCTRL4, @@ -77,26 +78,28 @@ enum ab8500_regulator_reg { AB8500_REGUMISC1, AB8500_VAUDIOSUPPLY, AB8500_REGUCTRL1VAMIC, + AB8500_VSMPS1REGU, + AB8500_VSMPS2REGU, + AB8500_VSMPS3REGU, /* NOTE! PRCMU register */ AB8500_VPLLVANAREGU, AB8500_VREFDDR, AB8500_EXTSUPPLYREGU, AB8500_VAUX12REGU, AB8500_VRF1VAUX3REGU, + AB8500_VSMPS1SEL1, + AB8500_VSMPS1SEL2, + AB8500_VSMPS1SEL3, + AB8500_VSMPS2SEL1, + AB8500_VSMPS2SEL2, + AB8500_VSMPS2SEL3, + AB8500_VSMPS3SEL1, /* NOTE! PRCMU register */ + AB8500_VSMPS3SEL2, /* NOTE! PRCMU register */ AB8500_VAUX1SEL, AB8500_VAUX2SEL, AB8500_VRF1VAUX3SEL, AB8500_REGUCTRL2SPARE, AB8500_REGUCTRLDISCH, AB8500_REGUCTRLDISCH2, - AB8500_ARMREGU2, /* NOTE! PRCMU register */ - AB8500_VBBSEL1, /* NOTE! PRCMU register */ - AB8500_VBBSEL2, /* NOTE! PRCMU register */ - AB8500_VSMPS1REGU, - AB8500_VSMPS2REGU, - AB8500_VSMPS3REGU, /* NOTE! PRCMU register */ - AB8500_VSMPS1SEL1, - AB8500_VSMPS3SEL1, /* NOTE! PRCMU register */ - AB8500_VSMPS3SEL2, /* NOTE! PRCMU register */ AB8500_NUM_REGULATOR_REGISTERS, }; -- cgit v1.2.3 From 732805a563617aafc7405409c03182afafb3943b Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Thu, 21 Mar 2013 15:59:03 +0000 Subject: regulator: ab8500: Separate regulator and MFD platform data The ab8500 MFD should not have knowledge about regulator- specific platform data like number of regulators and regulator registers. As the regulator platform data is about to grow with external regulators, this information is moved to a new structure provided by the regulator driver. Signed-off-by: Bengt Jonsson Signed-off-by: Lee Jones Reviewed-by: Yvan FILLION Signed-off-by: Mark Brown --- arch/arm/mach-ux500/board-mop500-regulators.c | 12 +++++++++--- arch/arm/mach-ux500/board-mop500-regulators.h | 4 +--- drivers/regulator/ab8500.c | 21 +++++++++++++++------ include/linux/regulator/ab8500.h | 7 +++++++ 4 files changed, 32 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index a8141e3e8ca1..0fd84d42e1ec 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -122,8 +122,7 @@ static struct regulator_consumer_supply ab8500_vana_consumers[] = { }; /* ab8500 regulator register initialization */ -struct ab8500_regulator_reg_init -ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { +static struct ab8500_regulator_reg_init ab8500_reg_init[] = { /* * VanaRequestCtrl = HP/LP depending on VxRequest * VpllRequestCtrl = HP/LP depending on VxRequest @@ -314,7 +313,7 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = { }; /* AB8500 regulators */ -struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { +static struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { /* supplies to the display/camera */ [AB8500_LDO_AUX1] = { .constraints = { @@ -423,3 +422,10 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { .consumer_supplies = ab8500_vana_consumers, }, }; + +struct ab8500_regulator_platform_data ab8500_regulator_plat_data = { + .reg_init = ab8500_reg_init, + .num_reg_init = ARRAY_SIZE(ab8500_reg_init), + .regulator = ab8500_regulators, + .num_regulator = ARRAY_SIZE(ab8500_regulators), +}; diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h index 78a0642a2206..9ca4869a6f23 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.h +++ b/arch/arm/mach-ux500/board-mop500-regulators.h @@ -14,9 +14,7 @@ #include #include -extern struct ab8500_regulator_reg_init -ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS]; -extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS]; +extern struct ab8500_regulator_platform_data ab8500_regulator_plat_data; extern struct regulator_init_data tps61052_regulator; extern struct regulator_init_data gpio_en_3v3_regulator; diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index c7784c4bff4f..f7d1f538c200 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -939,8 +939,9 @@ ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np) static int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); - struct ab8500_platform_data *pdata; struct device_node *np = pdev->dev.of_node; + struct ab8500_platform_data *ppdata; + struct ab8500_regulator_platform_data *pdata; int i, err; if (np) { @@ -961,7 +962,14 @@ static int ab8500_regulator_probe(struct platform_device *pdev) dev_err(&pdev->dev, "null mfd parent\n"); return -EINVAL; } - pdata = dev_get_platdata(ab8500->dev); + + ppdata = dev_get_platdata(ab8500->dev); + if (!ppdata) { + dev_err(&pdev->dev, "null parent pdata\n"); + return -EINVAL; + } + + pdata = ppdata->regulator; if (!pdata) { dev_err(&pdev->dev, "null pdata\n"); return -EINVAL; @@ -974,12 +982,12 @@ static int ab8500_regulator_probe(struct platform_device *pdev) } /* initialize registers */ - for (i = 0; i < pdata->num_regulator_reg_init; i++) { + for (i = 0; i < pdata->num_reg_init; i++) { int id, mask, value; - id = pdata->regulator_reg_init[i].id; - mask = pdata->regulator_reg_init[i].mask; - value = pdata->regulator_reg_init[i].value; + id = pdata->reg_init[i].id; + mask = pdata->reg_init[i].mask; + value = pdata->reg_init[i].value; /* check for configuration errors */ BUG_ON(id >= AB8500_NUM_REGULATOR_REGISTERS); @@ -1045,5 +1053,6 @@ module_exit(ab8500_regulator_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Sundar Iyer "); +MODULE_AUTHOR("Bengt Jonsson "); MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC"); MODULE_ALIAS("platform:ab8500-regulator"); diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index dd7944f735d8..3a8e02687f7b 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -152,4 +152,11 @@ enum ab9540_regulator_reg { AB9540_NUM_REGULATOR_REGISTERS, }; +struct ab8500_regulator_platform_data { + int num_reg_init; + struct ab8500_regulator_reg_init *reg_init; + int num_regulator; + struct regulator_init_data *regulator; +}; + #endif -- cgit v1.2.3 From 43a5911b3dcec81add87d833cd8c7ddaaa205a47 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 21 Mar 2013 15:59:15 +0000 Subject: regulator: ab8500: Clean out SoC registers Clean out initialisation that is handled by SoC. Regulator settings for Vpll (partly), Vsmps1, Vsmps2, Vsmps3 (partly), Vrf1, Varm, Vape, Vbb, Vmod are cleaned out. They should not be touched by the kernel. We also update many of the initialisation values to be more in-line with the current development efforts of ST-Ericsson internal engineers. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- arch/arm/mach-ux500/board-mop500-regulators.c | 28 ++------ drivers/regulator/ab8500.c | 98 +++++++-------------------- include/linux/regulator/ab8500.h | 12 ---- 3 files changed, 28 insertions(+), 110 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index c962d1d726bb..3d899c51bbac 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -139,10 +139,9 @@ static struct regulator_consumer_supply ab8500_vana_consumers[] = { static struct ab8500_regulator_reg_init ab8500_reg_init[] = { /* * VanaRequestCtrl = HP/LP depending on VxRequest - * VpllRequestCtrl = HP/LP depending on VxRequest * VextSupply1RequestCtrl = HP/LP depending on VxRequest */ - INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xfc, 0x00), + INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xf0, 0x00), /* * VextSupply2RequestCtrl = HP/LP depending on VxRequest * VextSupply3RequestCtrl = HP/LP depending on VxRequest @@ -156,16 +155,12 @@ static struct ab8500_regulator_reg_init ab8500_reg_init[] = { */ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x07, 0x00), /* - * Vsmps1SysClkReq1HPValid = enabled - * Vsmps2SysClkReq1HPValid = enabled - * Vsmps3SysClkReq1HPValid = enabled * VanaSysClkReq1HPValid = disabled - * VpllSysClkReq1HPValid = enabled * Vaux1SysClkReq1HPValid = disabled * Vaux2SysClkReq1HPValid = disabled * Vaux3SysClkReq1HPValid = disabled */ - INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xff, 0x17), + INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00), /* * VextSupply1SysClkReq1HPValid = disabled * VextSupply2SysClkReq1HPValid = disabled @@ -252,17 +247,7 @@ static struct ab8500_regulator_reg_init ab8500_reg_init[] = { */ INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00), /* - * Vsmps1Regu = HW control - * Vsmps1SelCtrl = Vsmps1 voltage defined by Vsmsp1Sel2 - */ - INIT_REGULATOR_REGISTER(AB8500_VSMPS1REGU, 0x0f, 0x06), - /* - * Vsmps2Regu = HW control - * Vsmps2SelCtrl = Vsmps2 voltage defined by Vsmsp2Sel2 - */ - INIT_REGULATOR_REGISTER(AB8500_VSMPS2REGU, 0x0f, 0x06), - /* - * VPll = Hw controlled + * VPll = Hw controlled (NOTE! PRCMU bits) * VanaRegu = force off */ INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x0f, 0x02), @@ -285,14 +270,9 @@ static struct ab8500_regulator_reg_init ab8500_reg_init[] = { */ INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x0f, 0x01), /* - * Vrf1Regu = HW control * Vaux3Regu = force off */ - INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x0f, 0x08), - /* - * Vsmps1 = 1.15V - */ - INIT_REGULATOR_REGISTER(AB8500_VSMPS1SEL1, 0x3f, 0x24), + INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x03, 0x00), /* * Vaux1Sel = 2.5 V */ diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index f1453a66a0fd..919d9fa9605e 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -613,19 +613,10 @@ struct ab8500_reg_init { static struct ab8500_reg_init ab8500_reg_init[] = { /* - * 0x03, VarmRequestCtrl - * 0x0c, VapeRequestCtrl - * 0x30, Vsmps1RequestCtrl - * 0xc0, Vsmps2RequestCtrl - */ - REG_INIT(AB8500_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), - /* - * 0x03, Vsmps3RequestCtrl - * 0x0c, VpllRequestCtrl * 0x30, VanaRequestCtrl * 0xc0, VextSupply1RequestCtrl */ - REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xff), + REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xf0), /* * 0x03, VextSupply2RequestCtrl * 0x0c, VextSupply3RequestCtrl @@ -639,91 +630,74 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), /* - * 0x01, Vsmps1SysClkReq1HPValid - * 0x02, Vsmps2SysClkReq1HPValid - * 0x04, Vsmps3SysClkReq1HPValid * 0x08, VanaSysClkReq1HPValid - * 0x10, VpllSysClkReq1HPValid * 0x20, Vaux1SysClkReq1HPValid * 0x40, Vaux2SysClkReq1HPValid * 0x80, Vaux3SysClkReq1HPValid */ - REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), + REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xe8), /* - * 0x01, VapeSysClkReq1HPValid - * 0x02, VarmSysClkReq1HPValid - * 0x04, VbbSysClkReq1HPValid - * 0x08, VmodSysClkReq1HPValid * 0x10, VextSupply1SysClkReq1HPValid * 0x20, VextSupply2SysClkReq1HPValid * 0x40, VextSupply3SysClkReq1HPValid */ - REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x7f), + REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x70), /* - * 0x01, Vsmps1HwHPReq1Valid - * 0x02, Vsmps2HwHPReq1Valid - * 0x04, Vsmps3HwHPReq1Valid * 0x08, VanaHwHPReq1Valid - * 0x10, VpllHwHPReq1Valid * 0x20, Vaux1HwHPReq1Valid * 0x40, Vaux2HwHPReq1Valid * 0x80, Vaux3HwHPReq1Valid */ - REG_INIT(AB8500_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), + REG_INIT(AB8500_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xe8), /* * 0x01, VextSupply1HwHPReq1Valid * 0x02, VextSupply2HwHPReq1Valid * 0x04, VextSupply3HwHPReq1Valid - * 0x08, VmodHwHPReq1Valid */ - REG_INIT(AB8500_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x0f), + REG_INIT(AB8500_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07), /* - * 0x01, Vsmps1HwHPReq2Valid - * 0x02, Vsmps2HwHPReq2Valid - * 0x03, Vsmps3HwHPReq2Valid * 0x08, VanaHwHPReq2Valid - * 0x10, VpllHwHPReq2Valid * 0x20, Vaux1HwHPReq2Valid * 0x40, Vaux2HwHPReq2Valid * 0x80, Vaux3HwHPReq2Valid */ - REG_INIT(AB8500_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), + REG_INIT(AB8500_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xe8), /* * 0x01, VextSupply1HwHPReq2Valid * 0x02, VextSupply2HwHPReq2Valid * 0x04, VextSupply3HwHPReq2Valid - * 0x08, VmodHwHPReq2Valid */ - REG_INIT(AB8500_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x0f), + REG_INIT(AB8500_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07), /* - * 0x01, VapeSwHPReqValid - * 0x02, VarmSwHPReqValid - * 0x04, Vsmps1SwHPReqValid - * 0x08, Vsmps2SwHPReqValid - * 0x10, Vsmps3SwHPReqValid * 0x20, VanaSwHPReqValid - * 0x40, VpllSwHPReqValid * 0x80, Vaux1SwHPReqValid */ - REG_INIT(AB8500_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), + REG_INIT(AB8500_REGUSWHPREQVALID1, 0x03, 0x0d, 0xa0), /* * 0x01, Vaux2SwHPReqValid * 0x02, Vaux3SwHPReqValid * 0x04, VextSupply1SwHPReqValid * 0x08, VextSupply2SwHPReqValid * 0x10, VextSupply3SwHPReqValid - * 0x20, VmodSwHPReqValid */ - REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x3f), + REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f), /* * 0x02, SysClkReq2Valid1 - * ... + * 0x04, SysClkReq3Valid1 + * 0x08, SysClkReq4Valid1 + * 0x10, SysClkReq5Valid1 + * 0x20, SysClkReq6Valid1 + * 0x40, SysClkReq7Valid1 * 0x80, SysClkReq8Valid1 */ REG_INIT(AB8500_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xfe), /* * 0x02, SysClkReq2Valid2 - * ... + * 0x04, SysClkReq3Valid2 + * 0x08, SysClkReq4Valid2 + * 0x10, SysClkReq5Valid2 + * 0x20, SysClkReq6Valid2 + * 0x40, SysClkReq7Valid2 * 0x80, SysClkReq8Valid2 */ REG_INIT(AB8500_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xfe), @@ -748,21 +722,7 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), /* - * 0x03, Vsmps1Regu - * 0x0c, Vsmps1SelCtrl - * 0x10, Vsmps1AutoMode - * 0x20, Vsmps1PWMMode - */ - REG_INIT(AB8500_VSMPS1REGU, 0x04, 0x03, 0x3f), - /* - * 0x03, Vsmps2Regu - * 0x0c, Vsmps2SelCtrl - * 0x10, Vsmps2AutoMode - * 0x20, Vsmps2PWMMode - */ - REG_INIT(AB8500_VSMPS2REGU, 0x04, 0x04, 0x3f), - /* - * 0x03, VpllRegu + * 0x03, VpllRegu (NOTE! PRCMU register bits) * 0x0c, VanaRegu */ REG_INIT(AB8500_VPLLVANAREGU, 0x04, 0x06, 0x0f), @@ -785,14 +745,9 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_VAUX12REGU, 0x04, 0x09, 0x0f), /* - * 0x0c, Vrf1Regu * 0x03, Vaux3Regu */ - REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), - /* - * 0x3f, Vsmps1Sel1 - */ - REG_INIT(AB8500_VSMPS1SEL1, 0x04, 0x13, 0x3f), + REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x03), /* * 0x0f, Vaux1Sel */ @@ -803,16 +758,13 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_VAUX2SEL, 0x04, 0x20, 0x0f), /* * 0x07, Vaux3Sel - * 0x30, Vrf1Sel */ - REG_INIT(AB8500_VRF1VAUX3SEL, 0x04, 0x21, 0x37), + REG_INIT(AB8500_VRF1VAUX3SEL, 0x04, 0x21, 0x07), /* * 0x01, VextSupply12LP */ REG_INIT(AB8500_REGUCTRL2SPARE, 0x04, 0x22, 0x01), /* - * 0x01, VpllDisch - * 0x02, Vrf1Disch * 0x04, Vaux1Disch * 0x08, Vaux2Disch * 0x10, Vaux3Disch @@ -820,15 +772,13 @@ static struct ab8500_reg_init ab8500_reg_init[] = { * 0x40, VTVoutDisch * 0x80, VaudioDisch */ - REG_INIT(AB8500_REGUCTRLDISCH, 0x04, 0x43, 0xff), + REG_INIT(AB8500_REGUCTRLDISCH, 0x04, 0x43, 0xfc), /* - * 0x01, VsimDisch * 0x02, VanaDisch * 0x04, VdmicPullDownEna - * 0x08, VpllPullDownEna * 0x10, VdmicDisch */ - REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x1f), + REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), }; static int ab8500_regulator_init_registers(struct platform_device *pdev, diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 3a8e02687f7b..26792ff360be 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -61,7 +61,6 @@ struct ab8500_regulator_reg_init { /* AB8500 registers */ enum ab8500_regulator_reg { - AB8500_REGUREQUESTCTRL1, AB8500_REGUREQUESTCTRL2, AB8500_REGUREQUESTCTRL3, AB8500_REGUREQUESTCTRL4, @@ -78,22 +77,11 @@ enum ab8500_regulator_reg { AB8500_REGUMISC1, AB8500_VAUDIOSUPPLY, AB8500_REGUCTRL1VAMIC, - AB8500_VSMPS1REGU, - AB8500_VSMPS2REGU, - AB8500_VSMPS3REGU, /* NOTE! PRCMU register */ AB8500_VPLLVANAREGU, AB8500_VREFDDR, AB8500_EXTSUPPLYREGU, AB8500_VAUX12REGU, AB8500_VRF1VAUX3REGU, - AB8500_VSMPS1SEL1, - AB8500_VSMPS1SEL2, - AB8500_VSMPS1SEL3, - AB8500_VSMPS2SEL1, - AB8500_VSMPS2SEL2, - AB8500_VSMPS2SEL3, - AB8500_VSMPS3SEL1, /* NOTE! PRCMU register */ - AB8500_VSMPS3SEL2, /* NOTE! PRCMU register */ AB8500_VAUX1SEL, AB8500_VAUX2SEL, AB8500_VRF1VAUX3SEL, -- cgit v1.2.3 From d1a820011b2fbc11d5af80d1a961fe66c613fa4b Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 28 Mar 2013 16:11:01 +0000 Subject: regulator: ab8500-ext: New driver to control external regulators The ABx500 is capable of controlling three external regulator supplies. Most commonly on and off are supported, but if an external regulator chipset or power supply supports high-power and low-power mode settings, we can control those too. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/Makefile | 2 +- drivers/regulator/ab8500-ext.c | 394 +++++++++++++++++++++++++++++++++++++++ drivers/regulator/ab8500.c | 12 +- include/linux/regulator/ab8500.h | 28 +++ 4 files changed, 434 insertions(+), 2 deletions(-) create mode 100644 drivers/regulator/ab8500-ext.c (limited to 'include/linux') diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 6e8250382def..47a34ff88f98 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o -obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o +obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o ab8500-ext.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c new file mode 100644 index 000000000000..95008dec5190 --- /dev/null +++ b/drivers/regulator/ab8500-ext.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Authors: Bengt Jonsson + * + * This file is based on drivers/regulator/ab8500.c + * + * AB8500 external regulators + * + * ab8500-ext supports the following regulators: + * - VextSupply3 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct ab8500_ext_regulator_info - ab8500 regulator information + * @dev: device pointer + * @desc: regulator description + * @rdev: regulator device + * @is_enabled: status of regulator (on/off) + * @update_bank: bank to control on/off + * @update_reg: register to control on/off + * @update_mask: mask to enable/disable and set mode of regulator + * @update_val: bits holding the regulator current mode + * @update_val_en: bits to set EN pin active (LPn pin deactive) + * normally this means high power mode + * @update_val_en_lp: bits to set EN pin active and LPn pin active + * normally this means low power mode + * @delay: startup delay in ms + */ +struct ab8500_ext_regulator_info { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + bool is_enabled; + u8 update_bank; + u8 update_reg; + u8 update_mask; + u8 update_val; + u8 update_val_en; + u8 update_val_en_lp; +}; + +static int ab8500_ext_regulator_enable(struct regulator_dev *rdev) +{ + int ret; + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, + info->update_mask, info->update_val); + if (ret < 0) + dev_err(rdev_get_dev(info->rdev), + "couldn't set enable bits for regulator\n"); + + info->is_enabled = true; + + dev_dbg(rdev_get_dev(rdev), "%s-enable (bank, reg, mask, value):" + " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, info->update_val); + + return ret; +} + +static int ab8500_ext_regulator_disable(struct regulator_dev *rdev) +{ + int ret; + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, + info->update_mask, 0x0); + if (ret < 0) + dev_err(rdev_get_dev(info->rdev), + "couldn't set disable bits for regulator\n"); + + info->is_enabled = false; + + dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):" + " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, 0x0); + + return ret; +} + +static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev) +{ + int ret; + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + ret = abx500_get_register_interruptible(info->dev, + info->update_bank, info->update_reg, ®val); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't read 0x%x register\n", info->update_reg); + return ret; + } + + dev_dbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value):" + " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, regval); + + if (regval & info->update_mask) + info->is_enabled = true; + else + info->is_enabled = false; + + return info->is_enabled; +} + +static int ab8500_ext_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + int ret = 0; + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + switch (mode) { + case REGULATOR_MODE_NORMAL: + info->update_val = info->update_val_hp; + break; + case REGULATOR_MODE_IDLE: + info->update_val = info->update_val_lp; + break; + + default: + return -EINVAL; + } + + if (info->is_enabled) { + u8 regval; + + ret = enable(info, ®val); + if (ret < 0) + dev_err(rdev_get_dev(rdev), + "Could not set regulator mode.\n"); + + dev_dbg(rdev_get_dev(rdev), + "%s-set_mode (bank, reg, mask, value): " + "0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, regval); + } + + return ret; +} + +static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev) +{ + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + if (info->update_val == info->update_val_hp) + ret = REGULATOR_MODE_NORMAL; + else if (info->update_val == info->update_val_lp) + ret = REGULATOR_MODE_IDLE; + else + ret = -EINVAL; + + return ret; +} + +static int ab8500_ext_fixed_get_voltage(struct regulator_dev *rdev) +{ + struct regulation_constraints *regu_constraints = rdev->constraints; + + if (regu_constraints == NULL) { + dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n"); + return -EINVAL; + } + if (regu_constraints->min_uV && regu_constraints->max_uV) { + if (regu_constraints->min_uV == regu_constraints->max_uV) + return regu_constraints->min_uV; + } + return -EINVAL; +} + +static int ab8500_ext_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + struct regulation_constraints *regu_constraints = rdev->constraints; + + if (regu_constraints == NULL) { + dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n"); + return -EINVAL; + } + /* return the uV for the fixed regulators */ + if (regu_constraints->min_uV && regu_constraints->max_uV) { + if (regu_constraints->min_uV == regu_constraints->max_uV) + return regu_constraints->min_uV; + } + return -EINVAL; +} + +static struct regulator_ops ab8500_ext_regulator_ops = { + .enable = ab8500_ext_regulator_enable, + .disable = ab8500_ext_regulator_disable, + .is_enabled = ab8500_ext_regulator_is_enabled, + .set_mode = ab8500_ext_regulator_set_mode, + .get_mode = ab8500_ext_regulator_get_mode, + .get_voltage = ab8500_ext_fixed_get_voltage, + .list_voltage = ab8500_ext_list_voltage, +}; + + +static struct ab8500_ext_regulator_info + ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = { + [AB8500_EXT_SUPPLY1] = { + .desc = { + .name = "VEXTSUPPLY1", + .ops = &ab8500_ext_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_EXT_SUPPLY1, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x04, + .update_reg = 0x08, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_hp = 0x01, + .update_val_lp = 0x03, + .update_val_hw = 0x02, + }, + [AB8500_EXT_SUPPLY2] = { + .desc = { + .name = "VEXTSUPPLY2", + .ops = &ab8500_ext_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_EXT_SUPPLY2, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x04, + .update_reg = 0x08, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_hp = 0x04, + .update_val_lp = 0x0c, + .update_val_hw = 0x08, + }, + [AB8500_EXT_SUPPLY3] = { + .desc = { + .name = "VEXTSUPPLY3", + .ops = &ab8500_ext_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_EXT_SUPPLY3, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x04, + .update_reg = 0x08, + .update_mask = 0x30, + .update_val = 0x10, + .update_val_en = 0x10, + .update_val_en_lp = 0x30, + }, +}; + +int ab8500_ext_regulator_init(struct platform_device *pdev) +{ + struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); + struct ab8500_platform_data *ppdata; + struct ab8500_regulator_platform_data *pdata; + struct regulator_config config = { }; + int i, err; + + if (!ab8500) { + dev_err(&pdev->dev, "null mfd parent\n"); + return -EINVAL; + } + ppdata = dev_get_platdata(ab8500->dev); + if (!ppdata) { + dev_err(&pdev->dev, "null parent pdata\n"); + return -EINVAL; + } + + pdata = ppdata->regulator; + if (!pdata) { + dev_err(&pdev->dev, "null pdata\n"); + return -EINVAL; + } + + /* make sure the platform data has the correct size */ + if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) { + dev_err(&pdev->dev, "Configuration error: size mismatch.\n"); + return -EINVAL; + } + + /* check for AB8500 2.x */ + if (abx500_get_chip_id(&pdev->dev) < 0x30) { + struct ab8500_ext_regulator_info *info; + + /* VextSupply3LPn is inverted on AB8500 2.x */ + info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3]; + info->update_val = 0x30; + info->update_val_en = 0x30; + info->update_val_en_lp = 0x10; + } + + /* register all regulators */ + for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { + struct ab8500_ext_regulator_info *info = NULL; + + /* assign per-regulator data */ + info = &ab8500_ext_regulator_info[i]; + info->dev = &pdev->dev; + + config.dev = &pdev->dev; + config.init_data = &pdata->ext_regulator[i]; + config.driver_data = info; + + /* register regulator with framework */ + info->rdev = regulator_register(&info->desc, &config); + + if (IS_ERR(info->rdev)) { + err = PTR_ERR(info->rdev); + dev_err(&pdev->dev, "failed to register regulator %s\n", + info->desc.name); + /* when we fail, un-register all earlier regulators */ + while (--i >= 0) { + info = &ab8500_ext_regulator_info[i]; + regulator_unregister(info->rdev); + } + return err; + } + + dev_dbg(rdev_get_dev(info->rdev), + "%s-probed\n", info->desc.name); + } + + return 0; +} + +int ab8500_ext_regulator_exit(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { + struct ab8500_ext_regulator_info *info = NULL; + info = &ab8500_ext_regulator_info[i]; + + dev_vdbg(rdev_get_dev(info->rdev), + "%s-remove\n", info->desc.name); + + regulator_unregister(info->rdev); + } + + return 0; +} + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Bengt Jonsson "); +MODULE_DESCRIPTION("AB8500 external regulator driver"); +MODULE_ALIAS("platform:ab8500-ext-regulator"); diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 3a1896655557..49746884923d 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -947,6 +947,11 @@ static int ab8500_regulator_probe(struct platform_device *pdev) return err; } + /* register external regulators (before Vaux1, 2 and 3) */ + err = ab8500_ext_regulator_init(pdev); + if (err) + return err; + /* register all regulators */ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { err = ab8500_regulator_register(pdev, &pdata->regulator[i], i, NULL); @@ -959,7 +964,7 @@ static int ab8500_regulator_probe(struct platform_device *pdev) static int ab8500_regulator_remove(struct platform_device *pdev) { - int i; + int i, err; for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { struct ab8500_regulator_info *info = NULL; @@ -971,6 +976,11 @@ static int ab8500_regulator_remove(struct platform_device *pdev) regulator_unregister(info->regulator); } + /* remove external regulators (after Vaux1, 2 and 3) */ + err = ab8500_ext_regulator_exit(pdev); + if (err) + return err; + return 0; } diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 26792ff360be..4e92e5b879a5 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -10,6 +10,8 @@ #ifndef __LINUX_MFD_AB8500_REGULATOR_H #define __LINUX_MFD_AB8500_REGULATOR_H +#include + /* AB8500 regulators */ enum ab8500_regulator_id { AB8500_LDO_AUX1, @@ -140,11 +142,37 @@ enum ab9540_regulator_reg { AB9540_NUM_REGULATOR_REGISTERS, }; +/* AB8500 external regulators */ +enum ab8500_ext_regulator_id { + AB8500_EXT_SUPPLY1, + AB8500_EXT_SUPPLY2, + AB8500_EXT_SUPPLY3, + AB8500_NUM_EXT_REGULATORS, +}; + +/* AB8500 regulator platform data */ struct ab8500_regulator_platform_data { int num_reg_init; struct ab8500_regulator_reg_init *reg_init; int num_regulator; struct regulator_init_data *regulator; + int num_ext_regulator; + struct regulator_init_data *ext_regulator; }; +/* AB8500 external regulator functions (internal) */ +#ifdef CONFIG_REGULATOR_AB8500_EXT +int ab8500_ext_regulator_init(struct platform_device *pdev); +int ab8500_ext_regulator_exit(struct platform_device *pdev); +#else +inline int ab8500_ext_regulator_init(struct platform_device *pdev) +{ + return 0; +} +inline int ab8500_ext_regulator_exit(struct platform_device *pdev) +{ + return 0; +} +#endif + #endif -- cgit v1.2.3 From 18bc2b39307b45527efc6c84836953c7a8f2181e Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Thu, 28 Mar 2013 16:11:06 +0000 Subject: regulator: ab8500-ext: Add HW request support Support for HW request is added in the external regulator driver. A flag in the board configuration can be set to let HW control the regulator when there is no SW request. This means that the regulator will be put in high power mode when there is a SW request and in HW-request mode otherwise. Signed-off-by: Bengt Jonsson Signed-off-by: Lee Jones Reviewed-by: Mattias NILSSON Reviewed-by: Jonas ABERG Signed-off-by: Mark Brown --- drivers/regulator/ab8500-ext.c | 98 +++++++++++++++++++++++++++++----------- include/linux/regulator/ab8500.h | 4 ++ 2 files changed, 75 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c index 95008dec5190..21b9bfb0fc5e 100644 --- a/drivers/regulator/ab8500-ext.c +++ b/drivers/regulator/ab8500-ext.c @@ -28,80 +28,121 @@ * @dev: device pointer * @desc: regulator description * @rdev: regulator device + * @cfg: regulator configuration (extension of regulator FW configuration) * @is_enabled: status of regulator (on/off) * @update_bank: bank to control on/off * @update_reg: register to control on/off * @update_mask: mask to enable/disable and set mode of regulator * @update_val: bits holding the regulator current mode - * @update_val_en: bits to set EN pin active (LPn pin deactive) + * @update_val_hp: bits to set EN pin active (LPn pin deactive) * normally this means high power mode - * @update_val_en_lp: bits to set EN pin active and LPn pin active - * normally this means low power mode - * @delay: startup delay in ms + * @update_val_lp: bits to set EN pin active and LPn pin active + * normally this means low power mode + * @update_val_hw: bits to set regulator pins in HW control + * SysClkReq pins and logic will choose mode */ struct ab8500_ext_regulator_info { struct device *dev; struct regulator_desc desc; struct regulator_dev *rdev; + struct ab8500_ext_regulator_cfg *cfg; bool is_enabled; u8 update_bank; u8 update_reg; u8 update_mask; u8 update_val; - u8 update_val_en; - u8 update_val_en_lp; + u8 update_val_hp; + u8 update_val_lp; + u8 update_val_hw; }; -static int ab8500_ext_regulator_enable(struct regulator_dev *rdev) +static int enable(struct ab8500_ext_regulator_info *info, u8 *regval) { int ret; - struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); - if (info == NULL) { - dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); - return -EINVAL; - } + *regval = info->update_val; + + /* + * To satisfy both HW high power request and SW request, the regulator + * must be on in high power. + */ + if (info->cfg && info->cfg->hwreq) + *regval = info->update_val_hp; ret = abx500_mask_and_set_register_interruptible(info->dev, info->update_bank, info->update_reg, - info->update_mask, info->update_val); + info->update_mask, *regval); if (ret < 0) dev_err(rdev_get_dev(info->rdev), "couldn't set enable bits for regulator\n"); info->is_enabled = true; - dev_dbg(rdev_get_dev(rdev), "%s-enable (bank, reg, mask, value):" - " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", - info->desc.name, info->update_bank, info->update_reg, - info->update_mask, info->update_val); - return ret; } -static int ab8500_ext_regulator_disable(struct regulator_dev *rdev) +static int ab8500_ext_regulator_enable(struct regulator_dev *rdev) { int ret; struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; if (info == NULL) { dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; } + ret = enable(info, ®val); + + dev_dbg(rdev_get_dev(rdev), "%s-enable (bank, reg, mask, value):" + " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, regval); + + return ret; +} + +static int disable(struct ab8500_ext_regulator_info *info, u8 *regval) +{ + int ret; + + *regval = 0x0; + + /* + * Set the regulator in HW request mode if configured + */ + if (info->cfg && info->cfg->hwreq) + *regval = info->update_val_hw; + ret = abx500_mask_and_set_register_interruptible(info->dev, info->update_bank, info->update_reg, - info->update_mask, 0x0); + info->update_mask, *regval); if (ret < 0) dev_err(rdev_get_dev(info->rdev), "couldn't set disable bits for regulator\n"); info->is_enabled = false; + return ret; +} + +static int ab8500_ext_regulator_disable(struct regulator_dev *rdev) +{ + int ret; + struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + ret = disable(info, ®val); + dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):" " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", info->desc.name, info->update_bank, info->update_reg, - info->update_mask, 0x0); + info->update_mask, regval); return ret; } @@ -130,7 +171,8 @@ static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev) info->desc.name, info->update_bank, info->update_reg, info->update_mask, regval); - if (regval & info->update_mask) + if (((regval & info->update_mask) == info->update_val_lp) || + ((regval & info->update_mask) == info->update_val_hp)) info->is_enabled = true; else info->is_enabled = false; @@ -241,7 +283,6 @@ static struct regulator_ops ab8500_ext_regulator_ops = { .list_voltage = ab8500_ext_list_voltage, }; - static struct ab8500_ext_regulator_info ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = { [AB8500_EXT_SUPPLY1] = { @@ -291,8 +332,9 @@ static struct ab8500_ext_regulator_info .update_reg = 0x08, .update_mask = 0x30, .update_val = 0x10, - .update_val_en = 0x10, - .update_val_en_lp = 0x30, + .update_val_hp = 0x10, + .update_val_lp = 0x30, + .update_val_hw = 0x20, }, }; @@ -333,8 +375,8 @@ int ab8500_ext_regulator_init(struct platform_device *pdev) /* VextSupply3LPn is inverted on AB8500 2.x */ info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3]; info->update_val = 0x30; - info->update_val_en = 0x30; - info->update_val_en_lp = 0x10; + info->update_val_hp = 0x30; + info->update_val_lp = 0x10; } /* register all regulators */ @@ -344,6 +386,8 @@ int ab8500_ext_regulator_init(struct platform_device *pdev) /* assign per-regulator data */ info = &ab8500_ext_regulator_info[i]; info->dev = &pdev->dev; + info->cfg = (struct ab8500_ext_regulator_cfg *) + pdata->ext_regulator[i].driver_data; config.dev = &pdev->dev; config.init_data = &pdata->ext_regulator[i]; diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 4e92e5b879a5..cf496e93c0cf 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -143,6 +143,10 @@ enum ab9540_regulator_reg { }; /* AB8500 external regulators */ +struct ab8500_ext_regulator_cfg { + bool hwreq; /* requires hw mode or high power mode */ +}; + enum ab8500_ext_regulator_id { AB8500_EXT_SUPPLY1, AB8500_EXT_SUPPLY2, -- cgit v1.2.3 From 41a06aa738ad889cf96f56024ddf84ecf4a18a6f Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 28 Mar 2013 16:11:08 +0000 Subject: regulator: ab8500: Remove USB regulator The USB regulator is controlled by hardware. The software support was only needed for early hardware (ED) which is no longer supported. Signed-off-by: Bengt Jonsson Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 20 -------------------- include/linux/regulator/ab8500.h | 1 - 2 files changed, 21 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 49746884923d..4d88a604efd1 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -488,25 +488,6 @@ static struct ab8500_regulator_info .update_val_idle = 0x82, .update_val_normal = 0x02, }, - - /* - * Regulators with fixed voltage and normal mode - */ - [AB8500_LDO_USB] = { - .desc = { - .name = "LDO-USB", - .ops = &ab8500_regulator_ops, - .type = REGULATOR_VOLTAGE, - .id = AB8500_LDO_USB, - .owner = THIS_MODULE, - .n_voltages = 1, - .min_uV = 3300000, - .enable_time = 150, - }, - .update_bank = 0x03, - .update_reg = 0x82, - .update_mask = 0x03, - }, [AB8500_LDO_AUDIO] = { .desc = { .name = "LDO-AUDIO", @@ -862,7 +843,6 @@ static struct of_regulator_match ab8500_regulator_matches[] = { { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8500_LDO_AUX3, }, { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8500_LDO_INTCORE, }, { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8500_LDO_TVOUT, }, - { .name = "ab8500_ldo_usb", .driver_data = (void *) AB8500_LDO_USB, }, { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8500_LDO_AUDIO, }, { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8500_LDO_ANAMIC1, }, { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8500_LDO_ANAMIC2, }, diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index cf496e93c0cf..b86e089195ea 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -19,7 +19,6 @@ enum ab8500_regulator_id { AB8500_LDO_AUX3, AB8500_LDO_INTCORE, AB8500_LDO_TVOUT, - AB8500_LDO_USB, AB8500_LDO_AUDIO, AB8500_LDO_ANAMIC1, AB8500_LDO_ANAMIC2, -- cgit v1.2.3 From da0b0c47dcfd92317e2ece4c3434e1f82b55cf8a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 28 Mar 2013 16:11:09 +0000 Subject: regulator: ab8500: Init debug from regulator driver The purpose of this patch is to guarantee that ab8500-debug will record the regulator registers before they are modified by the ab8500 regulator driver. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 10 ++++++++++ include/linux/regulator/ab8500.h | 14 ++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'include/linux') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 4d88a604efd1..bf34c4cd6631 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -911,6 +911,11 @@ static int ab8500_regulator_probe(struct platform_device *pdev) return -EINVAL; } + /* initialize debug (initial state is recorded with this call) */ + err = ab8500_regulator_debug_init(pdev); + if (err) + return err; + /* initialize registers */ for (i = 0; i < pdata->num_reg_init; i++) { int id, mask, value; @@ -961,6 +966,11 @@ static int ab8500_regulator_remove(struct platform_device *pdev) if (err) return err; + /* remove regulator debug */ + err = ab8500_regulator_debug_exit(pdev); + if (err) + return err; + return 0; } diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index b86e089195ea..592a3f3994c0 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -178,4 +178,18 @@ inline int ab8500_ext_regulator_exit(struct platform_device *pdev) } #endif +#ifdef CONFIG_REGULATOR_AB8500_DEBUG +int ab8500_regulator_debug_init(struct platform_device *pdev); +int ab8500_regulator_debug_exit(struct platform_device *pdev); +#else +static inline int ab8500_regulator_debug_init(struct platform_device *pdev) +{ + return 0; +} +static inline int ab8500_regulator_debug_exit(struct platform_device *pdev) +{ + return 0; +} +#endif + #endif -- cgit v1.2.3 From 547f384f33dbd6171607f925ab246e25e315961e Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 28 Mar 2013 16:11:14 +0000 Subject: regulator: ab8500: add support for ab8505 To obtain full AB8505 regulator support, the AB8500 regulator driver first needs to know its register layout and their initialisation values for each. That information is provided via a couple of large data structures which we provide here. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- arch/arm/mach-ux500/board-mop500-regulators.c | 511 ++++++++++++++++++++- arch/arm/mach-ux500/board-mop500-regulators.h | 1 + drivers/regulator/ab8500.c | 617 ++++++++++++++++++++++++++ include/linux/regulator/ab8500.h | 75 +++- 4 files changed, 1195 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index c1173a161a04..816151903d46 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -5,6 +5,7 @@ * * Authors: Sundar Iyer * Bengt Jonsson + * Daniel Willerud * * MOP500 board specific initialization for regulators */ @@ -99,6 +100,27 @@ static struct regulator_consumer_supply ab8500_vaux3_consumers[] = { REGULATOR_SUPPLY("vmmc", "sdi0"), }; +static struct regulator_consumer_supply ab8505_vaux4_consumers[] = { +}; + +static struct regulator_consumer_supply ab8505_vaux5_consumers[] = { +}; + +static struct regulator_consumer_supply ab8505_vaux6_consumers[] = { +}; + +static struct regulator_consumer_supply ab8505_vaux8_consumers[] = { + /* AB8500 audio codec device */ + REGULATOR_SUPPLY("v-aux8", NULL), +}; + +static struct regulator_consumer_supply ab8505_vadc_consumers[] = { + /* Internal general-purpose ADC */ + REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"), + /* ADC for charger */ + REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"), +}; + static struct regulator_consumer_supply ab8500_vtvout_consumers[] = { /* TV-out DENC supply */ REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"), @@ -133,6 +155,11 @@ static struct regulator_consumer_supply ab8500_vintcore_consumers[] = { REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"), }; +static struct regulator_consumer_supply ab8505_usb_consumers[] = { + /* HS USB OTG physical interface */ + REGULATOR_SUPPLY("v-ape", NULL), +}; + static struct regulator_consumer_supply ab8500_vana_consumers[] = { /* External displays, connector on board, 1v8 power supply */ REGULATOR_SUPPLY("vsmps2", "mcde.0"), @@ -469,6 +496,450 @@ static struct regulator_init_data ab8500_ext_regulators[] = { }, }; +/* ab8505 regulator register initialization */ +static struct ab8500_regulator_reg_init ab8505_reg_init[] = { + /* + * VarmRequestCtrl + * VsmpsCRequestCtrl + * VsmpsARequestCtrl + * VsmpsBRequestCtrl + */ + INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL1, 0x00, 0x00), + /* + * VsafeRequestCtrl + * VpllRequestCtrl + * VanaRequestCtrl = HP/LP depending on VxRequest + */ + INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL2, 0x30, 0x00), + /* + * Vaux1RequestCtrl = HP/LP depending on VxRequest + * Vaux2RequestCtrl = HP/LP depending on VxRequest + */ + INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL3, 0xf0, 0x00), + /* + * Vaux3RequestCtrl = HP/LP depending on VxRequest + * SwHPReq = Control through SWValid disabled + */ + INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL4, 0x07, 0x00), + /* + * VsmpsASysClkReq1HPValid + * VsmpsBSysClkReq1HPValid + * VsafeSysClkReq1HPValid + * VanaSysClkReq1HPValid = disabled + * VpllSysClkReq1HPValid + * Vaux1SysClkReq1HPValid = disabled + * Vaux2SysClkReq1HPValid = disabled + * Vaux3SysClkReq1HPValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00), + /* + * VsmpsCSysClkReq1HPValid + * VarmSysClkReq1HPValid + * VbbSysClkReq1HPValid + * VsmpsMSysClkReq1HPValid + */ + INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQ1HPVALID2, 0x00, 0x00), + /* + * VsmpsAHwHPReq1Valid + * VsmpsBHwHPReq1Valid + * VsafeHwHPReq1Valid + * VanaHwHPReq1Valid = disabled + * VpllHwHPReq1Valid + * Vaux1HwHPreq1Valid = disabled + * Vaux2HwHPReq1Valid = disabled + * Vaux3HwHPReqValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ1VALID1, 0xe8, 0x00), + /* + * VsmpsMHwHPReq1Valid + */ + INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ1VALID2, 0x00, 0x00), + /* + * VsmpsAHwHPReq2Valid + * VsmpsBHwHPReq2Valid + * VsafeHwHPReq2Valid + * VanaHwHPReq2Valid = disabled + * VpllHwHPReq2Valid + * Vaux1HwHPReq2Valid = disabled + * Vaux2HwHPReq2Valid = disabled + * Vaux3HwHPReq2Valid = disabled + */ + INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ2VALID1, 0xe8, 0x00), + /* + * VsmpsMHwHPReq2Valid + */ + INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ2VALID2, 0x00, 0x00), + /** + * VsmpsCSwHPReqValid + * VarmSwHPReqValid + * VsmpsASwHPReqValid + * VsmpsBSwHPReqValid + * VsafeSwHPReqValid + * VanaSwHPReqValid + * VanaSwHPReqValid = disabled + * VpllSwHPReqValid + * Vaux1SwHPReqValid = disabled + */ + INIT_REGULATOR_REGISTER(AB8505_REGUSWHPREQVALID1, 0xa0, 0x00), + /* + * Vaux2SwHPReqValid = disabled + * Vaux3SwHPReqValid = disabled + * VsmpsMSwHPReqValid + */ + INIT_REGULATOR_REGISTER(AB8505_REGUSWHPREQVALID2, 0x03, 0x00), + /* + * SysClkReq2Valid1 = SysClkReq2 controlled + * SysClkReq3Valid1 = disabled + * SysClkReq4Valid1 = SysClkReq4 controlled + */ + INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQVALID1, 0x0e, 0x0a), + /* + * SysClkReq2Valid2 = disabled + * SysClkReq3Valid2 = disabled + * SysClkReq4Valid2 = disabled + */ + INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQVALID2, 0x0e, 0x00), + /* + * Vaux4SwHPReqValid + * Vaux4HwHPReq2Valid + * Vaux4HwHPReq1Valid + * Vaux4SysClkReq1HPValid + */ + INIT_REGULATOR_REGISTER(AB8505_REGUVAUX4REQVALID, 0x00, 0x00), + /* + * VadcEna = disabled + * VintCore12Ena = disabled + * VintCore12Sel = 1.25 V + * VintCore12LP = inactive (HP) + * VadcLP = inactive (HP) + */ + INIT_REGULATOR_REGISTER(AB8505_REGUMISC1, 0xfe, 0x10), + /* + * VaudioEna = disabled + * Vaux8Ena = disabled + * Vamic1Ena = disabled + * Vamic2Ena = disabled + */ + INIT_REGULATOR_REGISTER(AB8505_VAUDIOSUPPLY, 0x1e, 0x00), + /* + * Vamic1_dzout = high-Z when Vamic1 is disabled + * Vamic2_dzout = high-Z when Vamic2 is disabled + */ + INIT_REGULATOR_REGISTER(AB8505_REGUCTRL1VAMIC, 0x03, 0x00), + /* + * VsmpsARegu + * VsmpsASelCtrl + * VsmpsAAutoMode + * VsmpsAPWMMode + */ + INIT_REGULATOR_REGISTER(AB8505_VSMPSAREGU, 0x00, 0x00), + /* + * VsmpsBRegu + * VsmpsBSelCtrl + * VsmpsBAutoMode + * VsmpsBPWMMode + */ + INIT_REGULATOR_REGISTER(AB8505_VSMPSBREGU, 0x00, 0x00), + /* + * VsafeRegu + * VsafeSelCtrl + * VsafeAutoMode + * VsafePWMMode + */ + INIT_REGULATOR_REGISTER(AB8505_VSAFEREGU, 0x00, 0x00), + /* + * VPll = Hw controlled (NOTE! PRCMU bits) + * VanaRegu = force off + */ + INIT_REGULATOR_REGISTER(AB8505_VPLLVANAREGU, 0x0f, 0x02), + /* + * VextSupply1Regu = force OFF (OTP_ExtSupply12LPnPolarity 1) + * VextSupply2Regu = force OFF (OTP_ExtSupply12LPnPolarity 1) + * VextSupply3Regu = force OFF (OTP_ExtSupply3LPnPolarity 0) + * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0 + * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0 + */ + INIT_REGULATOR_REGISTER(AB8505_EXTSUPPLYREGU, 0xff, 0x30), + /* + * Vaux1Regu = force HP + * Vaux2Regu = force off + */ + INIT_REGULATOR_REGISTER(AB8505_VAUX12REGU, 0x0f, 0x01), + /* + * Vaux3Regu = force off + */ + INIT_REGULATOR_REGISTER(AB8505_VRF1VAUX3REGU, 0x03, 0x00), + /* + * VsmpsASel1 + */ + INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL1, 0x00, 0x00), + /* + * VsmpsASel2 + */ + INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL2, 0x00, 0x00), + /* + * VsmpsASel3 + */ + INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL3, 0x00, 0x00), + /* + * VsmpsBSel1 + */ + INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL1, 0x00, 0x00), + /* + * VsmpsBSel2 + */ + INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL2, 0x00, 0x00), + /* + * VsmpsBSel3 + */ + INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL3, 0x00, 0x00), + /* + * VsafeSel1 + */ + INIT_REGULATOR_REGISTER(AB8505_VSAFESEL1, 0x00, 0x00), + /* + * VsafeSel2 + */ + INIT_REGULATOR_REGISTER(AB8505_VSAFESEL2, 0x00, 0x00), + /* + * VsafeSel3 + */ + INIT_REGULATOR_REGISTER(AB8505_VSAFESEL3, 0x00, 0x00), + /* + * Vaux1Sel = 2.8 V + */ + INIT_REGULATOR_REGISTER(AB8505_VAUX1SEL, 0x0f, 0x0C), + /* + * Vaux2Sel = 2.9 V + */ + INIT_REGULATOR_REGISTER(AB8505_VAUX2SEL, 0x0f, 0x0d), + /* + * Vaux3Sel = 2.91 V + */ + INIT_REGULATOR_REGISTER(AB8505_VRF1VAUX3SEL, 0x07, 0x07), + /* + * Vaux4RequestCtrl + */ + INIT_REGULATOR_REGISTER(AB8505_VAUX4REQCTRL, 0x00, 0x00), + /* + * Vaux4Regu + */ + INIT_REGULATOR_REGISTER(AB8505_VAUX4REGU, 0x00, 0x00), + /* + * Vaux4Sel + */ + INIT_REGULATOR_REGISTER(AB8505_VAUX4SEL, 0x00, 0x00), + /* + * Vaux1Disch = short discharge time + * Vaux2Disch = short discharge time + * Vaux3Disch = short discharge time + * Vintcore12Disch = short discharge time + * VTVoutDisch = short discharge time + * VaudioDisch = short discharge time + */ + INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH, 0xfc, 0x00), + /* + * VanaDisch = short discharge time + * Vaux8PullDownEna = pulldown disabled when Vaux8 is disabled + * Vaux8Disch = short discharge time + */ + INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH2, 0x16, 0x00), + /* + * Vaux4Disch = short discharge time + */ + INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH3, 0x01, 0x00), + /* + * Vaux5Sel + * Vaux5LP + * Vaux5Ena + * Vaux5Disch + * Vaux5DisSfst + * Vaux5DisPulld + */ + INIT_REGULATOR_REGISTER(AB8505_CTRLVAUX5, 0x00, 0x00), + /* + * Vaux6Sel + * Vaux6LP + * Vaux6Ena + * Vaux6DisPulld + */ + INIT_REGULATOR_REGISTER(AB8505_CTRLVAUX6, 0x00, 0x00), +}; + +struct regulator_init_data ab8505_regulators[AB8505_NUM_REGULATORS] = { + /* supplies to the display/camera */ + [AB8505_LDO_AUX1] = { + .constraints = { + .name = "V-DISPLAY", + .min_uV = 2800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, /* display is on at boot */ + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers), + .consumer_supplies = ab8500_vaux1_consumers, + }, + /* supplies to the on-board eMMC */ + [AB8505_LDO_AUX2] = { + .constraints = { + .name = "V-eMMC1", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers), + .consumer_supplies = ab8500_vaux2_consumers, + }, + /* supply for VAUX3, supplies to SDcard slots */ + [AB8505_LDO_AUX3] = { + .constraints = { + .name = "V-MMC-SD", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers), + .consumer_supplies = ab8500_vaux3_consumers, + }, + /* supply for VAUX4, supplies to NFC and standalone secure element */ + [AB8505_LDO_AUX4] = { + .constraints = { + .name = "V-NFC-SE", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux4_consumers), + .consumer_supplies = ab8505_vaux4_consumers, + }, + /* supply for VAUX5, supplies to TBD */ + [AB8505_LDO_AUX5] = { + .constraints = { + .name = "V-AUX5", + .min_uV = 1050000, + .max_uV = 2790000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux5_consumers), + .consumer_supplies = ab8505_vaux5_consumers, + }, + /* supply for VAUX6, supplies to TBD */ + [AB8505_LDO_AUX6] = { + .constraints = { + .name = "V-AUX6", + .min_uV = 1050000, + .max_uV = 2790000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux6_consumers), + .consumer_supplies = ab8505_vaux6_consumers, + }, + /* supply for gpadc, ADC LDO */ + [AB8505_LDO_ADC] = { + .constraints = { + .name = "V-ADC", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8505_vadc_consumers), + .consumer_supplies = ab8505_vadc_consumers, + }, + /* supply for ab8500-vaudio, VAUDIO LDO */ + [AB8505_LDO_AUDIO] = { + .constraints = { + .name = "V-AUD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers), + .consumer_supplies = ab8500_vaud_consumers, + }, + /* supply for v-anamic1 VAMic1-LDO */ + [AB8505_LDO_ANAMIC1] = { + .constraints = { + .name = "V-AMIC1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers), + .consumer_supplies = ab8500_vamic1_consumers, + }, + /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */ + [AB8505_LDO_ANAMIC2] = { + .constraints = { + .name = "V-AMIC2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers), + .consumer_supplies = ab8500_vamic2_consumers, + }, + /* supply for v-aux8, VAUX8 LDO */ + [AB8505_LDO_AUX8] = { + .constraints = { + .name = "V-AUX8", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux8_consumers), + .consumer_supplies = ab8505_vaux8_consumers, + }, + /* supply for v-intcore12, VINTCORE12 LDO */ + [AB8505_LDO_INTCORE] = { + .constraints = { + .name = "V-INTCORE", + .min_uV = 1250000, + .max_uV = 1350000, + .input_uV = 1800000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_DRMS, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers), + .consumer_supplies = ab8500_vintcore_consumers, + }, + /* supply for LDO USB */ + [AB8505_LDO_USB] = { + .constraints = { + .name = "V-USB", + .valid_ops_mask = REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8505_usb_consumers), + .consumer_supplies = ab8505_usb_consumers, + }, + /* supply for U8500 CSI-DSI, VANA LDO */ + [AB8505_LDO_ANA] = { + .constraints = { + .name = "V-CSI-DSI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers), + .consumer_supplies = ab8500_vana_consumers, + }, +}; + struct ab8500_regulator_platform_data ab8500_regulator_plat_data = { .reg_init = ab8500_reg_init, .num_reg_init = ARRAY_SIZE(ab8500_reg_init), @@ -478,18 +949,39 @@ struct ab8500_regulator_platform_data ab8500_regulator_plat_data = { .num_ext_regulator = ARRAY_SIZE(ab8500_ext_regulators), }; +/* Use the AB8500 init settings for AB8505 as they are the same right now */ +struct ab8500_regulator_platform_data ab8505_regulator_plat_data = { + .reg_init = ab8505_reg_init, + .num_reg_init = ARRAY_SIZE(ab8505_reg_init), + .regulator = ab8505_regulators, + .num_regulator = ARRAY_SIZE(ab8505_regulators), +}; + static void ab8500_modify_reg_init(int id, u8 mask, u8 value) { int i; - for (i = ARRAY_SIZE(ab8500_reg_init) - 1; i >= 0; i--) { - if (ab8500_reg_init[i].id == id) { - u8 initval = ab8500_reg_init[i].value; - initval = (initval & ~mask) | (value & mask); - ab8500_reg_init[i].value = initval; + if (cpu_is_u8520()) { + for (i = ARRAY_SIZE(ab8505_reg_init) - 1; i >= 0; i--) { + if (ab8505_reg_init[i].id == id) { + u8 initval = ab8505_reg_init[i].value; + initval = (initval & ~mask) | (value & mask); + ab8505_reg_init[i].value = initval; - BUG_ON(mask & ~ab8500_reg_init[i].mask); - return; + BUG_ON(mask & ~ab8505_reg_init[i].mask); + return; + } + } + } else { + for (i = ARRAY_SIZE(ab8500_reg_init) - 1; i >= 0; i--) { + if (ab8500_reg_init[i].id == id) { + u8 initval = ab8500_reg_init[i].value; + initval = (initval & ~mask) | (value & mask); + ab8500_reg_init[i].value = initval; + + BUG_ON(mask & ~ab8500_reg_init[i].mask); + return; + } } } @@ -511,6 +1003,11 @@ void mop500_regulator_init(void) regulator->constraints.state_standby.disabled = 1; } + if (cpu_is_u8520()) { + /* Vaux2 initialized to be on */ + ab8500_modify_reg_init(AB8505_VAUX12REGU, 0x0f, 0x05); + } + /* * Handle AB8500_EXT_SUPPLY2 on HREFP_V20_V50 boards (do it for * all HREFP_V20 boards) diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h index 3d4c412d0b7a..9bece38fe933 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.h +++ b/arch/arm/mach-ux500/board-mop500-regulators.h @@ -15,6 +15,7 @@ #include extern struct ab8500_regulator_platform_data ab8500_regulator_plat_data; +extern struct ab8500_regulator_platform_data ab8505_regulator_plat_data; extern struct regulator_init_data tps61052_regulator; extern struct regulator_init_data gpio_en_3v3_regulator; diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 9de3a211b0b4..1ab0f8a7c862 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -5,11 +5,15 @@ * * Authors: Sundar Iyer for ST-Ericsson * Bengt Jonsson for ST-Ericsson + * Daniel Willerud for ST-Ericsson * * AB8500 peripheral regulators * * AB8500 supports the following regulators: * VAUX1/2/3, VINTCORE, VTVOUT, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA + * + * AB8505 supports the following regulators: + * VAUX1/2/3/4/5/6, VINTCORE, VADC, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA */ #include #include @@ -92,6 +96,17 @@ static const unsigned int ldo_vaux3_voltages[] = { 2910000, }; +static const int ldo_vaux56_voltages[] = { + 1800000, + 1050000, + 1100000, + 1200000, + 1500000, + 2200000, + 2500000, + 2790000, +}; + static const unsigned int ldo_vintcore_voltages[] = { 1200000, 1225000, @@ -589,6 +604,313 @@ static struct ab8500_regulator_info }, }; +/* AB8505 regulator information */ +static struct ab8500_regulator_info + ab8505_regulator_info[AB8505_NUM_REGULATORS] = { + /* + * Variable Voltage Regulators + * name, min mV, max mV, + * update bank, reg, mask, enable val + * volt bank, reg, mask, table, table length + */ + [AB8505_LDO_AUX1] = { + .desc = { + .name = "LDO-AUX1", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX1, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1f, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8505_LDO_AUX2] = { + .desc = { + .name = "LDO-AUX2", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX2, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + .voltage_bank = 0x04, + .voltage_reg = 0x20, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8505_LDO_AUX3] = { + .desc = { + .name = "LDO-AUX3", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX3, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x0a, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x21, + .voltage_mask = 0x07, + .voltages = ldo_vaux3_voltages, + .voltages_len = ARRAY_SIZE(ldo_vaux3_voltages), + }, + [AB8505_LDO_AUX4] = { + .desc = { + .name = "LDO-AUX4", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_AUX4, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .load_lp_uA = 5000, + /* values for Vaux4Regu register */ + .update_bank = 0x04, + .update_reg = 0x2e, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + /* values for Vaux4SEL register */ + .voltage_bank = 0x04, + .voltage_reg = 0x2f, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8505_LDO_AUX5] = { + .desc = { + .name = "LDO-AUX5", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX5, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux56_voltages), + }, + .min_uV = 1050000, + .max_uV = 2790000, + .load_lp_uA = 2000, + /* values for CtrlVaux5 register */ + .update_bank = 0x01, + .update_reg = 0x55, + .update_mask = 0x08, + .update_val = 0x00, + .update_val_idle = 0x01, + .update_val_normal = 0x00, + .voltage_bank = 0x01, + .voltage_reg = 0x55, + .voltage_mask = 0x07, + .voltages = ldo_vaux56_voltages, + .voltages_len = ARRAY_SIZE(ldo_vaux56_voltages), + }, + [AB8505_LDO_AUX6] = { + .desc = { + .name = "LDO-AUX6", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX6, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux56_voltages), + }, + .min_uV = 1050000, + .max_uV = 2790000, + .load_lp_uA = 2000, + /* values for CtrlVaux6 register */ + .update_bank = 0x01, + .update_reg = 0x56, + .update_mask = 0x08, + .update_val = 0x00, + .update_val_idle = 0x01, + .update_val_normal = 0x00, + .voltage_bank = 0x01, + .voltage_reg = 0x56, + .voltage_mask = 0x07, + .voltages = ldo_vaux56_voltages, + .voltages_len = ARRAY_SIZE(ldo_vaux56_voltages), + }, + [AB8505_LDO_INTCORE] = { + .desc = { + .name = "LDO-INTCORE", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_INTCORE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .load_lp_uA = 5000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x44, + .update_val = 0x04, + .update_val_idle = 0x44, + .update_val_normal = 0x04, + .voltage_bank = 0x03, + .voltage_reg = 0x80, + .voltage_mask = 0x38, + .voltages = ldo_vintcore_voltages, + .voltages_len = ARRAY_SIZE(ldo_vintcore_voltages), + .voltage_shift = 3, + }, + + /* + * Fixed Voltage Regulators + * name, fixed mV, + * update bank, reg, mask, enable val + */ + [AB8505_LDO_ADC] = { + .desc = { + .name = "LDO-ADC", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_ADC, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .delay = 10000, + .fixed_uV = 2000000, + .load_lp_uA = 1000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x82, + .update_val = 0x02, + .update_val_idle = 0x82, + .update_val_normal = 0x02, + }, + [AB8505_LDO_USB] = { + .desc = { + .name = "LDO-USB", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_USB, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 3300000, + .update_bank = 0x03, + .update_reg = 0x82, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + }, + [AB8505_LDO_AUDIO] = { + .desc = { + .name = "LDO-AUDIO", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUDIO, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2000000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x02, + .update_val = 0x02, + }, + [AB8505_LDO_ANAMIC1] = { + .desc = { + .name = "LDO-ANAMIC1", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC1, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2050000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x08, + .update_val = 0x08, + }, + [AB8505_LDO_ANAMIC2] = { + .desc = { + .name = "LDO-ANAMIC2", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC2, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2050000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x10, + .update_val = 0x10, + }, + [AB8505_LDO_AUX8] = { + .desc = { + .name = "LDO-AUX8", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8505_LDO_AUX8, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1800000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x04, + .update_val = 0x04, + }, + /* + * Regulators with fixed voltage and normal/idle modes + */ + [AB8505_LDO_ANA] = { + .desc = { + .name = "LDO-ANA", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANA, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1200000, + .load_lp_uA = 1000, + .update_bank = 0x04, + .update_reg = 0x06, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + }, +}; + /* AB9540 regulator information */ static struct ab8500_regulator_info ab9540_regulator_info[AB9540_NUM_REGULATORS] = { @@ -1031,6 +1353,276 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), }; +/* AB8505 register init */ +static struct ab8500_reg_init ab8505_reg_init[] = { + /* + * 0x03, VarmRequestCtrl + * 0x0c, VsmpsCRequestCtrl + * 0x30, VsmpsARequestCtrl + * 0xc0, VsmpsBRequestCtrl + */ + REG_INIT(AB8505_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), + /* + * 0x03, VsafeRequestCtrl + * 0x0c, VpllRequestCtrl + * 0x30, VanaRequestCtrl + */ + REG_INIT(AB8505_REGUREQUESTCTRL2, 0x03, 0x04, 0x3f), + /* + * 0x30, Vaux1RequestCtrl + * 0xc0, Vaux2RequestCtrl + */ + REG_INIT(AB8505_REGUREQUESTCTRL3, 0x03, 0x05, 0xf0), + /* + * 0x03, Vaux3RequestCtrl + * 0x04, SwHPReq + */ + REG_INIT(AB8505_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), + /* + * 0x01, VsmpsASysClkReq1HPValid + * 0x02, VsmpsBSysClkReq1HPValid + * 0x04, VsafeSysClkReq1HPValid + * 0x08, VanaSysClkReq1HPValid + * 0x10, VpllSysClkReq1HPValid + * 0x20, Vaux1SysClkReq1HPValid + * 0x40, Vaux2SysClkReq1HPValid + * 0x80, Vaux3SysClkReq1HPValid + */ + REG_INIT(AB8505_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), + /* + * 0x01, VsmpsCSysClkReq1HPValid + * 0x02, VarmSysClkReq1HPValid + * 0x04, VbbSysClkReq1HPValid + * 0x08, VsmpsMSysClkReq1HPValid + */ + REG_INIT(AB8505_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x0f), + /* + * 0x01, VsmpsAHwHPReq1Valid + * 0x02, VsmpsBHwHPReq1Valid + * 0x04, VsafeHwHPReq1Valid + * 0x08, VanaHwHPReq1Valid + * 0x10, VpllHwHPReq1Valid + * 0x20, Vaux1HwHPReq1Valid + * 0x40, Vaux2HwHPReq1Valid + * 0x80, Vaux3HwHPReq1Valid + */ + REG_INIT(AB8505_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), + /* + * 0x08, VsmpsMHwHPReq1Valid + */ + REG_INIT(AB8505_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x08), + /* + * 0x01, VsmpsAHwHPReq2Valid + * 0x02, VsmpsBHwHPReq2Valid + * 0x04, VsafeHwHPReq2Valid + * 0x08, VanaHwHPReq2Valid + * 0x10, VpllHwHPReq2Valid + * 0x20, Vaux1HwHPReq2Valid + * 0x40, Vaux2HwHPReq2Valid + * 0x80, Vaux3HwHPReq2Valid + */ + REG_INIT(AB8505_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), + /* + * 0x08, VsmpsMHwHPReq2Valid + */ + REG_INIT(AB8505_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x08), + /* + * 0x01, VsmpsCSwHPReqValid + * 0x02, VarmSwHPReqValid + * 0x04, VsmpsASwHPReqValid + * 0x08, VsmpsBSwHPReqValid + * 0x10, VsafeSwHPReqValid + * 0x20, VanaSwHPReqValid + * 0x40, VpllSwHPReqValid + * 0x80, Vaux1SwHPReqValid + */ + REG_INIT(AB8505_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), + /* + * 0x01, Vaux2SwHPReqValid + * 0x02, Vaux3SwHPReqValid + * 0x20, VsmpsMSwHPReqValid + */ + REG_INIT(AB8505_REGUSWHPREQVALID2, 0x03, 0x0e, 0x23), + /* + * 0x02, SysClkReq2Valid1 + * 0x04, SysClkReq3Valid1 + * 0x08, SysClkReq4Valid1 + */ + REG_INIT(AB8505_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0x0e), + /* + * 0x02, SysClkReq2Valid2 + * 0x04, SysClkReq3Valid2 + * 0x08, SysClkReq4Valid2 + */ + REG_INIT(AB8505_REGUSYSCLKREQVALID2, 0x03, 0x10, 0x0e), + /* + * 0x01, Vaux4SwHPReqValid + * 0x02, Vaux4HwHPReq2Valid + * 0x04, Vaux4HwHPReq1Valid + * 0x08, Vaux4SysClkReq1HPValid + */ + REG_INIT(AB8505_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f), + /* + * 0x02, VadcEna + * 0x04, VintCore12Ena + * 0x38, VintCore12Sel + * 0x40, VintCore12LP + * 0x80, VadcLP + */ + REG_INIT(AB8505_REGUMISC1, 0x03, 0x80, 0xfe), + /* + * 0x02, VaudioEna + * 0x04, VdmicEna + * 0x08, Vamic1Ena + * 0x10, Vamic2Ena + */ + REG_INIT(AB8505_VAUDIOSUPPLY, 0x03, 0x83, 0x1e), + /* + * 0x01, Vamic1_dzout + * 0x02, Vamic2_dzout + */ + REG_INIT(AB8505_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), + /* + * 0x03, VsmpsARegu + * 0x0c, VsmpsASelCtrl + * 0x10, VsmpsAAutoMode + * 0x20, VsmpsAPWMMode + */ + REG_INIT(AB8505_VSMPSAREGU, 0x04, 0x03, 0x3f), + /* + * 0x03, VsmpsBRegu + * 0x0c, VsmpsBSelCtrl + * 0x10, VsmpsBAutoMode + * 0x20, VsmpsBPWMMode + */ + REG_INIT(AB8505_VSMPSBREGU, 0x04, 0x04, 0x3f), + /* + * 0x03, VsafeRegu + * 0x0c, VsafeSelCtrl + * 0x10, VsafeAutoMode + * 0x20, VsafePWMMode + */ + REG_INIT(AB8505_VSAFEREGU, 0x04, 0x05, 0x3f), + /* + * 0x03, VpllRegu (NOTE! PRCMU register bits) + * 0x0c, VanaRegu + */ + REG_INIT(AB8505_VPLLVANAREGU, 0x04, 0x06, 0x0f), + /* + * 0x03, VextSupply1Regu + * 0x0c, VextSupply2Regu + * 0x30, VextSupply3Regu + * 0x40, ExtSupply2Bypass + * 0x80, ExtSupply3Bypass + */ + REG_INIT(AB8505_EXTSUPPLYREGU, 0x04, 0x08, 0xff), + /* + * 0x03, Vaux1Regu + * 0x0c, Vaux2Regu + */ + REG_INIT(AB8505_VAUX12REGU, 0x04, 0x09, 0x0f), + /* + * 0x0f, Vaux3Regu + */ + REG_INIT(AB8505_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), + /* + * 0x3f, VsmpsASel1 + */ + REG_INIT(AB8505_VSMPSASEL1, 0x04, 0x13, 0x3f), + /* + * 0x3f, VsmpsASel2 + */ + REG_INIT(AB8505_VSMPSASEL2, 0x04, 0x14, 0x3f), + /* + * 0x3f, VsmpsASel3 + */ + REG_INIT(AB8505_VSMPSASEL3, 0x04, 0x15, 0x3f), + /* + * 0x3f, VsmpsBSel1 + */ + REG_INIT(AB8505_VSMPSBSEL1, 0x04, 0x17, 0x3f), + /* + * 0x3f, VsmpsBSel2 + */ + REG_INIT(AB8505_VSMPSBSEL2, 0x04, 0x18, 0x3f), + /* + * 0x3f, VsmpsBSel3 + */ + REG_INIT(AB8505_VSMPSBSEL3, 0x04, 0x19, 0x3f), + /* + * 0x7f, VsafeSel1 + */ + REG_INIT(AB8505_VSAFESEL1, 0x04, 0x1b, 0x7f), + /* + * 0x3f, VsafeSel2 + */ + REG_INIT(AB8505_VSAFESEL2, 0x04, 0x1c, 0x7f), + /* + * 0x3f, VsafeSel3 + */ + REG_INIT(AB8505_VSAFESEL3, 0x04, 0x1d, 0x7f), + /* + * 0x0f, Vaux1Sel + */ + REG_INIT(AB8505_VAUX1SEL, 0x04, 0x1f, 0x0f), + /* + * 0x0f, Vaux2Sel + */ + REG_INIT(AB8505_VAUX2SEL, 0x04, 0x20, 0x0f), + /* + * 0x07, Vaux3Sel + * 0x30, VRF1Sel + */ + REG_INIT(AB8505_VRF1VAUX3SEL, 0x04, 0x21, 0x37), + /* + * 0x03, Vaux4RequestCtrl + */ + REG_INIT(AB8505_VAUX4REQCTRL, 0x04, 0x2d, 0x03), + /* + * 0x03, Vaux4Regu + */ + REG_INIT(AB8505_VAUX4REGU, 0x04, 0x2e, 0x03), + /* + * 0x0f, Vaux4Sel + */ + REG_INIT(AB8505_VAUX4SEL, 0x04, 0x2f, 0x0f), + /* + * 0x04, Vaux1Disch + * 0x08, Vaux2Disch + * 0x10, Vaux3Disch + * 0x20, Vintcore12Disch + * 0x40, VTVoutDisch + * 0x80, VaudioDisch + */ + REG_INIT(AB8505_REGUCTRLDISCH, 0x04, 0x43, 0xfc), + /* + * 0x02, VanaDisch + * 0x04, VdmicPullDownEna + * 0x10, VdmicDisch + */ + REG_INIT(AB8505_REGUCTRLDISCH2, 0x04, 0x44, 0x16), + /* + * 0x01, Vaux4Disch + */ + REG_INIT(AB8505_REGUCTRLDISCH3, 0x04, 0x48, 0x01), + /* + * 0x07, Vaux5Sel + * 0x08, Vaux5LP + * 0x10, Vaux5Ena + * 0x20, Vaux5Disch + * 0x40, Vaux5DisSfst + * 0x80, Vaux5DisPulld + */ + REG_INIT(AB8505_CTRLVAUX5, 0x01, 0x55, 0xff), + /* + * 0x07, Vaux6Sel + * 0x08, Vaux6LP + * 0x10, Vaux6Ena + * 0x80, Vaux6DisPulld + */ + REG_INIT(AB8505_CTRLVAUX6, 0x01, 0x56, 0x9f), +}; + /* AB9540 register init */ static struct ab8500_reg_init ab9540_reg_init[] = { /* @@ -1396,6 +1988,22 @@ static struct of_regulator_match ab8500_regulator_match[] = { { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8500_LDO_ANA, }, }; +static struct of_regulator_match ab8505_regulator_match[] = { + { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8505_LDO_AUX1, }, + { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8505_LDO_AUX2, }, + { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8505_LDO_AUX3, }, + { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB8505_LDO_AUX4, }, + { .name = "ab8500_ldo_aux5", .driver_data = (void *) AB8505_LDO_AUX5, }, + { .name = "ab8500_ldo_aux6", .driver_data = (void *) AB8505_LDO_AUX6, }, + { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8505_LDO_INTCORE, }, + { .name = "ab8500_ldo_adc", .driver_data = (void *) AB8505_LDO_ADC, }, + { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8505_LDO_AUDIO, }, + { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8505_LDO_ANAMIC1, }, + { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8505_LDO_ANAMIC2, }, + { .name = "ab8500_ldo_aux8", .driver_data = (void *) AB8505_LDO_AUX8, }, + { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8505_LDO_ANA, }, +}; + static struct of_regulator_match ab9540_regulator_match[] = { { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB9540_LDO_AUX1, }, { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB9540_LDO_AUX2, }, @@ -1450,6 +2058,11 @@ static int ab8500_regulator_probe(struct platform_device *pdev) reg_init_size = AB9540_NUM_REGULATOR_REGISTERS; match = ab9540_regulator_match; match_size = ARRAY_SIZE(ab9540_regulator_match) + } else if (is_ab8505(ab8500)) { + regulator_info = ab8505_regulator_info; + regulator_info_size = ARRAY_SIZE(ab8505_regulator_info); + reg_init = ab8505_reg_init; + reg_init_size = AB8505_NUM_REGULATOR_REGISTERS; } else { regulator_info = ab8500_regulator_info; regulator_info_size = ARRAY_SIZE(ab8500_regulator_info); @@ -1543,6 +2156,9 @@ static int ab8500_regulator_remove(struct platform_device *pdev) if (is_ab9540(ab8500)) { regulator_info = ab9540_regulator_info; regulator_info_size = ARRAY_SIZE(ab9540_regulator_info); + } else if (is_ab8505(ab8500)) { + regulator_info = ab8505_regulator_info; + regulator_info_size = ARRAY_SIZE(ab8505_regulator_info); } else { regulator_info = ab8500_regulator_info; regulator_info_size = ARRAY_SIZE(ab8500_regulator_info); @@ -1601,5 +2217,6 @@ module_exit(ab8500_regulator_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Sundar Iyer "); MODULE_AUTHOR("Bengt Jonsson "); +MODULE_AUTHOR("Daniel Willerud "); MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC"); MODULE_ALIAS("platform:ab8500-regulator"); diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 592a3f3994c0..9a7cf97e5040 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -5,6 +5,7 @@ * * Authors: Sundar Iyer for ST-Ericsson * Bengt Jonsson for ST-Ericsson + * Daniel Willerud for ST-Ericsson */ #ifndef __LINUX_MFD_AB8500_REGULATOR_H @@ -27,7 +28,28 @@ enum ab8500_regulator_id { AB8500_NUM_REGULATORS, }; -/* AB9450 regulators */ +/* AB8505 regulators */ +enum ab8505_regulator_id { + AB8505_LDO_AUX1, + AB8505_LDO_AUX2, + AB8505_LDO_AUX3, + AB8505_LDO_AUX4, + AB8505_LDO_AUX5, + AB8505_LDO_AUX6, + AB8505_LDO_INTCORE, + AB8505_LDO_ADC, + AB8505_LDO_USB, + AB8505_LDO_AUDIO, + AB8505_LDO_ANAMIC1, + AB8505_LDO_ANAMIC2, + AB8505_LDO_AUX8, + AB8505_LDO_ANA, + AB8505_SYSCLKREQ_2, + AB8505_SYSCLKREQ_4, + AB8505_NUM_REGULATORS, +}; + +/* AB9540 regulators */ enum ab9540_regulator_id { AB9540_LDO_AUX1, AB9540_LDO_AUX2, @@ -46,7 +68,7 @@ enum ab9540_regulator_id { AB9540_NUM_REGULATORS, }; -/* AB8500 and AB9540 register initialization */ +/* AB8500, AB8505, and AB9540 register initialization */ struct ab8500_regulator_reg_init { int id; u8 mask; @@ -92,6 +114,55 @@ enum ab8500_regulator_reg { AB8500_NUM_REGULATOR_REGISTERS, }; +/* AB8505 registers */ +enum ab8505_regulator_reg { + AB8505_REGUREQUESTCTRL1, + AB8505_REGUREQUESTCTRL2, + AB8505_REGUREQUESTCTRL3, + AB8505_REGUREQUESTCTRL4, + AB8505_REGUSYSCLKREQ1HPVALID1, + AB8505_REGUSYSCLKREQ1HPVALID2, + AB8505_REGUHWHPREQ1VALID1, + AB8505_REGUHWHPREQ1VALID2, + AB8505_REGUHWHPREQ2VALID1, + AB8505_REGUHWHPREQ2VALID2, + AB8505_REGUSWHPREQVALID1, + AB8505_REGUSWHPREQVALID2, + AB8505_REGUSYSCLKREQVALID1, + AB8505_REGUSYSCLKREQVALID2, + AB8505_REGUVAUX4REQVALID, + AB8505_REGUMISC1, + AB8505_VAUDIOSUPPLY, + AB8505_REGUCTRL1VAMIC, + AB8505_VSMPSAREGU, + AB8505_VSMPSBREGU, + AB8505_VSAFEREGU, /* NOTE! PRCMU register */ + AB8505_VPLLVANAREGU, + AB8505_EXTSUPPLYREGU, + AB8505_VAUX12REGU, + AB8505_VRF1VAUX3REGU, + AB8505_VSMPSASEL1, + AB8505_VSMPSASEL2, + AB8505_VSMPSASEL3, + AB8505_VSMPSBSEL1, + AB8505_VSMPSBSEL2, + AB8505_VSMPSBSEL3, + AB8505_VSAFESEL1, /* NOTE! PRCMU register */ + AB8505_VSAFESEL2, /* NOTE! PRCMU register */ + AB8505_VSAFESEL3, /* NOTE! PRCMU register */ + AB8505_VAUX1SEL, + AB8505_VAUX2SEL, + AB8505_VRF1VAUX3SEL, + AB8505_VAUX4REQCTRL, + AB8505_VAUX4REGU, + AB8505_VAUX4SEL, + AB8505_REGUCTRLDISCH, + AB8505_REGUCTRLDISCH2, + AB8505_REGUCTRLDISCH3, + AB8505_CTRLVAUX5, + AB8505_CTRLVAUX6, + AB8505_NUM_REGULATOR_REGISTERS, +}; /* AB9540 registers */ enum ab9540_regulator_reg { -- cgit v1.2.3 From ae0a9a3efce22e77b5f0f2b266646431f492f7ed Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 28 Mar 2013 16:11:16 +0000 Subject: regulator: ab8500: Add support for the ab8540 To obtain full AB8540 regulator support, the AB8500 regulator driver first needs to know its register layout and their initialisation values for each. That information is provided via a couple of large data structures which we provide here. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 686 ++++++++++++++++++++++++++++++++++++++- include/linux/regulator/ab8500.h | 86 +++++ 2 files changed, 764 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 1ab0f8a7c862..ec609ab747ae 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -107,6 +107,18 @@ static const int ldo_vaux56_voltages[] = { 2790000, }; +static const int ldo_vaux3_ab8540_voltages[] = { + 1200000, + 1500000, + 1800000, + 2100000, + 2500000, + 2750000, + 2790000, + 2910000, + 3050000, +}; + static const unsigned int ldo_vintcore_voltages[] = { 1200000, 1225000, @@ -117,6 +129,17 @@ static const unsigned int ldo_vintcore_voltages[] = { 1350000, }; +static const int ldo_sdio_voltages[] = { + 1160000, + 1050000, + 1100000, + 1500000, + 1800000, + 2200000, + 2910000, + 3050000, +}; + static int ab8500_regulator_enable(struct regulator_dev *rdev) { int ret; @@ -726,10 +749,10 @@ static struct ab8500_regulator_info /* values for CtrlVaux5 register */ .update_bank = 0x01, .update_reg = 0x55, - .update_mask = 0x08, - .update_val = 0x00, - .update_val_idle = 0x01, - .update_val_normal = 0x00, + .update_mask = 0x18, + .update_val = 0x10, + .update_val_idle = 0x18, + .update_val_normal = 0x10, .voltage_bank = 0x01, .voltage_reg = 0x55, .voltage_mask = 0x07, @@ -751,10 +774,10 @@ static struct ab8500_regulator_info /* values for CtrlVaux6 register */ .update_bank = 0x01, .update_reg = 0x56, - .update_mask = 0x08, - .update_val = 0x00, - .update_val_idle = 0x01, - .update_val_normal = 0x00, + .update_mask = 0x18, + .update_val = 0x10, + .update_val_idle = 0x18, + .update_val_normal = 0x10, .voltage_bank = 0x01, .voltage_reg = 0x56, .voltage_mask = 0x07, @@ -1169,6 +1192,255 @@ static struct ab8500_regulator_info }, }; +/* AB8540 regulator information */ +static struct ab8500_regulator_info + ab8540_regulator_info[AB8540_NUM_REGULATORS] = { + /* + * Variable Voltage Regulators + * name, min mV, max mV, + * update bank, reg, mask, enable val + * volt bank, reg, mask, table, table length + */ + [AB8540_LDO_AUX1] = { + .desc = { + .name = "LDO-AUX1", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX1, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1f, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8540_LDO_AUX2] = { + .desc = { + .name = "LDO-AUX2", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX2, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + .voltage_bank = 0x04, + .voltage_reg = 0x20, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8540_LDO_AUX3] = { + .desc = { + .name = "LDO-AUX3", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX3, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux3_ab8540_voltages), + }, + .load_lp_uA = 5000, + .update_bank = 0x04, + .update_reg = 0x0a, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x21, + .voltage_mask = 0x07, + .voltages = ldo_vaux3_ab8540_voltages, + .voltages_len = ARRAY_SIZE(ldo_vaux3_ab8540_voltages), + }, + [AB8540_LDO_AUX4] = { + .desc = { + .name = "LDO-AUX4", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB9540_LDO_AUX4, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .load_lp_uA = 5000, + /* values for Vaux4Regu register */ + .update_bank = 0x04, + .update_reg = 0x2e, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + /* values for Vaux4SEL register */ + .voltage_bank = 0x04, + .voltage_reg = 0x2f, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8540_LDO_INTCORE] = { + .desc = { + .name = "LDO-INTCORE", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_INTCORE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), + }, + .load_lp_uA = 5000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x44, + .update_val = 0x44, + .update_val_idle = 0x44, + .update_val_normal = 0x04, + .voltage_bank = 0x03, + .voltage_reg = 0x80, + .voltage_mask = 0x38, + .voltages = ldo_vintcore_voltages, + .voltages_len = ARRAY_SIZE(ldo_vintcore_voltages), + .voltage_shift = 3, + }, + + /* + * Fixed Voltage Regulators + * name, fixed mV, + * update bank, reg, mask, enable val + */ + [AB8540_LDO_TVOUT] = { + .desc = { + .name = "LDO-TVOUT", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_TVOUT, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .delay = 10000, + .load_lp_uA = 1000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x82, + .update_val = 0x02, + .update_val_idle = 0x82, + .update_val_normal = 0x02, + }, + [AB8540_LDO_AUDIO] = { + .desc = { + .name = "LDO-AUDIO", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUDIO, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x02, + .update_val = 0x02, + }, + [AB8540_LDO_ANAMIC1] = { + .desc = { + .name = "LDO-ANAMIC1", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC1, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x08, + .update_val = 0x08, + }, + [AB8540_LDO_ANAMIC2] = { + .desc = { + .name = "LDO-ANAMIC2", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC2, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x10, + .update_val = 0x10, + }, + [AB8540_LDO_DMIC] = { + .desc = { + .name = "LDO-DMIC", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_DMIC, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x04, + .update_val = 0x04, + }, + + /* + * Regulators with fixed voltage and normal/idle modes + */ + [AB8540_LDO_ANA] = { + .desc = { + .name = "LDO-ANA", + .ops = &ab8500_regulator_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANA, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .load_lp_uA = 1000, + .update_bank = 0x04, + .update_reg = 0x06, + .update_mask = 0x0c, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, + }, + [AB8540_LDO_SDIO] = { + .desc = { + .name = "LDO-SDIO", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_SDIO, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_sdio_voltages), + }, + .min_uV = 1050000, + .max_uV = 3050000, + .load_lp_uA = 5000, + .update_bank = 0x03, + .update_reg = 0x88, + .update_mask = 0x30, + .update_val = 0x10, + .update_val_idle = 0x30, + .update_val_normal = 0x10, + .voltage_bank = 0x03, + .voltage_reg = 0x88, + .voltage_mask = 0x07, + .voltages = ldo_sdio_voltages, + .voltages_len = ARRAY_SIZE(ldo_sdio_voltages), + }, +}; + struct ab8500_reg_init { u8 bank; u8 addr; @@ -1898,6 +2170,384 @@ static struct ab8500_reg_init ab9540_reg_init[] = { REG_INIT(AB9540_REGUCTRLDISCH3, 0x04, 0x48, 0x01), }; +/* AB8540 register init */ +static struct ab8500_reg_init ab8540_reg_init[] = { + /* + * 0x01, VSimSycClkReq1Valid + * 0x02, VSimSycClkReq2Valid + * 0x04, VSimSycClkReq3Valid + * 0x08, VSimSycClkReq4Valid + * 0x10, VSimSycClkReq5Valid + * 0x20, VSimSycClkReq6Valid + * 0x40, VSimSycClkReq7Valid + * 0x80, VSimSycClkReq8Valid + */ + REG_INIT(AB8540_VSIMSYSCLKCTRL, 0x02, 0x33, 0xff), + /* + * 0x03, VarmRequestCtrl + * 0x0c, VapeRequestCtrl + * 0x30, Vsmps1RequestCtrl + * 0xc0, Vsmps2RequestCtrl + */ + REG_INIT(AB8540_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), + /* + * 0x03, Vsmps3RequestCtrl + * 0x0c, VpllRequestCtrl + * 0x30, VanaRequestCtrl + * 0xc0, VextSupply1RequestCtrl + */ + REG_INIT(AB8540_REGUREQUESTCTRL2, 0x03, 0x04, 0xff), + /* + * 0x03, VextSupply2RequestCtrl + * 0x0c, VextSupply3RequestCtrl + * 0x30, Vaux1RequestCtrl + * 0xc0, Vaux2RequestCtrl + */ + REG_INIT(AB8540_REGUREQUESTCTRL3, 0x03, 0x05, 0xff), + /* + * 0x03, Vaux3RequestCtrl + * 0x04, SwHPReq + */ + REG_INIT(AB8540_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), + /* + * 0x01, Vsmps1SysClkReq1HPValid + * 0x02, Vsmps2SysClkReq1HPValid + * 0x04, Vsmps3SysClkReq1HPValid + * 0x08, VanaSysClkReq1HPValid + * 0x10, VpllSysClkReq1HPValid + * 0x20, Vaux1SysClkReq1HPValid + * 0x40, Vaux2SysClkReq1HPValid + * 0x80, Vaux3SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), + /* + * 0x01, VapeSysClkReq1HPValid + * 0x02, VarmSysClkReq1HPValid + * 0x04, VbbSysClkReq1HPValid + * 0x10, VextSupply1SysClkReq1HPValid + * 0x20, VextSupply2SysClkReq1HPValid + * 0x40, VextSupply3SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x77), + /* + * 0x01, Vsmps1HwHPReq1Valid + * 0x02, Vsmps2HwHPReq1Valid + * 0x04, Vsmps3HwHPReq1Valid + * 0x08, VanaHwHPReq1Valid + * 0x10, VpllHwHPReq1Valid + * 0x20, Vaux1HwHPReq1Valid + * 0x40, Vaux2HwHPReq1Valid + * 0x80, Vaux3HwHPReq1Valid + */ + REG_INIT(AB8540_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), + /* + * 0x01, VextSupply1HwHPReq1Valid + * 0x02, VextSupply2HwHPReq1Valid + * 0x04, VextSupply3HwHPReq1Valid + */ + REG_INIT(AB8540_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07), + /* + * 0x01, Vsmps1HwHPReq2Valid + * 0x02, Vsmps2HwHPReq2Valid + * 0x03, Vsmps3HwHPReq2Valid + * 0x08, VanaHwHPReq2Valid + * 0x10, VpllHwHPReq2Valid + * 0x20, Vaux1HwHPReq2Valid + * 0x40, Vaux2HwHPReq2Valid + * 0x80, Vaux3HwHPReq2Valid + */ + REG_INIT(AB8540_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), + /* + * 0x01, VextSupply1HwHPReq2Valid + * 0x02, VextSupply2HwHPReq2Valid + * 0x04, VextSupply3HwHPReq2Valid + */ + REG_INIT(AB8540_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07), + /* + * 0x01, VapeSwHPReqValid + * 0x02, VarmSwHPReqValid + * 0x04, Vsmps1SwHPReqValid + * 0x08, Vsmps2SwHPReqValid + * 0x10, Vsmps3SwHPReqValid + * 0x20, VanaSwHPReqValid + * 0x40, VpllSwHPReqValid + * 0x80, Vaux1SwHPReqValid + */ + REG_INIT(AB8540_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), + /* + * 0x01, Vaux2SwHPReqValid + * 0x02, Vaux3SwHPReqValid + * 0x04, VextSupply1SwHPReqValid + * 0x08, VextSupply2SwHPReqValid + * 0x10, VextSupply3SwHPReqValid + */ + REG_INIT(AB8540_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f), + /* + * 0x02, SysClkReq2Valid1 + * ... + * 0x80, SysClkReq8Valid1 + */ + REG_INIT(AB8540_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xff), + /* + * 0x02, SysClkReq2Valid2 + * ... + * 0x80, SysClkReq8Valid2 + */ + REG_INIT(AB8540_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xff), + /* + * 0x01, Vaux4SwHPReqValid + * 0x02, Vaux4HwHPReq2Valid + * 0x04, Vaux4HwHPReq1Valid + * 0x08, Vaux4SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f), + /* + * 0x01, Vaux5SwHPReqValid + * 0x02, Vaux5HwHPReq2Valid + * 0x04, Vaux5HwHPReq1Valid + * 0x08, Vaux5SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVAUX5REQVALID, 0x03, 0x12, 0x0f), + /* + * 0x01, Vaux6SwHPReqValid + * 0x02, Vaux6HwHPReq2Valid + * 0x04, Vaux6HwHPReq1Valid + * 0x08, Vaux6SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVAUX6REQVALID, 0x03, 0x13, 0x0f), + /* + * 0x01, VclkbSwHPReqValid + * 0x02, VclkbHwHPReq2Valid + * 0x04, VclkbHwHPReq1Valid + * 0x08, VclkbSysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVCLKBREQVALID, 0x03, 0x14, 0x0f), + /* + * 0x01, Vrf1SwHPReqValid + * 0x02, Vrf1HwHPReq2Valid + * 0x04, Vrf1HwHPReq1Valid + * 0x08, Vrf1SysClkReq1HPValid + */ + REG_INIT(AB8540_REGUVRF1REQVALID, 0x03, 0x15, 0x0f), + /* + * 0x02, VTVoutEna + * 0x04, Vintcore12Ena + * 0x38, Vintcore12Sel + * 0x40, Vintcore12LP + * 0x80, VTVoutLP + */ + REG_INIT(AB8540_REGUMISC1, 0x03, 0x80, 0xfe), + /* + * 0x02, VaudioEna + * 0x04, VdmicEna + * 0x08, Vamic1Ena + * 0x10, Vamic2Ena + * 0x20, Vamic12LP + * 0xC0, VdmicSel + */ + REG_INIT(AB8540_VAUDIOSUPPLY, 0x03, 0x83, 0xfe), + /* + * 0x01, Vamic1_dzout + * 0x02, Vamic2_dzout + */ + REG_INIT(AB8540_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), + /* + * 0x07, VHSICSel + * 0x08, VHSICOffState + * 0x10, VHSIEna + * 0x20, VHSICLP + */ + REG_INIT(AB8540_VHSIC, 0x03, 0x87, 0x3f), + /* + * 0x07, VSDIOSel + * 0x08, VSDIOOffState + * 0x10, VSDIOEna + * 0x20, VSDIOLP + */ + REG_INIT(AB8540_VSDIO, 0x03, 0x88, 0x3f), + /* + * 0x03, Vsmps1Regu + * 0x0c, Vsmps1SelCtrl + * 0x10, Vsmps1AutoMode + * 0x20, Vsmps1PWMMode + */ + REG_INIT(AB8540_VSMPS1REGU, 0x04, 0x03, 0x3f), + /* + * 0x03, Vsmps2Regu + * 0x0c, Vsmps2SelCtrl + * 0x10, Vsmps2AutoMode + * 0x20, Vsmps2PWMMode + */ + REG_INIT(AB8540_VSMPS2REGU, 0x04, 0x04, 0x3f), + /* + * 0x03, Vsmps3Regu + * 0x0c, Vsmps3SelCtrl + * 0x10, Vsmps3AutoMode + * 0x20, Vsmps3PWMMode + * NOTE! PRCMU register + */ + REG_INIT(AB8540_VSMPS3REGU, 0x04, 0x05, 0x0f), + /* + * 0x03, VpllRegu + * 0x0c, VanaRegu + */ + REG_INIT(AB8540_VPLLVANAREGU, 0x04, 0x06, 0x0f), + /* + * 0x03, VextSupply1Regu + * 0x0c, VextSupply2Regu + * 0x30, VextSupply3Regu + * 0x40, ExtSupply2Bypass + * 0x80, ExtSupply3Bypass + */ + REG_INIT(AB8540_EXTSUPPLYREGU, 0x04, 0x08, 0xff), + /* + * 0x03, Vaux1Regu + * 0x0c, Vaux2Regu + */ + REG_INIT(AB8540_VAUX12REGU, 0x04, 0x09, 0x0f), + /* + * 0x0c, VRF1Regu + * 0x03, Vaux3Regu + */ + REG_INIT(AB8540_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), + /* + * 0x3f, Vsmps1Sel1 + */ + REG_INIT(AB8540_VSMPS1SEL1, 0x04, 0x13, 0x3f), + /* + * 0x3f, Vsmps1Sel2 + */ + REG_INIT(AB8540_VSMPS1SEL2, 0x04, 0x14, 0x3f), + /* + * 0x3f, Vsmps1Sel3 + */ + REG_INIT(AB8540_VSMPS1SEL3, 0x04, 0x15, 0x3f), + /* + * 0x3f, Vsmps2Sel1 + */ + REG_INIT(AB8540_VSMPS2SEL1, 0x04, 0x17, 0x3f), + /* + * 0x3f, Vsmps2Sel2 + */ + REG_INIT(AB8540_VSMPS2SEL2, 0x04, 0x18, 0x3f), + /* + * 0x3f, Vsmps2Sel3 + */ + REG_INIT(AB8540_VSMPS2SEL3, 0x04, 0x19, 0x3f), + /* + * 0x7f, Vsmps3Sel1 + * NOTE! PRCMU register + */ + REG_INIT(AB8540_VSMPS3SEL1, 0x04, 0x1b, 0x7f), + /* + * 0x7f, Vsmps3Sel2 + * NOTE! PRCMU register + */ + REG_INIT(AB8540_VSMPS3SEL2, 0x04, 0x1c, 0x7f), + /* + * 0x0f, Vaux1Sel + */ + REG_INIT(AB8540_VAUX1SEL, 0x04, 0x1f, 0x0f), + /* + * 0x0f, Vaux2Sel + */ + REG_INIT(AB8540_VAUX2SEL, 0x04, 0x20, 0x0f), + /* + * 0x07, Vaux3Sel + * 0x70, Vrf1Sel + */ + REG_INIT(AB8540_VRF1VAUX3SEL, 0x04, 0x21, 0x77), + /* + * 0x01, VextSupply12LP + */ + REG_INIT(AB8540_REGUCTRL2SPARE, 0x04, 0x22, 0x01), + /* + * 0x07, Vanasel + * 0x30, Vpllsel + */ + REG_INIT(AB8540_VANAVPLLSEL, 0x04, 0x29, 0x37), + /* + * 0x03, Vaux4RequestCtrl + */ + REG_INIT(AB8540_VAUX4REQCTRL, 0x04, 0x2d, 0x03), + /* + * 0x03, Vaux4Regu + */ + REG_INIT(AB8540_VAUX4REGU, 0x04, 0x2e, 0x03), + /* + * 0x0f, Vaux4Sel + */ + REG_INIT(AB8540_VAUX4SEL, 0x04, 0x2f, 0x0f), + /* + * 0x03, Vaux5RequestCtrl + */ + REG_INIT(AB8540_VAUX5REQCTRL, 0x04, 0x31, 0x03), + /* + * 0x03, Vaux5Regu + */ + REG_INIT(AB8540_VAUX5REGU, 0x04, 0x32, 0x03), + /* + * 0x3f, Vaux5Sel + */ + REG_INIT(AB8540_VAUX5SEL, 0x04, 0x33, 0x3f), + /* + * 0x03, Vaux6RequestCtrl + */ + REG_INIT(AB8540_VAUX6REQCTRL, 0x04, 0x34, 0x03), + /* + * 0x03, Vaux6Regu + */ + REG_INIT(AB8540_VAUX6REGU, 0x04, 0x35, 0x03), + /* + * 0x3f, Vaux6Sel + */ + REG_INIT(AB8540_VAUX6SEL, 0x04, 0x36, 0x3f), + /* + * 0x03, VCLKBRequestCtrl + */ + REG_INIT(AB8540_VCLKBREQCTRL, 0x04, 0x37, 0x03), + /* + * 0x03, VCLKBRegu + */ + REG_INIT(AB8540_VCLKBREGU, 0x04, 0x38, 0x03), + /* + * 0x07, VCLKBSel + */ + REG_INIT(AB8540_VCLKBSEL, 0x04, 0x39, 0x07), + /* + * 0x03, Vrf1RequestCtrl + */ + REG_INIT(AB8540_VRF1REQCTRL, 0x04, 0x3a, 0x03), + /* + * 0x01, VpllDisch + * 0x02, Vrf1Disch + * 0x04, Vaux1Disch + * 0x08, Vaux2Disch + * 0x10, Vaux3Disch + * 0x20, Vintcore12Disch + * 0x40, VTVoutDisch + * 0x80, VaudioDisch + */ + REG_INIT(AB8540_REGUCTRLDISCH, 0x04, 0x43, 0xff), + /* + * 0x02, VanaDisch + * 0x04, VdmicPullDownEna + * 0x08, VpllPullDownEna + * 0x10, VdmicDisch + */ + REG_INIT(AB8540_REGUCTRLDISCH2, 0x04, 0x44, 0x1e), + /* + * 0x01, Vaux4Disch + */ + REG_INIT(AB8540_REGUCTRLDISCH3, 0x04, 0x48, 0x01), + /* + * 0x01, Vaux5Disch + * 0x02, Vaux6Disch + * 0x04, VCLKBDisch + */ + REG_INIT(AB8540_REGUCTRLDISCH4, 0x04, 0x49, 0x07), +}; + static int ab8500_regulator_init_registers(struct platform_device *pdev, struct ab8500_reg_init *reg_init, int id, int mask, int value) @@ -2004,6 +2654,21 @@ static struct of_regulator_match ab8505_regulator_match[] = { { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8505_LDO_ANA, }, }; +static struct of_regulator_match ab8540_regulator_match[] = { + { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8540_LDO_AUX1, }, + { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8540_LDO_AUX2, }, + { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8540_LDO_AUX3, }, + { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB8540_LDO_AUX4, }, + { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8540_LDO_INTCORE, }, + { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8540_LDO_TVOUT, }, + { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8540_LDO_AUDIO, }, + { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8540_LDO_ANAMIC1, }, + { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8540_LDO_ANAMIC2, }, + { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB8540_LDO_DMIC, }, + { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8540_LDO_ANA, }, + { .name = "ab8500_ldo_sdio", .driver_data = (void *) AB8540_LDO_SDIO, }, +}; + static struct of_regulator_match ab9540_regulator_match[] = { { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB9540_LDO_AUX1, }, { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB9540_LDO_AUX2, }, @@ -2063,6 +2728,11 @@ static int ab8500_regulator_probe(struct platform_device *pdev) regulator_info_size = ARRAY_SIZE(ab8505_regulator_info); reg_init = ab8505_reg_init; reg_init_size = AB8505_NUM_REGULATOR_REGISTERS; + } else if (is_ab8540(ab8500)) { + regulator_info = ab8540_regulator_info; + regulator_info_size = ARRAY_SIZE(ab8540_regulator_info); + reg_init = ab8540_reg_init; + reg_init_size = AB8540_NUM_REGULATOR_REGISTERS; } else { regulator_info = ab8500_regulator_info; regulator_info_size = ARRAY_SIZE(ab8500_regulator_info); diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 9a7cf97e5040..bb0140c9d4f4 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -68,6 +68,25 @@ enum ab9540_regulator_id { AB9540_NUM_REGULATORS, }; +/* AB8540 regulators */ +enum ab8540_regulator_id { + AB8540_LDO_AUX1, + AB8540_LDO_AUX2, + AB8540_LDO_AUX3, + AB8540_LDO_AUX4, + AB8540_LDO_INTCORE, + AB8540_LDO_TVOUT, + AB8540_LDO_AUDIO, + AB8540_LDO_ANAMIC1, + AB8540_LDO_ANAMIC2, + AB8540_LDO_DMIC, + AB8540_LDO_ANA, + AB8540_LDO_SDIO, + AB8540_SYSCLKREQ_2, + AB8540_SYSCLKREQ_4, + AB8540_NUM_REGULATORS, +}; + /* AB8500, AB8505, and AB9540 register initialization */ struct ab8500_regulator_reg_init { int id; @@ -212,6 +231,73 @@ enum ab9540_regulator_reg { AB9540_NUM_REGULATOR_REGISTERS, }; +/* AB8540 registers */ +enum ab8540_regulator_reg { + AB8540_REGUREQUESTCTRL1, + AB8540_REGUREQUESTCTRL2, + AB8540_REGUREQUESTCTRL3, + AB8540_REGUREQUESTCTRL4, + AB8540_REGUSYSCLKREQ1HPVALID1, + AB8540_REGUSYSCLKREQ1HPVALID2, + AB8540_REGUHWHPREQ1VALID1, + AB8540_REGUHWHPREQ1VALID2, + AB8540_REGUHWHPREQ2VALID1, + AB8540_REGUHWHPREQ2VALID2, + AB8540_REGUSWHPREQVALID1, + AB8540_REGUSWHPREQVALID2, + AB8540_REGUSYSCLKREQVALID1, + AB8540_REGUSYSCLKREQVALID2, + AB8540_REGUVAUX4REQVALID, + AB8540_REGUVAUX5REQVALID, + AB8540_REGUVAUX6REQVALID, + AB8540_REGUVCLKBREQVALID, + AB8540_REGUVRF1REQVALID, + AB8540_REGUMISC1, + AB8540_VAUDIOSUPPLY, + AB8540_REGUCTRL1VAMIC, + AB8540_VHSIC, + AB8540_VSDIO, + AB8540_VSMPS1REGU, + AB8540_VSMPS2REGU, + AB8540_VSMPS3REGU, + AB8540_VPLLVANAREGU, + AB8540_EXTSUPPLYREGU, + AB8540_VAUX12REGU, + AB8540_VRF1VAUX3REGU, + AB8540_VSMPS1SEL1, + AB8540_VSMPS1SEL2, + AB8540_VSMPS1SEL3, + AB8540_VSMPS2SEL1, + AB8540_VSMPS2SEL2, + AB8540_VSMPS2SEL3, + AB8540_VSMPS3SEL1, + AB8540_VSMPS3SEL2, + AB8540_VAUX1SEL, + AB8540_VAUX2SEL, + AB8540_VRF1VAUX3SEL, + AB8540_REGUCTRL2SPARE, + AB8540_VAUX4REQCTRL, + AB8540_VAUX4REGU, + AB8540_VAUX4SEL, + AB8540_VAUX5REQCTRL, + AB8540_VAUX5REGU, + AB8540_VAUX5SEL, + AB8540_VAUX6REQCTRL, + AB8540_VAUX6REGU, + AB8540_VAUX6SEL, + AB8540_VCLKBREQCTRL, + AB8540_VCLKBREGU, + AB8540_VCLKBSEL, + AB8540_VRF1REQCTRL, + AB8540_REGUCTRLDISCH, + AB8540_REGUCTRLDISCH2, + AB8540_REGUCTRLDISCH3, + AB8540_REGUCTRLDISCH4, + AB8540_VSIMSYSCLKCTRL, + AB8540_VANAVPLLSEL, + AB8540_NUM_REGULATOR_REGISTERS, +}; + /* AB8500 external regulators */ struct ab8500_ext_regulator_cfg { bool hwreq; /* requires hw mode or high power mode */ -- cgit v1.2.3 From 35e1d5f6344ed1bb2fab61ac7934aa0f19908b2c Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 2 Apr 2013 13:24:05 +0100 Subject: regulator: ab8500-ext: Remove unused REGULATOR_AB8500_EXT guard Before the AB8500 External Regulator driver was Mainlined, it used to be conditionally compiled in using the CONFIG_REGULATOR_AB8500_EXT flag. During the review process that capability was removed, but the guard controlling prototyping slipped though the net. This patch cleans it up. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- include/linux/regulator/ab8500.h | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index bb0140c9d4f4..44f67e8f1a6d 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -320,21 +320,6 @@ struct ab8500_regulator_platform_data { struct regulator_init_data *ext_regulator; }; -/* AB8500 external regulator functions (internal) */ -#ifdef CONFIG_REGULATOR_AB8500_EXT -int ab8500_ext_regulator_init(struct platform_device *pdev); -int ab8500_ext_regulator_exit(struct platform_device *pdev); -#else -inline int ab8500_ext_regulator_init(struct platform_device *pdev) -{ - return 0; -} -inline int ab8500_ext_regulator_exit(struct platform_device *pdev) -{ - return 0; -} -#endif - #ifdef CONFIG_REGULATOR_AB8500_DEBUG int ab8500_regulator_debug_init(struct platform_device *pdev); int ab8500_regulator_debug_exit(struct platform_device *pdev); @@ -349,4 +334,8 @@ static inline int ab8500_regulator_debug_exit(struct platform_device *pdev) } #endif +/* AB8500 external regulator functions. */ +int ab8500_ext_regulator_init(struct platform_device *pdev); +int ab8500_ext_regulator_exit(struct platform_device *pdev); + #endif -- cgit v1.2.3 From 684d5ce4afafddb2ad08f36ea30ca7d7adc88ebe Mon Sep 17 00:00:00 2001 From: Zhenhua HUANG Date: Tue, 2 Apr 2013 13:24:15 +0100 Subject: regulator: ab8500: Introduce aux5, aux6 regulators for AB8540 Introduce aux5, aux6 into ab8540 regulator framework. Signed-off-by: Zhenhua HUANG Signed-off-by: Lee Jones Reviewed-by: Maxime COQUELIN Reviewed-by: David PARIS Reviewed-by: Philippe LANGLAIS Signed-off-by: Mark Brown --- drivers/regulator/ab8500.c | 65 ++++++++++++++++++++++++++++++++++++++++ include/linux/regulator/ab8500.h | 2 ++ 2 files changed, 67 insertions(+) (limited to 'include/linux') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 9cb634807ff8..433cac4396df 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -149,6 +149,21 @@ static const unsigned int ldo_vaux3_ab8540_voltages[] = { 3050000, }; +static const unsigned int ldo_vaux56_ab8540_voltages[] = { + 750000, 760000, 770000, 780000, 790000, 800000, + 810000, 820000, 830000, 840000, 850000, 860000, + 870000, 880000, 890000, 900000, 910000, 920000, + 930000, 940000, 950000, 960000, 970000, 980000, + 990000, 1000000, 1010000, 1020000, 1030000, + 1040000, 1050000, 1060000, 1070000, 1080000, + 1090000, 1100000, 1110000, 1120000, 1130000, + 1140000, 1150000, 1160000, 1170000, 1180000, + 1190000, 1200000, 1210000, 1220000, 1230000, + 1240000, 1250000, 1260000, 1270000, 1280000, + 1290000, 1300000, 1310000, 1320000, 1330000, + 1340000, 1350000, 1360000, 1800000, 2790000, +}; + static const unsigned int ldo_vintcore_voltages[] = { 1200000, 1225000, @@ -1569,6 +1584,54 @@ static struct ab8500_regulator_info .voltage_reg = 0x2f, .voltage_mask = 0x0f, }, + [AB8540_LDO_AUX5] = { + .desc = { + .name = "LDO-AUX5", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_AUX5, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux56_ab8540_voltages), + }, + .load_lp_uA = 20000, + /* values for Vaux5Regu register */ + .update_bank = 0x04, + .update_reg = 0x32, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + /* values for Vaux5SEL register */ + .voltage_bank = 0x04, + .voltage_reg = 0x33, + .voltage_mask = 0x3f, + .voltages = ldo_vaux56_ab8540_voltages, + .voltages_len = ARRAY_SIZE(ldo_vaux56_ab8540_voltages), + }, + [AB8540_LDO_AUX6] = { + .desc = { + .name = "LDO-AUX6", + .ops = &ab8500_regulator_volt_mode_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8540_LDO_AUX6, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux56_ab8540_voltages), + }, + .load_lp_uA = 20000, + /* values for Vaux6Regu register */ + .update_bank = 0x04, + .update_reg = 0x35, + .update_mask = 0x03, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, + /* values for Vaux6SEL register */ + .voltage_bank = 0x04, + .voltage_reg = 0x36, + .voltage_mask = 0x3f, + .voltages = ldo_vaux56_ab8540_voltages, + .voltages_len = ARRAY_SIZE(ldo_vaux56_ab8540_voltages), + }, [AB8540_LDO_INTCORE] = { .desc = { .name = "LDO-INTCORE", @@ -2979,6 +3042,8 @@ static struct of_regulator_match ab8540_regulator_match[] = { { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8540_LDO_AUX2, }, { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8540_LDO_AUX3, }, { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB8540_LDO_AUX4, }, + { .name = "ab8500_ldo_aux5", .driver_data = (void *) AB8540_LDO_AUX5, }, + { .name = "ab8500_ldo_aux6", .driver_data = (void *) AB8540_LDO_AUX6, }, { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8540_LDO_INTCORE, }, { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8540_LDO_TVOUT, }, { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8540_LDO_AUDIO, }, diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 44f67e8f1a6d..90b8b5ae9a4e 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -74,6 +74,8 @@ enum ab8540_regulator_id { AB8540_LDO_AUX2, AB8540_LDO_AUX3, AB8540_LDO_AUX4, + AB8540_LDO_AUX5, + AB8540_LDO_AUX6, AB8540_LDO_INTCORE, AB8540_LDO_TVOUT, AB8540_LDO_AUDIO, -- cgit v1.2.3 From c4e67bbc99ce661808c3ee77b0bb5779d0df11ca Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 2 Apr 2013 13:24:19 +0100 Subject: ARM: ux500: Pass regulator platform data using the new format Regulator platform data is now passed though a single structure as opposed to the old way where four separate struct elements were required. This patch makes use of the new format. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- arch/arm/mach-ux500/board-mop500.c | 5 +---- include/linux/mfd/abx500/ab8500.h | 11 ++--------- 2 files changed, 3 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index b03457881c4b..b1124bd34a6c 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -198,10 +198,7 @@ static struct platform_device snowball_sbnet_dev = { struct ab8500_platform_data ab8500_platdata = { .irq_base = MOP500_AB8500_IRQ_BASE, - .regulator_reg_init = ab8500_regulator_reg_init, - .num_regulator_reg_init = ARRAY_SIZE(ab8500_regulator_reg_init), - .regulator = ab8500_regulators, - .num_regulator = ARRAY_SIZE(ab8500_regulators), + .regulator = &ab8500_regulator_plat_data, .gpio = &ab8500_gpio_pdata, .codec = &ab8500_codec_pdata, }; diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index 9db0bda446a0..84f449475c25 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h @@ -364,8 +364,7 @@ struct ab8500 { const int *irq_reg_offset; }; -struct regulator_reg_init; -struct regulator_init_data; +struct ab8500_regulator_platform_data; struct ab8500_gpio_platform_data; struct ab8500_codec_platform_data; struct ab8500_sysctrl_platform_data; @@ -375,19 +374,13 @@ struct ab8500_sysctrl_platform_data; * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used * @pm_power_off: Should machine pm power off hook be registered or not * @init: board-specific initialization after detection of ab8500 - * @num_regulator_reg_init: number of regulator init registers - * @regulator_reg_init: regulator init registers - * @num_regulator: number of regulators * @regulator: machine-specific constraints for regulators */ struct ab8500_platform_data { int irq_base; bool pm_power_off; void (*init) (struct ab8500 *); - int num_regulator_reg_init; - struct ab8500_regulator_reg_init *regulator_reg_init; - int num_regulator; - struct regulator_init_data *regulator; + struct ab8500_regulator_platform_data *regulator; struct abx500_gpio_platform_data *gpio; struct ab8500_codec_platform_data *codec; struct ab8500_sysctrl_platform_data *sysctrl; -- cgit v1.2.3 From 3ec6eb9cc2dbfa5b626f813ab8077eb71da60af2 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 4 Apr 2013 18:17:19 +0200 Subject: regulator: max8952: Separate constraints from platform data struct This patch modifies platform data structure of max8952 driver to use pointer to regulator_init_data struct instead of embedding it. This is a prerequisite for adding Device Tree support for the driver. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Signed-off-by: Mark Brown --- arch/arm/mach-exynos/mach-universal_c210.c | 27 ++++++++++++++------------- drivers/regulator/max8952.c | 4 ++-- include/linux/regulator/max8952.h | 2 +- 3 files changed, 17 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 497fcb793dc1..d28c7fbaba2d 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -97,6 +97,19 @@ static struct s3c2410_uartcfg universal_uartcfgs[] __initdata = { static struct regulator_consumer_supply max8952_consumer = REGULATOR_SUPPLY("vdd_arm", NULL); +static struct regulator_init_data universal_max8952_reg_data = { + .constraints = { + .name = "VARM_1.2V", + .min_uV = 770000, + .max_uV = 1400000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &max8952_consumer, +}; + static struct max8952_platform_data universal_max8952_pdata __initdata = { .gpio_vid0 = EXYNOS4_GPX0(3), .gpio_vid1 = EXYNOS4_GPX0(4), @@ -105,19 +118,7 @@ static struct max8952_platform_data universal_max8952_pdata __initdata = { .dvs_mode = { 48, 32, 28, 18 }, /* 1.25, 1.20, 1.05, 0.95V */ .sync_freq = 0, /* default: fastest */ .ramp_speed = 0, /* default: fastest */ - - .reg_data = { - .constraints = { - .name = "VARM_1.2V", - .min_uV = 770000, - .max_uV = 1400000, - .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, - .always_on = 1, - .boot_on = 1, - }, - .num_consumer_supplies = 1, - .consumer_supplies = &max8952_consumer, - }, + .reg_data = &universal_max8952_reg_data, }; static struct regulator_consumer_supply lp3974_buck1_consumer = diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index fc7935a19e3a..100b9177dba1 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -154,11 +154,11 @@ static int max8952_pmic_probe(struct i2c_client *client, max8952->pdata = pdata; config.dev = max8952->dev; - config.init_data = &pdata->reg_data; + config.init_data = pdata->reg_data; config.driver_data = max8952; config.ena_gpio = pdata->gpio_en; - if (pdata->reg_data.constraints.boot_on) + if (pdata->reg_data->constraints.boot_on) config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; max8952->rdev = regulator_register(®ulator, &config); diff --git a/include/linux/regulator/max8952.h b/include/linux/regulator/max8952.h index 45e42855ad05..c13aa34d9019 100644 --- a/include/linux/regulator/max8952.h +++ b/include/linux/regulator/max8952.h @@ -128,7 +128,7 @@ struct max8952_platform_data { u8 sync_freq; u8 ramp_speed; - struct regulator_init_data reg_data; + struct regulator_init_data *reg_data; }; -- cgit v1.2.3 From 3ff4aa95b3cd960a1c2e1422bc3dbd604f88271b Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Thu, 4 Apr 2013 18:17:20 +0200 Subject: regulator: max8952: Add Device Tree support This patch adds Device Tree support to max8952 regulator driver. Signed-off-by: Tomasz Figa Signed-off-by: Kyungmin Park Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/max8952.txt | 52 ++++++++++++++++ drivers/regulator/max8952.c | 70 ++++++++++++++++++++++ include/linux/regulator/max8952.h | 8 +-- 3 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/regulator/max8952.txt (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/regulator/max8952.txt b/Documentation/devicetree/bindings/regulator/max8952.txt new file mode 100644 index 000000000000..866fcdd0f4eb --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max8952.txt @@ -0,0 +1,52 @@ +Maxim MAX8952 voltage regulator + +Required properties: +- compatible: must be equal to "maxim,max8952" +- reg: I2C slave address, usually 0x60 +- max8952,dvs-mode-microvolt: array of 4 integer values defining DVS voltages + in microvolts. All values must be from range <770000, 1400000> +- any required generic properties defined in regulator.txt + +Optional properties: +- max8952,vid-gpios: array of two GPIO pins used for DVS voltage selection +- max8952,en-gpio: GPIO used to control enable status of regulator +- max8952,default-mode: index of default DVS voltage, from <0, 3> range +- max8952,sync-freq: sync frequency, must be one of following values: + - 0: 26 MHz + - 1: 13 MHz + - 2: 19.2 MHz + Defaults to 26 MHz if not specified. +- max8952,ramp-speed: voltage ramp speed, must be one of following values: + - 0: 32mV/us + - 1: 16mV/us + - 2: 8mV/us + - 3: 4mV/us + - 4: 2mV/us + - 5: 1mV/us + - 6: 0.5mV/us + - 7: 0.25mV/us + Defaults to 32mV/us if not specified. +- any available generic properties defined in regulator.txt + +Example: + + vdd_arm_reg: pmic@60 { + compatible = "maxim,max8952"; + reg = <0x60>; + + /* max8952-specific properties */ + max8952,vid-gpios = <&gpx0 3 0>, <&gpx0 4 0>; + max8952,en-gpio = <&gpx0 1 0>; + max8952,default-mode = <0>; + max8952,dvs-mode-microvolt = <1250000>, <1200000>, + <1050000>, <950000>; + max8952,sync-freq = <0>; + max8952,ramp-speed = <0>; + + /* generic regulator properties */ + regulator-name = "vdd_arm"; + regulator-min-microvolt = <770000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + regulator-boot-on; + }; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 100b9177dba1..4259c78abf88 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include /* Registers */ @@ -126,6 +129,69 @@ static const struct regulator_desc regulator = { .owner = THIS_MODULE, }; +#ifdef CONFIG_OF +static struct of_device_id max8952_dt_match[] = { + { .compatible = "maxim,max8952" }, + {}, +}; +MODULE_DEVICE_TABLE(of, max8952_dt_match); + +static struct max8952_platform_data *max8952_parse_dt(struct device *dev) +{ + struct max8952_platform_data *pd; + struct device_node *np = dev->of_node; + int ret; + int i; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) { + dev_err(dev, "Failed to allocate platform data\n"); + return NULL; + } + + pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0); + pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1); + pd->gpio_en = of_get_named_gpio(np, "max8952,en-gpio", 0); + + if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode)) + dev_warn(dev, "Default mode not specified, assuming 0\n"); + + ret = of_property_read_u32_array(np, "max8952,dvs-mode-microvolt", + pd->dvs_mode, ARRAY_SIZE(pd->dvs_mode)); + if (ret) { + dev_err(dev, "max8952,dvs-mode-microvolt property not specified"); + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(pd->dvs_mode); ++i) { + if (pd->dvs_mode[i] < 770000 || pd->dvs_mode[i] > 1400000) { + dev_err(dev, "DVS voltage %d out of range\n", i); + return NULL; + } + pd->dvs_mode[i] = (pd->dvs_mode[i] - 770000) / 10000; + } + + if (of_property_read_u32(np, "max8952,sync-freq", &pd->sync_freq)) + dev_warn(dev, "max8952,sync-freq property not specified, defaulting to 26MHz\n"); + + if (of_property_read_u32(np, "max8952,ramp-speed", &pd->ramp_speed)) + dev_warn(dev, "max8952,ramp-speed property not specified, defaulting to 32mV/us\n"); + + pd->reg_data = of_get_regulator_init_data(dev, np); + if (!pd->reg_data) { + dev_err(dev, "Failed to parse regulator init data\n"); + return NULL; + } + + return pd; +} +#else +static struct max8952_platform_data *max8952_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + static int max8952_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { @@ -136,6 +202,9 @@ static int max8952_pmic_probe(struct i2c_client *client, int ret = 0, err = 0; + if (client->dev.of_node) + pdata = max8952_parse_dt(&client->dev); + if (!pdata) { dev_err(&client->dev, "Require the platform data\n"); return -EINVAL; @@ -271,6 +340,7 @@ static struct i2c_driver max8952_pmic_driver = { .remove = max8952_pmic_remove, .driver = { .name = "max8952", + .of_match_table = of_match_ptr(max8952_dt_match), }, .id_table = max8952_ids, }; diff --git a/include/linux/regulator/max8952.h b/include/linux/regulator/max8952.h index c13aa34d9019..4dbb63a1d4ab 100644 --- a/include/linux/regulator/max8952.h +++ b/include/linux/regulator/max8952.h @@ -122,11 +122,11 @@ struct max8952_platform_data { int gpio_vid1; int gpio_en; - u8 default_mode; - u8 dvs_mode[MAX8952_NUM_DVS_MODE]; /* MAX8952_DVS_MODEx_XXXXmV */ + u32 default_mode; + u32 dvs_mode[MAX8952_NUM_DVS_MODE]; /* MAX8952_DVS_MODEx_XXXXmV */ - u8 sync_freq; - u8 ramp_speed; + u32 sync_freq; + u32 ramp_speed; struct regulator_init_data *reg_data; }; -- cgit v1.2.3 From 3480c0cab6e1a25fdeb63147b0b643b7825a36fb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 11 Apr 2013 12:04:18 +0800 Subject: regulator: ab8500-ext: Make the return type of ab8500_ext_regulator_exit() void ab8500_ext_regulator_exit() never fails. Signed-off-by: Axel Lin Acked-by: Bengt Jonsson Signed-off-by: Mark Brown --- drivers/regulator/ab8500-ext.c | 4 +--- drivers/regulator/ab8500.c | 9 +++------ include/linux/regulator/ab8500.h | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c index 9aee21cad379..20680f30a968 100644 --- a/drivers/regulator/ab8500-ext.c +++ b/drivers/regulator/ab8500-ext.c @@ -394,7 +394,7 @@ int ab8500_ext_regulator_init(struct platform_device *pdev) return 0; } -int ab8500_ext_regulator_exit(struct platform_device *pdev) +void ab8500_ext_regulator_exit(struct platform_device *pdev) { int i; @@ -407,8 +407,6 @@ int ab8500_ext_regulator_exit(struct platform_device *pdev) regulator_unregister(info->rdev); } - - return 0; } MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 9ebd131b2ec6..c200f8bb61db 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -3194,12 +3194,9 @@ static int ab8500_regulator_remove(struct platform_device *pdev) regulator_unregister(info->regulator); } - if (!is_ab8505(ab8500)) { - /* remove external regulators (after Vaux1, 2 and 3) */ - err = ab8500_ext_regulator_exit(pdev); - if (err) - return err; - } + /* remove external regulators (after Vaux1, 2 and 3) */ + if (!is_ab8505(ab8500)) + ab8500_ext_regulator_exit(pdev); /* remove regulator debug */ err = ab8500_regulator_debug_exit(pdev); diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 90b8b5ae9a4e..7c5ff0c55773 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -338,6 +338,6 @@ static inline int ab8500_regulator_debug_exit(struct platform_device *pdev) /* AB8500 external regulator functions. */ int ab8500_ext_regulator_init(struct platform_device *pdev); -int ab8500_ext_regulator_exit(struct platform_device *pdev); +void ab8500_ext_regulator_exit(struct platform_device *pdev); #endif -- cgit v1.2.3 From aa07f02793ec149d560142f25af0243fff84208b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 17 Apr 2013 15:13:12 +0530 Subject: regulator: palmas: support for external regulator through control outputs Palmas device have control outputs like REGEN1, REGEN2, REGEN3, SYSEN1 and SYSEN2. These control outputs can be used for controlling external voltage switches to enabled/disable voltage outputs. Add support of these control outputs through regulator framework. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 95 +++++++++++++++++++++++++++++++----- include/linux/mfd/palmas.h | 6 +++ 2 files changed, 89 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index af2109a73a80..c61c0fa83e22 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -165,6 +165,26 @@ static const struct regs_info palmas_regs_info[] = { .vsel_addr = PALMAS_LDOUSB_VOLTAGE, .ctrl_addr = PALMAS_LDOUSB_CTRL, }, + { + .name = "REGEN1", + .ctrl_addr = PALMAS_REGEN1_CTRL, + }, + { + .name = "REGEN2", + .ctrl_addr = PALMAS_REGEN2_CTRL, + }, + { + .name = "REGEN3", + .ctrl_addr = PALMAS_REGEN3_CTRL, + }, + { + .name = "SYSEN1", + .ctrl_addr = PALMAS_SYSEN1_CTRL, + }, + { + .name = "SYSEN2", + .ctrl_addr = PALMAS_SYSEN2_CTRL, + }, }; #define SMPS_CTRL_MODE_OFF 0x00 @@ -422,6 +442,12 @@ static struct regulator_ops palmas_ops_ldo = { .map_voltage = regulator_map_voltage_linear, }; +static struct regulator_ops palmas_ops_extreg = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, +}; + /* * setup the hardware based sleep configuration of the SMPS/LDO regulators * from the platform data. This is different to the software based control @@ -523,6 +549,28 @@ static int palmas_ldo_init(struct palmas *palmas, int id, return 0; } +static int palmas_extreg_init(struct palmas *palmas, int id, + struct palmas_reg_init *reg_init) +{ + unsigned int addr; + int ret; + unsigned int val = 0; + + addr = palmas_regs_info[id].ctrl_addr; + + if (reg_init->mode_sleep) + val = PALMAS_REGEN1_CTRL_MODE_SLEEP; + + ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, + addr, PALMAS_REGEN1_CTRL_MODE_SLEEP, val); + if (ret < 0) { + dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n", + addr, ret); + return ret; + } + return 0; +} + static struct of_regulator_match palmas_matches[] = { { .name = "smps12", }, { .name = "smps123", }, @@ -545,6 +593,11 @@ static struct of_regulator_match palmas_matches[] = { { .name = "ldo9", }, { .name = "ldoln", }, { .name = "ldousb", }, + { .name = "regen1", }, + { .name = "regen2", }, + { .name = "regen3", }, + { .name = "sysen1", }, + { .name = "sysen2", }, }; static void palmas_dt_to_pdata(struct device *dev, @@ -763,21 +816,34 @@ static int palmas_regulators_probe(struct platform_device *pdev) /* Register the regulators */ pmic->desc[id].name = palmas_regs_info[id].name; pmic->desc[id].id = id; - pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES; - - pmic->desc[id].ops = &palmas_ops_ldo; - pmic->desc[id].type = REGULATOR_VOLTAGE; pmic->desc[id].owner = THIS_MODULE; - pmic->desc[id].min_uV = 900000; - pmic->desc[id].uV_step = 50000; - pmic->desc[id].linear_min_sel = 1; - pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + + if (id < PALMAS_REG_REGEN1) { + pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES; + pmic->desc[id].ops = &palmas_ops_ldo; + pmic->desc[id].min_uV = 900000; + pmic->desc[id].uV_step = 50000; + pmic->desc[id].linear_min_sel = 1; + pmic->desc[id].vsel_reg = + PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, palmas_regs_info[id].vsel_addr); - pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK; - pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + pmic->desc[id].vsel_mask = + PALMAS_LDO1_VOLTAGE_VSEL_MASK; + pmic->desc[id].enable_reg = + PALMAS_BASE_TO_REG(PALMAS_LDO_BASE, + palmas_regs_info[id].ctrl_addr); + pmic->desc[id].enable_mask = + PALMAS_LDO1_CTRL_MODE_ACTIVE; + } else { + pmic->desc[id].n_voltages = 1; + pmic->desc[id].ops = &palmas_ops_extreg; + pmic->desc[id].enable_reg = + PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE, palmas_regs_info[id].ctrl_addr); - pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; + pmic->desc[id].enable_mask = + PALMAS_REGEN1_CTRL_MODE_ACTIVE; + } if (pdata) config.init_data = pdata->reg_data[id]; @@ -803,7 +869,12 @@ static int palmas_regulators_probe(struct platform_device *pdev) if (pdata) { reg_init = pdata->reg_init[id]; if (reg_init) { - ret = palmas_ldo_init(palmas, id, reg_init); + if (id < PALMAS_REG_REGEN1) + ret = palmas_ldo_init(palmas, + id, reg_init); + else + ret = palmas_extreg_init(palmas, + id, reg_init); if (ret) { regulator_unregister(pmic->rdev[id]); goto err_unregister_regulator; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index a4d13d7cd001..44256aa7b46a 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -154,6 +154,12 @@ enum palmas_regulators { PALMAS_REG_LDO9, PALMAS_REG_LDOLN, PALMAS_REG_LDOUSB, + /* External regulators */ + PALMAS_REG_REGEN1, + PALMAS_REG_REGEN2, + PALMAS_REG_REGEN3, + PALMAS_REG_SYSEN1, + PALMAS_REG_SYSEN2, /* Total number of regulators */ PALMAS_NUM_REGS, }; -- cgit v1.2.3 From 17c11a7603496949989ed286ed218a9e645b6259 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 17 Apr 2013 15:13:13 +0530 Subject: regulator: palmas: add support for LDO8 tracking mode LDO8 of Palma device like tps65913 support the tracking mode on which LDO8 track the SMPS45 voltage when SMPS45 is ON and use the LDO8.VOLTAGE_SEL register when SMPS45 is OFF. On track mode, the steps of voltage change for LDO8 is 25mV where in non-tracking mode it is 50mV. Set the steps accordingly. Number of voltage count is still same for both the cases. Signed-off-by: Laxman Dewangan Acked-by: Graeme Gregory Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 53 ++++++++++++++++++++++++++++++++++++ include/linux/mfd/palmas.h | 3 ++ 2 files changed, 56 insertions(+) (limited to 'include/linux') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index c61c0fa83e22..6538b339e441 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -571,6 +571,46 @@ static int palmas_extreg_init(struct palmas *palmas, int id, return 0; } +static void palmas_enable_ldo8_track(struct palmas *palmas) +{ + unsigned int reg; + unsigned int addr; + int ret; + + addr = palmas_regs_info[PALMAS_REG_LDO8].ctrl_addr; + + ret = palmas_ldo_read(palmas, addr, ®); + if (ret) { + dev_err(palmas->dev, "Error in reading ldo8 control reg\n"); + return; + } + + reg |= PALMAS_LDO8_CTRL_LDO_TRACKING_EN; + ret = palmas_ldo_write(palmas, addr, reg); + if (ret < 0) { + dev_err(palmas->dev, "Error in enabling tracking mode\n"); + return; + } + /* + * When SMPS45 is set to off and LDO8 tracking is enabled, the LDO8 + * output is defined by the LDO8_VOLTAGE.VSEL register divided by two, + * and can be set from 0.45 to 1.65 V. + */ + addr = palmas_regs_info[PALMAS_REG_LDO8].vsel_addr; + ret = palmas_ldo_read(palmas, addr, ®); + if (ret) { + dev_err(palmas->dev, "Error in reading ldo8 voltage reg\n"); + return; + } + + reg = (reg << 1) & PALMAS_LDO8_VOLTAGE_VSEL_MASK; + ret = palmas_ldo_write(palmas, addr, reg); + if (ret < 0) + dev_err(palmas->dev, "Error in setting ldo8 voltage reg\n"); + + return; +} + static struct of_regulator_match palmas_matches[] = { { .name = "smps12", }, { .name = "smps123", }, @@ -656,6 +696,11 @@ static void palmas_dt_to_pdata(struct device *dev, if (ret) pdata->reg_init[idx]->vsel = PALMAS_SMPS12_VOLTAGE_RANGE; + + if (idx == PALMAS_REG_LDO8) + pdata->enable_ldo8_tracking = of_property_read_bool( + palmas_matches[idx].of_node, + "ti,enable-ldo8-tracking"); } pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator"); @@ -835,6 +880,13 @@ static int palmas_regulators_probe(struct platform_device *pdev) palmas_regs_info[id].ctrl_addr); pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; + + /* Check if LDO8 is in tracking mode or not */ + if (pdata && (id == PALMAS_REG_LDO8) && + pdata->enable_ldo8_tracking) { + palmas_enable_ldo8_track(palmas); + pmic->desc[id].uV_step = 25000; + } } else { pmic->desc[id].n_voltages = 1; pmic->desc[id].ops = &palmas_ops_extreg; @@ -883,6 +935,7 @@ static int palmas_regulators_probe(struct platform_device *pdev) } } + return 0; err_unregister_regulator: diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index 44256aa7b46a..10daa8c1e73c 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -177,6 +177,9 @@ struct palmas_pmic_platform_data { /* use LDO6 for vibrator control */ int ldo6_vibrator; + + /* Enable tracking mode of LDO8 */ + bool enable_ldo8_tracking; }; struct palmas_usb_platform_data { -- cgit v1.2.3 From fcf371ee5624cc87abac205cd0dad2432d7f0346 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 18 Apr 2013 10:34:49 +0800 Subject: regulator: core: Add regulator_map_voltage_ascend() API A lot of regulator hardware has ascendant voltage list. This patch adds regulator_map_voltage_ascend() and export it. Drivers that have ascendant voltage list can use this as their map_voltage() operation, this is more efficient than default regulator_map_voltage_iterate() function. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/core.c | 31 +++++++++++++++++++++++++++++++ include/linux/regulator/driver.h | 2 ++ 2 files changed, 33 insertions(+) (limited to 'include/linux') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e3661c20cf38..56f4ca0854c9 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2137,6 +2137,37 @@ int regulator_map_voltage_iterate(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate); +/** + * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list + * + * @rdev: Regulator to operate on + * @min_uV: Lower bound for voltage + * @max_uV: Upper bound for voltage + * + * Drivers that have ascendant voltage list can use this as their + * map_voltage() operation. + */ +int regulator_map_voltage_ascend(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int i, ret; + + for (i = 0; i < rdev->desc->n_voltages; i++) { + ret = rdev->desc->ops->list_voltage(rdev, i); + if (ret < 0) + continue; + + if (ret > max_uV) + break; + + if (ret >= min_uV && ret <= max_uV) + return i; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend); + /** * regulator_map_voltage_linear - map_voltage() for simple linear mappings * diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 7df93f52db08..2acdc66f8342 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -329,6 +329,8 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev, int min_uV, int max_uV); int regulator_map_voltage_iterate(struct regulator_dev *rdev, int min_uV, int max_uV); +int regulator_map_voltage_ascend(struct regulator_dev *rdev, + int min_uV, int max_uV); int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev); int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel); int regulator_is_enabled_regmap(struct regulator_dev *rdev); -- cgit v1.2.3 From 28d1e8cd671a53d6b4f967abbbc2a55f7bd333f6 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 18 Apr 2013 18:32:47 +0530 Subject: regulator: palma: add ramp delay support through regulator constraints Currently Palma regulator driver support the ramp delay through rail specific platform data. As regulator framework support the configuration of ramp delay through regulator constraint, using the framework method and removing the platform specific data approach. Signed-off-by: Laxman Dewangan Acked-by: Graeme Gregory Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 93 ++++++++++++++++++++++++++++++------ include/linux/mfd/palmas.h | 14 +----- 2 files changed, 79 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 6538b339e441..33369160b770 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -187,6 +187,8 @@ static const struct regs_info palmas_regs_info[] = { }, }; +static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500}; + #define SMPS_CTRL_MODE_OFF 0x00 #define SMPS_CTRL_MODE_ON 0x01 #define SMPS_CTRL_MODE_ECO 0x02 @@ -397,6 +399,56 @@ static int palmas_map_voltage_smps(struct regulator_dev *rdev, return ret; } +static int palma_smps_set_voltage_smps_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int old_uv, new_uv; + unsigned int ramp_delay = pmic->ramp_delay[id]; + + if (!ramp_delay) + return 0; + + old_uv = palmas_list_voltage_smps(rdev, old_selector); + if (old_uv < 0) + return old_uv; + + new_uv = palmas_list_voltage_smps(rdev, new_selector); + if (new_uv < 0) + return new_uv; + + return DIV_ROUND_UP(abs(old_uv - new_uv), ramp_delay); +} + +static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev, + int ramp_delay) +{ + struct palmas_pmic *pmic = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + unsigned int reg = 0; + unsigned int addr = palmas_regs_info[id].tstep_addr; + int ret; + + if (ramp_delay <= 0) + reg = 0; + else if (ramp_delay < 2500) + reg = 3; + else if (ramp_delay < 5000) + reg = 2; + else + reg = 1; + + ret = palmas_smps_write(pmic->palmas, addr, reg); + if (ret < 0) { + dev_err(pmic->palmas->dev, "TSTEP write failed: %d\n", ret); + return ret; + } + + pmic->ramp_delay[id] = palmas_smps_ramp_delay[reg]; + return ret; +} + static struct regulator_ops palmas_ops_smps = { .is_enabled = palmas_is_enabled_smps, .enable = palmas_enable_smps, @@ -407,6 +459,8 @@ static struct regulator_ops palmas_ops_smps = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .list_voltage = palmas_list_voltage_smps, .map_voltage = palmas_map_voltage_smps, + .set_voltage_time_sel = palma_smps_set_voltage_smps_time_sel, + .set_ramp_delay = palmas_smps_set_ramp_delay, }; static struct regulator_ops palmas_ops_smps10 = { @@ -495,16 +549,6 @@ static int palmas_smps_init(struct palmas *palmas, int id, if (ret) return ret; - if (palmas_regs_info[id].tstep_addr && reg_init->tstep) { - addr = palmas_regs_info[id].tstep_addr; - - reg = reg_init->tstep & PALMAS_SMPS12_TSTEP_TSTEP_MASK; - - ret = palmas_smps_write(palmas, addr, reg); - if (ret) - return ret; - } - if (palmas_regs_info[id].vsel_addr && reg_init->vsel) { addr = palmas_regs_info[id].vsel_addr; @@ -686,11 +730,6 @@ static void palmas_dt_to_pdata(struct device *dev, if (!ret) pdata->reg_init[idx]->mode_sleep = prop; - ret = of_property_read_u32(palmas_matches[idx].of_node, - "ti,tstep", &prop); - if (!ret) - pdata->reg_init[idx]->tstep = prop; - ret = of_property_read_bool(palmas_matches[idx].of_node, "ti,smps-range"); if (ret) @@ -752,6 +791,7 @@ static int palmas_regulators_probe(struct platform_device *pdev) config.driver_data = pmic; for (id = 0; id < PALMAS_REG_LDO1; id++) { + bool ramp_delay_support = false; /* * Miss out regulators which are not available due @@ -762,19 +802,42 @@ static int palmas_regulators_probe(struct platform_device *pdev) case PALMAS_REG_SMPS3: if (pmic->smps123) continue; + if (id == PALMAS_REG_SMPS12) + ramp_delay_support = true; break; case PALMAS_REG_SMPS123: if (!pmic->smps123) continue; + ramp_delay_support = true; break; case PALMAS_REG_SMPS45: case PALMAS_REG_SMPS7: if (pmic->smps457) continue; + if (id == PALMAS_REG_SMPS45) + ramp_delay_support = true; break; case PALMAS_REG_SMPS457: if (!pmic->smps457) continue; + ramp_delay_support = true; + break; + } + + if ((id == PALMAS_REG_SMPS6) && (id == PALMAS_REG_SMPS8)) + ramp_delay_support = true; + + if (ramp_delay_support) { + addr = palmas_regs_info[id].tstep_addr; + ret = palmas_smps_read(pmic->palmas, addr, ®); + if (ret < 0) { + dev_err(&pdev->dev, + "reading TSTEP reg failed: %d\n", ret); + goto err_unregister_regulator; + } + pmic->desc[id].ramp_delay = + palmas_smps_ramp_delay[reg & 0x3]; + pmic->ramp_delay[id] = pmic->desc[id].ramp_delay; } /* Initialise sleep/init values from platform data */ diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index 10daa8c1e73c..a58c579e8cf4 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -109,19 +109,6 @@ struct palmas_reg_init { */ int mode_sleep; - /* tstep is the timestep loaded to the TSTEP register - * - * For SMPS - * - * 0: Jump (no slope control) - * 1: 10mV/us - * 2: 5mV/us - * 3: 2.5mV/us - * - * For LDO unused - */ - int tstep; - /* voltage_sel is the bitfield loaded onto the SMPSX_VOLTAGE * register. Set this is the default voltage set in OTP needs * to be overridden. @@ -339,6 +326,7 @@ struct palmas_pmic { int smps457; int range[PALMAS_REG_SMPS10]; + unsigned int ramp_delay[PALMAS_REG_SMPS10]; }; struct palmas_resource { -- cgit v1.2.3 From 51d3a0c999e18a802a654171b5e05952b4630148 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 18 Apr 2013 18:32:48 +0530 Subject: regulator: palmas: preserve modes of rails during enable/disable The Palma device like TPS65913 have the mode mask which is also used for enable/disable the rails. The mode bits are defined as 00: OFF 01: AUTO 10: ECO 11: Forced PWM and modes are set accordingly as REGULATOR_MODE_NORMAL: AUTO REGULATOR_MODE_IDLE: ECO REGULATOR_MODE_FAST: PWM Two issue observed: 1. If client calls following sequence: regulator_enable(), regulator_set_mode(FAST), regulator_disable() and again the regulator_enable() then the mode is reset to NORMAL inplace of keeping the mode as FAST. Fixing this by storing the current mode configured by client and restoring modes when enable() is called after disable(). 2. In following sequence, the regulator get enabled: regulator_disable() regulator_set_mode(FAST), Fixing this by updating new mode in register only if it is enabled. Signed-off-by: Laxman Dewangan Acked-by: Graeme Gregory Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 30 +++++++++++++++++++++++------- include/linux/mfd/palmas.h | 1 + 2 files changed, 24 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 33369160b770..38447ac53cb8 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -274,7 +274,10 @@ static int palmas_enable_smps(struct regulator_dev *dev) palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; - reg |= SMPS_CTRL_MODE_ON; + if (pmic->current_reg_mode[id]) + reg |= pmic->current_reg_mode[id]; + else + reg |= SMPS_CTRL_MODE_ON; palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg); @@ -296,16 +299,19 @@ static int palmas_disable_smps(struct regulator_dev *dev) return 0; } - static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode) { struct palmas_pmic *pmic = rdev_get_drvdata(dev); int id = rdev_get_id(dev); unsigned int reg; + bool rail_enable = true; palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + if (reg == SMPS_CTRL_MODE_OFF) + rail_enable = false; + switch (mode) { case REGULATOR_MODE_NORMAL: reg |= SMPS_CTRL_MODE_ON; @@ -319,8 +325,11 @@ static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode) default: return -EINVAL; } - palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg); + pmic->current_reg_mode[id] = reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + if (rail_enable) + palmas_smps_write(pmic->palmas, + palmas_regs_info[id].ctrl_addr, reg); return 0; } @@ -330,9 +339,7 @@ static unsigned int palmas_get_mode_smps(struct regulator_dev *dev) int id = rdev_get_id(dev); unsigned int reg; - palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); - reg &= PALMAS_SMPS12_CTRL_STATUS_MASK; - reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT; + reg = pmic->current_reg_mode[id] & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; switch (reg) { case SMPS_CTRL_MODE_ON: @@ -871,7 +878,8 @@ static int palmas_regulators_probe(struct platform_device *pdev) /* * Read and store the RANGE bit for later use * This must be done before regulator is probed, - * otherwise we error in probe with unsupportable ranges. + * otherwise we error in probe with unsupportable + * ranges. Read the current smps mode for later use. */ addr = palmas_regs_info[id].vsel_addr; @@ -888,6 +896,14 @@ static int palmas_regulators_probe(struct platform_device *pdev) palmas_regs_info[id].vsel_addr); pmic->desc[id].vsel_mask = PALMAS_SMPS12_VOLTAGE_VSEL_MASK; + + /* Read the smps mode for later use. */ + addr = palmas_regs_info[id].ctrl_addr; + ret = palmas_smps_read(pmic->palmas, addr, ®); + if (ret) + goto err_unregister_regulator; + pmic->current_reg_mode[id] = reg & + PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; } pmic->desc[id].type = REGULATOR_VOLTAGE; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index a58c579e8cf4..e971a7c81b79 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -327,6 +327,7 @@ struct palmas_pmic { int range[PALMAS_REG_SMPS10]; unsigned int ramp_delay[PALMAS_REG_SMPS10]; + unsigned int current_reg_mode[PALMAS_REG_SMPS10]; }; struct palmas_resource { -- cgit v1.2.3