Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MMC: regulator utilities

Glue between MMC and regulator stacks ... verified with
some OMAP3 boards using adjustable and configured-as-fixed
regulators on several MMC controllers.

These calls are intended to be used by MMC host adapters
using at least one regulator per host. Examples include
slots with regulators supporting multiple voltages and
ones using multiple voltage rails (e.g. DAT4..DAT7 using a
separate supply, or a split rail chip like certain SDIO
WLAN or eMMC solutions).

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Acked-by: Pierre Ossman <drzeus@drzeus.cx>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>

authored by

David Brownell and committed by
Liam Girdwood
5c13941a 66b659e6

+105
+100
drivers/mmc/core/core.c
··· 21 21 #include <linux/leds.h> 22 22 #include <linux/scatterlist.h> 23 23 #include <linux/log2.h> 24 + #include <linux/regulator/consumer.h> 24 25 25 26 #include <linux/mmc/card.h> 26 27 #include <linux/mmc/host.h> ··· 523 522 return mask; 524 523 } 525 524 EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); 525 + 526 + #ifdef CONFIG_REGULATOR 527 + 528 + /** 529 + * mmc_regulator_get_ocrmask - return mask of supported voltages 530 + * @supply: regulator to use 531 + * 532 + * This returns either a negative errno, or a mask of voltages that 533 + * can be provided to MMC/SD/SDIO devices using the specified voltage 534 + * regulator. This would normally be called before registering the 535 + * MMC host adapter. 536 + */ 537 + int mmc_regulator_get_ocrmask(struct regulator *supply) 538 + { 539 + int result = 0; 540 + int count; 541 + int i; 542 + 543 + count = regulator_count_voltages(supply); 544 + if (count < 0) 545 + return count; 546 + 547 + for (i = 0; i < count; i++) { 548 + int vdd_uV; 549 + int vdd_mV; 550 + 551 + vdd_uV = regulator_list_voltage(supply, i); 552 + if (vdd_uV <= 0) 553 + continue; 554 + 555 + vdd_mV = vdd_uV / 1000; 556 + result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV); 557 + } 558 + 559 + return result; 560 + } 561 + EXPORT_SYMBOL(mmc_regulator_get_ocrmask); 562 + 563 + /** 564 + * mmc_regulator_set_ocr - set regulator to match host->ios voltage 565 + * @vdd_bit: zero for power off, else a bit number (host->ios.vdd) 566 + * @supply: regulator to use 567 + * 568 + * Returns zero on success, else negative errno. 569 + * 570 + * MMC host drivers may use this to enable or disable a regulator using 571 + * a particular supply voltage. This would normally be called from the 572 + * set_ios() method. 573 + */ 574 + int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit) 575 + { 576 + int result = 0; 577 + int min_uV, max_uV; 578 + int enabled; 579 + 580 + enabled = regulator_is_enabled(supply); 581 + if (enabled < 0) 582 + return enabled; 583 + 584 + if (vdd_bit) { 585 + int tmp; 586 + int voltage; 587 + 588 + /* REVISIT mmc_vddrange_to_ocrmask() may have set some 589 + * bits this regulator doesn't quite support ... don't 590 + * be too picky, most cards and regulators are OK with 591 + * a 0.1V range goof (it's a small error percentage). 592 + */ 593 + tmp = vdd_bit - ilog2(MMC_VDD_165_195); 594 + if (tmp == 0) { 595 + min_uV = 1650 * 1000; 596 + max_uV = 1950 * 1000; 597 + } else { 598 + min_uV = 1900 * 1000 + tmp * 100 * 1000; 599 + max_uV = min_uV + 100 * 1000; 600 + } 601 + 602 + /* avoid needless changes to this voltage; the regulator 603 + * might not allow this operation 604 + */ 605 + voltage = regulator_get_voltage(supply); 606 + if (voltage < 0) 607 + result = voltage; 608 + else if (voltage < min_uV || voltage > max_uV) 609 + result = regulator_set_voltage(supply, min_uV, max_uV); 610 + else 611 + result = 0; 612 + 613 + if (result == 0 && !enabled) 614 + result = regulator_enable(supply); 615 + } else if (enabled) { 616 + result = regulator_disable(supply); 617 + } 618 + 619 + return result; 620 + } 621 + EXPORT_SYMBOL(mmc_regulator_set_ocr); 622 + 623 + #endif 526 624 527 625 /* 528 626 * Mask off any voltages we don't support and select
+5
include/linux/mmc/host.h
··· 192 192 wake_up_process(host->sdio_irq_thread); 193 193 } 194 194 195 + struct regulator; 196 + 197 + int mmc_regulator_get_ocrmask(struct regulator *supply); 198 + int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit); 199 + 195 200 #endif 196 201