From patchwork Thu Mar 21 15:59:32 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lee Jones X-Patchwork-Id: 15510 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 5CEAC23E14 for ; Thu, 21 Mar 2013 16:01:17 +0000 (UTC) Received: from mail-vc0-f179.google.com (mail-vc0-f179.google.com [209.85.220.179]) by fiordland.canonical.com (Postfix) with ESMTP id 678ECA19955 for ; Thu, 21 Mar 2013 16:01:15 +0000 (UTC) Received: by mail-vc0-f179.google.com with SMTP id gf12so2467865vcb.10 for ; Thu, 21 Mar 2013 09:01:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:x-received:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=kWAzKZN2EwNOnfwdl/AOnhh4yq47eZk6IqVKOTtCaao=; b=cWiSP0NSx5IFk9sbiNwsD7xd041FTeRRZEcFCz76fBDvk2AbG341hTE+bXbuWTRYnr uW6G7SXPCQwVFCgr3w01mwLWhZ/2hEF//K0rmYqqcmMgfMZPP9plnPdt8k64MzDlW2UK /uOwzsBpbr7nTTWaQy3drGYkCXufFfsABPF9/5mops065iThdWiscFBoaElYQlO83c4/ MqpNbd/sFINsdTapK0tKfpJLltuBcwC3gUnDY6ZUG5tA5uZnh8RnYTlZ/UXepHbvrOgu DDF7bWJnduzeBydzxYXFQrPc6kNACf/GQ7rynMhkf364UNfbiQZPgMEN40+uOmOsKoJ5 rHrA== X-Received: by 10.52.31.103 with SMTP id z7mr12002904vdh.56.1363881674821; Thu, 21 Mar 2013 09:01:14 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.58.233.198 with SMTP id ty6csp66818vec; Thu, 21 Mar 2013 09:01:14 -0700 (PDT) X-Received: by 10.180.72.148 with SMTP id d20mr5801949wiv.31.1363881673141; Thu, 21 Mar 2013 09:01:13 -0700 (PDT) Received: from mail-wi0-x232.google.com ([2a00:1450:400c:c05::232]) by mx.google.com with ESMTPS id eo13si1418609wid.102.2013.03.21.09.01.12 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 21 Mar 2013 09:01:13 -0700 (PDT) Received-SPF: neutral (google.com: 2a00:1450:400c:c05::232 is neither permitted nor denied by best guess record for domain of lee.jones@linaro.org) client-ip=2a00:1450:400c:c05::232; Authentication-Results: mx.google.com; spf=neutral (google.com: 2a00:1450:400c:c05::232 is neither permitted nor denied by best guess record for domain of lee.jones@linaro.org) smtp.mail=lee.jones@linaro.org Received: by mail-wi0-f178.google.com with SMTP id hq4so3277361wib.5 for ; Thu, 21 Mar 2013 09:01:12 -0700 (PDT) X-Received: by 10.180.81.193 with SMTP id c1mr5684152wiy.19.1363881672651; Thu, 21 Mar 2013 09:01:12 -0700 (PDT) Received: from localhost.localdomain (cpc34-aztw25-2-0-cust250.18-1.cable.virginmedia.com. [86.16.136.251]) by mx.google.com with ESMTPS id h10sm6110847wic.8.2013.03.21.09.01.10 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 21 Mar 2013 09:01:11 -0700 (PDT) From: Lee Jones To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, broonie@opensource.wolfsonmicro.com Cc: arnd@arndb.de, linus.walleij@stericsson.com, Lee Jones Subject: [PATCH 35/46] regulator: ab8500: Add mode operation for v-amic Date: Thu, 21 Mar 2013 15:59:32 +0000 Message-Id: <1363881583-15234-36-git-send-email-lee.jones@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1363881583-15234-1-git-send-email-lee.jones@linaro.org> References: <1363881583-15234-1-git-send-email-lee.jones@linaro.org> X-Gm-Message-State: ALoCoQm+WQFHerr9e+Aaz4K0VjaWtoP9rw3d5buxaxsN4oZ7QFydK7dchWmuzhL599d5sy3UN1Ml v-amic1 and v-amic2 regulators have dedicated mode registers and share the same mode bit. This patch adds special handling for those regulators. Signed-off-by: Lee Jones --- arch/arm/mach-ux500/board-mop500-regulators.c | 10 +- drivers/regulator/ab8500.c | 178 ++++++++++++++++++++++--- 2 files changed, 167 insertions(+), 21 deletions(-) diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index 8161519..30e61e0 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -877,7 +877,10 @@ struct regulator_init_data ab8505_regulators[AB8505_NUM_REGULATORS] = { [AB8505_LDO_ANAMIC1] = { .constraints = { .name = "V-AMIC1", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, }, .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers), .consumer_supplies = ab8500_vamic1_consumers, @@ -886,7 +889,10 @@ struct regulator_init_data ab8505_regulators[AB8505_NUM_REGULATORS] = { [AB8505_LDO_ANAMIC2] = { .constraints = { .name = "V-AMIC2", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .valid_ops_mask = REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_IDLE, }, .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers), .consumer_supplies = ab8500_vamic2_consumers, diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 9f41a10b..7265a24 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -30,10 +30,22 @@ #include /** + * struct ab8500_shared_mode - is used when mode is shared between + * two regulators. + * @shared_regulator: pointer to the other sharing regulator + * @lp_mode_req: low power mode requested by this regulator + */ +struct ab8500_shared_mode { + struct ab8500_regulator_info *shared_regulator; + bool lp_mode_req; +}; + +/** * struct ab8500_regulator_info - ab8500 regulator information * @dev: device pointer * @desc: regulator description * @regulator_dev: regulator device + * @shared_mode: used when mode is shared between two regulators * @is_enabled: status of regulator (on/off) * @load_lp_uA: maximum load in idle (low power) mode * @update_bank: bank to control on/off @@ -42,6 +54,11 @@ * @update_val: bits holding the regulator current mode * @update_val_idle: bits to enable the regulator in idle (low power) mode * @update_val_normal: bits to enable the regulator in normal (high power) mode + * @mode_bank: bank with location of mode register + * @mode_reg: mode register + * @mode_mask: mask for setting mode + * @mode_val_idle: mode setting for low power + * @mode_val_normal: mode setting for normal power * @voltage_bank: bank to control regulator voltage * @voltage_reg: register to control regulator voltage * @voltage_mask: mask to control regulator voltage @@ -52,6 +69,7 @@ struct ab8500_regulator_info { struct device *dev; struct regulator_desc desc; struct regulator_dev *regulator; + struct ab8500_shared_mode *shared_mode; bool is_enabled; int load_lp_uA; u8 update_bank; @@ -60,6 +78,11 @@ struct ab8500_regulator_info { u8 update_val; u8 update_val_idle; u8 update_val_normal; + u8 mode_bank; + u8 mode_reg; + u8 mode_mask; + u8 mode_val_idle; + u8 mode_val_normal; u8 voltage_bank; u8 voltage_reg; u8 voltage_mask; @@ -191,6 +214,10 @@ static const unsigned int ldo_vaudio_voltages[] = { 2600000, /* Duplicated in Vaudio and IsoUicc Control register. */ }; +static DEFINE_MUTEX(shared_mode_mutex); +static struct ab8500_shared_mode ldo_anamic1_shared; +static struct ab8500_shared_mode ldo_anamic2_shared; + static int ab8500_regulator_enable(struct regulator_dev *rdev) { int ret; @@ -270,7 +297,11 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) { int ret = 0; - + u8 bank; + u8 reg; + u8 mask; + u8 val; + bool dmr = false; /* Dedicated mode register */ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); if (info == NULL) { @@ -278,21 +309,72 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, return -EINVAL; } - switch (mode) { - case REGULATOR_MODE_NORMAL: - info->update_val = info->update_val_normal; - break; - case REGULATOR_MODE_IDLE: - info->update_val = info->update_val_idle; - break; - default: - return -EINVAL; + if (info->shared_mode) { + /* + * Special case where mode is shared between two regulators. + */ + struct ab8500_shared_mode *sm = info->shared_mode; + mutex_lock(&shared_mode_mutex); + + if (mode == REGULATOR_MODE_IDLE) { + sm->lp_mode_req = true; /* Low power mode requested */ + if (!((sm->shared_regulator)-> + shared_mode->lp_mode_req)) { + mutex_unlock(&shared_mode_mutex); + return 0; /* Other regulator prevent LP mode */ + } + } else { + sm->lp_mode_req = false; + } } - if (info->is_enabled) { + if (info->mode_mask) { + /* Dedicated register for handling mode */ + + dmr = true; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = info->mode_val_normal; + break; + case REGULATOR_MODE_IDLE: + val = info->mode_val_idle; + break; + default: + if (info->shared_mode) + mutex_unlock(&shared_mode_mutex); + return -EINVAL; + } + + bank = info->mode_bank; + reg = info->mode_reg; + mask = info->mode_mask; + } else { + /* Mode register same as enable register */ + + switch (mode) { + case REGULATOR_MODE_NORMAL: + info->update_val = info->update_val_normal; + val = info->update_val_normal; + break; + case REGULATOR_MODE_IDLE: + info->update_val = info->update_val_idle; + val = info->update_val_idle; + break; + default: + if (info->shared_mode) + mutex_unlock(&shared_mode_mutex); + return -EINVAL; + } + + bank = info->update_bank; + reg = info->update_reg; + mask = info->update_mask; + } + + if (info->is_enabled || dmr) { ret = abx500_mask_and_set_register_interruptible(info->dev, - info->update_bank, info->update_reg, - info->update_mask, info->update_val); + bank, reg, mask, val); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set regulator mode\n"); @@ -300,10 +382,13 @@ static int ab8500_regulator_set_mode(struct regulator_dev *rdev, dev_vdbg(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, info->update_val); + info->desc.name, bank, reg, + mask, val); } + if (info->shared_mode) + mutex_unlock(&shared_mode_mutex); + return ret; } @@ -311,15 +396,41 @@ static unsigned int ab8500_regulator_get_mode(struct regulator_dev *rdev) { struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); int ret; + u8 val; + u8 val_normal; + u8 val_idle; if (info == NULL) { dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; } - if (info->update_val == info->update_val_normal) + /* Need special handling for shared mode */ + if (info->shared_mode) { + if (info->shared_mode->lp_mode_req) + return REGULATOR_MODE_IDLE; + else + return REGULATOR_MODE_NORMAL; + } + + if (info->mode_mask) { + /* Dedicated register for handling mode */ + ret = abx500_get_register_interruptible(info->dev, + info->mode_bank, info->mode_reg, &val); + val = val & info->mode_mask; + + val_normal = info->mode_val_normal; + val_idle = info->mode_val_idle; + } else { + /* Mode register same as enable register */ + val = info->update_val; + val_normal = info->update_val_normal; + val_idle = info->update_val_idle; + } + + if (val == val_normal) ret = REGULATOR_MODE_NORMAL; - else if (info->update_val == info->update_val_idle) + else if (val == val_idle) ret = REGULATOR_MODE_IDLE; else ret = -EINVAL; @@ -574,6 +685,15 @@ static struct regulator_ops ab8500_regulator_ops = { .list_voltage = regulator_list_voltage_table, }; +static struct regulator_ops ab8500_regulator_anamic_mode_ops = { + .enable = ab8500_regulator_enable, + .disable = ab8500_regulator_disable, + .is_enabled = ab8500_regulator_is_enabled, + .set_mode = ab8500_regulator_set_mode, + .get_mode = ab8500_regulator_get_mode, + .list_voltage = regulator_list_voltage_table, +}; + /* AB8500 regulator information */ static struct ab8500_regulator_info ab8500_regulator_info[AB8500_NUM_REGULATORS] = { @@ -1005,32 +1125,44 @@ static struct ab8500_regulator_info [AB8505_LDO_ANAMIC1] = { .desc = { .name = "LDO-ANAMIC1", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_anamic_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8505_LDO_ANAMIC1, .owner = THIS_MODULE, .n_voltages = 1, .volt_table = fixed_2050000_voltage, }, + .shared_mode = &ldo_anamic1_shared, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x08, .update_val = 0x08, + .mode_bank = 0x01, + .mode_reg = 0x54, + .mode_mask = 0x04, + .mode_val_idle = 0x04, + .mode_val_normal = 0x00, }, [AB8505_LDO_ANAMIC2] = { .desc = { .name = "LDO-ANAMIC2", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_anamic_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8505_LDO_ANAMIC2, .owner = THIS_MODULE, .n_voltages = 1, .volt_table = fixed_2050000_voltage, }, + .shared_mode = &ldo_anamic2_shared, .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x10, .update_val = 0x10, + .mode_bank = 0x01, + .mode_reg = 0x54, + .mode_mask = 0x04, + .mode_val_idle = 0x04, + .mode_val_normal = 0x00, }, [AB8505_LDO_AUX8] = { .desc = { @@ -1570,6 +1702,14 @@ static struct ab8500_regulator_info }, }; +static struct ab8500_shared_mode ldo_anamic1_shared = { + .shared_regulator = &ab8505_regulator_info[AB8505_LDO_ANAMIC2], +}; + +static struct ab8500_shared_mode ldo_anamic2_shared = { + .shared_regulator = &ab8505_regulator_info[AB8505_LDO_ANAMIC1], +}; + struct ab8500_reg_init { u8 bank; u8 addr;