Skip to content

Commit

Permalink
mmc: Add mmc_vddrange_to_ocrmask() helper function
Browse files Browse the repository at this point in the history
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 <avorontsov@ru.mvista.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
  • Loading branch information
Anton Vorontsov authored and Pierre Ossman committed Dec 31, 2008
1 parent 0527a60 commit 86e8286
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
75 changes: 75 additions & 0 deletions drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/leds.h>
#include <linux/scatterlist.h>
#include <linux/log2.h>

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
Expand Down Expand Up @@ -448,6 +449,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
Expand Down
2 changes: 2 additions & 0 deletions include/linux/mmc/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 86e8286

Please sign in to comment.