From patchwork Wed Dec 10 20:58:02 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 5472351 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id AB8E79F444 for ; Wed, 10 Dec 2014 21:01:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B6F4F2018E for ; Wed, 10 Dec 2014 21:01:23 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B46AE2017D for ; Wed, 10 Dec 2014 21:01:22 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XyoLc-0005Ed-4J; Wed, 10 Dec 2014 20:59:00 +0000 Received: from mail-ie0-x234.google.com ([2607:f8b0:4001:c03::234]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XyoLQ-0004yz-4M for linux-arm-kernel@lists.infradead.org; Wed, 10 Dec 2014 20:58:49 +0000 Received: by mail-ie0-f180.google.com with SMTP id rp18so3555749iec.11 for ; Wed, 10 Dec 2014 12:58:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id; bh=tgbz3kUnYpWAipZHxllCrvNoD9uDzG+feb7fBtLW+XA=; b=IbznoRbRLXUHOKkzQsMaQjtMWO01m8Ltdnu4ZUCnkLd7Ug61c6iaKvV7QwX2xPDns0 qpALQgSck0Vv333GyDh7RwjEfByiW5VG+kv2yTBlcoy2ajlNR+g5caC5SwbQq104Mafp kH+5mWFjv/XK8PpZEDYvho5j9/B1FQS5s10K8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=tgbz3kUnYpWAipZHxllCrvNoD9uDzG+feb7fBtLW+XA=; b=l14saQgcvH/W3Z3y9HG9AQnljF5Hdt5ys4xDIv2sZZnVdojp5dSk9VHdVRsZBkJWfC Z+RKgBA5CaiS9kuuSNwcrNClMP1DeKGhnIOmmN4mBvY3Wg0ketGVJ/xbJiTR6m12sCLp S/EPjSzsaAPYWAF4bvEt1PTFUOIo+deiSWhUDu0wKQsXOyGArRBcNNES0mNvOF7Bl8vv R/vmxrF9JW+/sI9LRc5mEaQPNNaDMgGKuEDKwmmKV9Qf3PA/3ER7wJhP0Hra3k0p0lHn XZyHso+c5cbuiQ++ES700w4LZWhDoBrvcAGRjzJtXpp7A37B5TlD6VY0ffN6cZC4cmny W+Aw== X-Gm-Message-State: ALoCoQkBiSbtzifeklFB610yuFSdfRNi3kxppRfsd7lCx1EW2gu8+7YBX8+d2moJLKqJC8CHGQyP X-Received: by 10.50.73.228 with SMTP id o4mr10115762igv.15.1418245106896; Wed, 10 Dec 2014 12:58:26 -0800 (PST) Received: from tictac.mtv.corp.google.com ([172.22.65.76]) by mx.google.com with ESMTPSA id m15sm2091454iom.44.2014.12.10.12.58.25 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 10 Dec 2014 12:58:26 -0800 (PST) From: Doug Anderson To: Ulf Hansson , Mark Brown , Heiko Stuebner , Jaehoon Chung , Seungwon Jeon Subject: [PATCH 1/4] regulator: core: Support trying to get close to a certain voltage Date: Wed, 10 Dec 2014 12:58:02 -0800 Message-Id: <1418245085-9754-1-git-send-email-dianders@chromium.org> X-Mailer: git-send-email 2.2.0.rc0.207.ga3a616c X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20141210_125848_259905_2F177B41 X-CRM114-Status: GOOD ( 17.97 ) X-Spam-Score: -0.8 (/) Cc: Alexandru Stan , Andrew Bresticker , linux-kernel@vger.kernel.org, Doug Anderson , lgirdwood@gmail.com, linux-rockchip@lists.infradead.org, Alim Akhtar , Sonny Rao , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP There are some cases where you'd like to set a voltage for a regulator and a range of voltages are OK, but you'd really like to get as close as you can to a specific voltage if at all possible. The VQMMC (IO voltage) regulator for SD cards is the inspiration for needing this function. A few things about SD cards to justify its need: 1. In old systems (before UHS), the VMMC and VQMMC were provided by the same regulator. That means that SD cards were all tested with VMMC and VQMMC being exactly the same. With UHS we need to have two regulators providing VMMC and VQMMC. For maximum compatibility, we'd like to keep those two regulators providing the exact same voltage when we're using "3.3V signaling". Note: VMMC is managed with very specific rules in the MMC core and we tend to pick the _highest_ supported voltage in range. 2. On UHS systems we'll eventually negotiate the IO voltage (VQMMC) down to 1.8V. Note that we don't provide a 1.8V reference voltage to the SD card so it comes up with 1.8V on its own based on VMMC (perhaps using an on-card LDO). While the SD card spec says that VQMMC can be 1.7V to 1.95V, it seems best to try to get the closest voltage. Trying to achieve 1.8V means that the card and controller drive the IO lines (which are push-pull) with as close to the same voltage as possible. Signed-off-by: Doug Anderson --- drivers/regulator/core.c | 62 ++++++++++++++++++++++++++++++++++++++ include/linux/regulator/consumer.h | 9 ++++++ 2 files changed, 71 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e225711..ce91b20 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2664,6 +2664,68 @@ out2: EXPORT_SYMBOL_GPL(regulator_set_voltage); /** + * regulator_set_closest_voltage - set voltage trying to reach a certain one. + * @regulator: regulator source + * @min_uV: Minimum required voltage in uV + * @ideal_uV: Try to get as close to this voltage as possible + * @max_uV: Maximum acceptable voltage in uV + * + * This function is useful in cases where we want to try to get as close to + * a target voltage as possible but we would accept other voltages as fallback. + */ +int regulator_set_closest_voltage(struct regulator *regulator, int min_uV, + int ideal_uV, int max_uV) +{ + int best_uV, delta, best_delta; + int i, voltages, ret; + struct regulator_dev *rdev = regulator->rdev; + + if (ideal_uV < min_uV || ideal_uV > max_uV) + return -EINVAL; + + /* Handle continuous ranges */ + if (rdev->desc->continuous_voltage_range) { + min_uV = max(min_uV, rdev->constraints->min_uV); + max_uV = min(max_uV, rdev->constraints->max_uV); + + if (min_uV > max_uV) + return -EINVAL; + + best_uV = min(max(ideal_uV, min_uV), max_uV); + return regulator_set_voltage(regulator, best_uV, best_uV); + } + + ret = regulator_count_voltages(regulator); + if (ret < 0) + return ret; + voltages = ret; + + best_uV = 0; + best_delta = INT_MAX; + for (i = 0; i < voltages; i++) { + ret = regulator_list_voltage(regulator, i); + + if (ret < min_uV || ret > max_uV) + continue; + + delta = ideal_uV - ret; + delta = abs(delta); + + if (delta < best_delta) { + best_delta = delta; + best_uV = ret; + } + } + + /* If no voltages, let regulator_set_voltage() decide if we're OK */ + if (best_uV == 0) + return regulator_set_voltage(regulator, min_uV, max_uV); + + return regulator_set_voltage(regulator, best_uV, best_uV); +} +EXPORT_SYMBOL_GPL(regulator_set_closest_voltage); + +/** * regulator_set_voltage_time - get raise/fall time * @regulator: regulator source * @old_uV: starting voltage in microvolts diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index d17e1ff..71c9ec2 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -228,6 +228,8 @@ int regulator_is_supported_voltage(struct regulator *regulator, int min_uV, int max_uV); unsigned int regulator_get_linear_step(struct regulator *regulator); int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV); +int regulator_set_closest_voltage(struct regulator *regulator, int min_uV, + int ideal_uV, int max_uV); int regulator_set_voltage_time(struct regulator *regulator, int old_uV, int new_uV); int regulator_get_voltage(struct regulator *regulator); @@ -440,6 +442,13 @@ static inline int regulator_set_voltage(struct regulator *regulator, return 0; } +static inline int regulator_set_closest_voltage(struct regulator *regulator, + int min_uV, int ideal_uV, + int max_uV) +{ + return 0; +} + static inline int regulator_set_voltage_time(struct regulator *regulator, int old_uV, int new_uV) {