From patchwork Wed Nov 26 19:54:17 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Vorontsov X-Patchwork-Id: 10977 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [127.0.0.1]) by ozlabs.org (Postfix) with ESMTP id 793E4DDF00 for ; Thu, 27 Nov 2008 06:55:26 +1100 (EST) X-Original-To: linuxppc-dev@ozlabs.org Delivered-To: linuxppc-dev@ozlabs.org Received: from buildserver.ru.mvista.com (unknown [85.21.88.6]) by ozlabs.org (Postfix) with ESMTP id 08AC3DDDE0 for ; Thu, 27 Nov 2008 06:54:21 +1100 (EST) Received: from localhost (unknown [10.150.0.9]) by buildserver.ru.mvista.com (Postfix) with ESMTP id C09198824; Thu, 27 Nov 2008 00:54:18 +0400 (SAMT) Date: Wed, 26 Nov 2008 22:54:17 +0300 From: Anton Vorontsov To: Pierre Ossman Subject: [PATCH v2] mmc: Add mmc_vddrange_to_ocrmask() helper function Message-ID: <20081126195417.GA26264@oksana.dev.rtsoft.ru> References: <20081030195546.GA30645@oksana.dev.rtsoft.ru> <20081030195632.GB13640@oksana.dev.rtsoft.ru> <20081108215537.12cdf5f6@mjolnir.drzeus.cx> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20081108215537.12cdf5f6@mjolnir.drzeus.cx> User-Agent: Mutt/1.5.18 (2008-05-17) Cc: linuxppc-dev@ozlabs.org, David Brownell , linux-kernel@vger.kernel.org X-BeenThere: linuxppc-dev@ozlabs.org X-Mailman-Version: 2.1.11 Precedence: list Reply-To: avorontsov@ru.mvista.com List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org This function sets the OCR mask bits according to provided voltage ranges. Will be used by the mmc_spi OpenFirmware bindings. Signed-off-by: Anton Vorontsov --- Hi Pierre, Sorry for the delay. On Sat, Nov 08, 2008 at 09:55:37PM +0100, Pierre Ossman wrote: > On Thu, 30 Oct 2008 22:56:32 +0300 > Anton Vorontsov wrote: > > > +/** > > + * mmc_vddrange_to_ocrmask - Convert a voltage range to the OCR mask > > + * @vdd_min: minimum voltage value (mV) > > + * @vdd_max: maximum voltage value (mV) > > + * @mask: pointer to the mask > > + * > > Why the pointer? Why not let the caller handle the aggregation? That > would be a lot safer. Yeah, makes sense. Now the function returns OCR mask, or 0 on error. > > + /* fill the mask, from max bit to min bit */ > > + while (vdd_max >= vdd_min) > > + *mask |= 1 << vdd_max--; > > + return 0; > > Many cards get a bit uppity with a single bit set. If possible, try to > make this function set two bits when the voltage is right on the > boundary (e.g. 3.3V). Something like this patch (the boundary cases are documented now)? p.s. If the patch is OK I'll respin the whole patchset. drivers/mmc/core/core.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/core.h | 2 + 2 files changed, 77 insertions(+), 0 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 044d84e..1673765 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -444,6 +445,80 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width) mmc_set_ios(host); } +/** + * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number + * @vdd: voltage (mV) + * @low_bits: prefer low bits in boundary cases + * + * This function returns the OCR bit number according to the provided @vdd + * value. If conversion is not possible a negative errno value returned. + * + * Depending on the @low_bits flag the function prefers low or high OCR bits + * on boundary voltages. For example, + * with @low_bits = true, 3300 mV translates to ilog2(MMC_VDD_32_33); + * with @low_bits = false, 3300 mV translates to ilog2(MMC_VDD_33_34); + * + * Any value in the [1951:1999] range translates to the ilog2(MMC_VDD_20_21). + */ +static int mmc_vdd_to_ocrbitnum(int vdd, bool low_bits) +{ + const int max_bit = ilog2(MMC_VDD_35_36); + int bit; + + if (vdd < 1650 || vdd > 3600) + return -EINVAL; + + if (vdd >= 1650 && vdd <= 1950) + return ilog2(MMC_VDD_165_195); + + if (low_bits) + vdd -= 1; + + /* Base 2000 mV, step 100 mV, bit's base 8. */ + bit = (vdd - 2000) / 100 + 8; + if (bit > max_bit) + return max_bit; + return bit; +} + +/** + * mmc_vddrange_to_ocrmask - Convert a voltage range to the OCR mask + * @vdd_min: minimum voltage value (mV) + * @vdd_max: maximum voltage value (mV) + * + * This function returns the OCR mask bits according to the provided @vdd_min + * and @vdd_max values. If conversion is not possible the function returns 0. + * + * Notes wrt boundary cases: + * This function sets the OCR bits for all boundary voltages, for example + * [3300:3400] range is translated to MMC_VDD_32_33 | MMC_VDD_33_34 | + * MMC_VDD_34_35 mask. + */ +u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max) +{ + u32 mask = 0; + + if (vdd_max < vdd_min) + return 0; + + /* Prefer high bits for the boundary vdd_max values. */ + vdd_max = mmc_vdd_to_ocrbitnum(vdd_max, false); + if (vdd_max < 0) + return 0; + + /* Prefer low bits for the boundary vdd_min values. */ + vdd_min = mmc_vdd_to_ocrbitnum(vdd_min, true); + if (vdd_min < 0) + return 0; + + /* Fill the mask, from max bit to min bit. */ + while (vdd_max >= vdd_min) + mask |= 1 << vdd_max--; + + return mask; +} +EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); + /* * Mask off any voltages we don't support and select * the lowest voltage diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 143cebf..7ac8b50 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -151,4 +151,6 @@ static inline void mmc_claim_host(struct mmc_host *host) __mmc_claim_host(host, NULL); } +extern u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max); + #endif