diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-02 11:40:22 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-02 11:40:22 -0800 |
| commit | 17a1359034e1fb5cfe9e5196a8ab5153acfacdc6 (patch) | |
| tree | e9b12d256183b9cbf4d95fbd5628cba725c7e531 /drivers | |
| parent | 66b019967845a5af58802fd9af77f2317e5298a1 (diff) | |
| parent | 7cc8d580228cc712edcf7a1856a3bdb38c164e83 (diff) | |
| download | linux-17a1359034e1fb5cfe9e5196a8ab5153acfacdc6.tar.gz linux-17a1359034e1fb5cfe9e5196a8ab5153acfacdc6.tar.bz2 linux-17a1359034e1fb5cfe9e5196a8ab5153acfacdc6.zip | |
Merge tag 'mmc-v4.4' of git://git.linaro.org/people/ulf.hansson/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Add new API to set VCCQ voltage - mmc_regulator_set_vqmmc()
- Add new ioctl to allow userspace to send multi commands
- Wait for card busy signalling before starting SDIO requests
- Remove MMC_CLKGATE
- Enable tuning for DDR50 mode
- Some code clean-up/improvements to mmc pwrseq
- Use highest priority for eMMC restart handler
- Add DT bindings for eMMC hardware reset support
- Extend the mmc_send_tuning() API
- Improve ios show for debugfs
- A couple of code optimizations
MMC host:
- Some generic OF improvements
- Various code clean-ups
- sirf: Add support for DDR50
- sunxi: Add support for card busy detection
- mediatek: Use MMC_CAP_RUNTIME_RESUME
- mediatek: Add support for eMMC HW-reset
- mediatek: Add support for HS400
- dw_mmc: Convert to use the new mmc_regulator_set_vqmmc() API
- dw_mmc: Add external DMA interface support
- dw_mmc: Some various improvements
- dw_mmc-rockchip: MMC tuning with the clock phase framework
- sdhci: Properly clear IRQs during resume
- sdhci: Enable tuning for DDR50 mode
- sdhci-of-esdhc: Use IRQ mode for card detection
- sdhci-of-esdhc: Support both BE and LE host controller
- sdhci-pci: Build o2micro support in the same module
- sdhci-pci: Support for new Intel host controllers
- sdhci-acpi: Support for new Intel host controllers"
* tag 'mmc-v4.4' of git://git.linaro.org/people/ulf.hansson/mmc: (73 commits)
mmc: dw_mmc: fix the wrong setting for UHS-DDR50 mode
mmc: dw_mmc: fix the CardThreshold boundary at CardThrCtl register
mmc: dw_mmc: NULL dereference in error message
mmc: pwrseq: Use highest priority for eMMC restart handler
mmc: mediatek: add HS400 support
mmc: mmc: extend the mmc_send_tuning()
mmc: mediatek: add implement of ops->hw_reset()
mmc: mediatek: fix got GPD checksum error interrupt when data transfer
mmc: mediatek: change the argument "ddr" to "timing"
mmc: mediatek: make cmd_ints_mask to const
mmc: dt-bindings: update Mediatek MMC bindings
mmc: core: Add DT bindings for eMMC hardware reset support
mmc: omap_hsmmc: Enable omap_hsmmc for Keystone 2
mmc: sdhci-acpi: Add more ACPI HIDs for Intel controllers
mmc: sdhci-pci: Add more PCI IDs for Intel controllers
arm: lpc18xx_defconfig: remove CONFIG_MMC_DW_IDMAC
arm: hisi_defconfig: remove CONFIG_MMC_DW_IDMAC
arm: exynos_defconfig: remove CONFIG_MMC_DW_IDMAC
arc: axs10x_defconfig: remove CONFIG_MMC_DW_IDMAC
mips: pistachio_defconfig: remove CONFIG_MMC_DW_IDMAC
...
Diffstat (limited to 'drivers')
45 files changed, 1578 insertions, 842 deletions
diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index 9b613426e968..bc24e5a002e7 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -45,8 +45,8 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw, #define PSECS_PER_SEC 1000000000000LL /* - * Each fine delay is between 40ps-80ps. Assume each fine delay is 60ps to - * simplify calculations. So 45degs could be anywhere between 33deg and 66deg. + * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to + * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. */ #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 @@ -69,7 +69,7 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw) delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; - degrees += delay_num * factor / 10000; + degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000); } return degrees % 360; @@ -82,25 +82,41 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees) u8 nineties, remainder; u8 delay_num; u32 raw_value; - u64 delay; - - /* allow 22 to be 22.5 */ - degrees++; - /* floor to 22.5 increment */ - degrees -= ((degrees) * 10 % 225) / 10; + u32 delay; nineties = degrees / 90; - /* 22.5 multiples */ - remainder = (degrees % 90) / 22; - - delay = PSECS_PER_SEC; - do_div(delay, rate); - /* / 360 / 22.5 */ - do_div(delay, 16); - do_div(delay, ROCKCHIP_MMC_DELAY_ELEMENT_PSEC); - + remainder = (degrees % 90); + + /* + * Due to the inexact nature of the "fine" delay, we might + * actually go non-monotonic. We don't go _too_ monotonic + * though, so we should be OK. Here are options of how we may + * work: + * + * Ideally we end up with: + * 1.0, 2.0, ..., 69.0, 70.0, ..., 89.0, 90.0 + * + * On one extreme (if delay is actually 44ps): + * .73, 1.5, ..., 50.6, 51.3, ..., 65.3, 90.0 + * The other (if delay is actually 77ps): + * 1.3, 2.6, ..., 88.6. 89.8, ..., 114.0, 90 + * + * It's possible we might make a delay that is up to 25 + * degrees off from what we think we're making. That's OK + * though because we should be REALLY far from any bad range. + */ + + /* + * Convert to delay; do a little extra work to make sure we + * don't overflow 32-bit / 64-bit numbers. + */ + delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ delay *= remainder; - delay_num = (u8) min(delay, 255ULL); + delay = DIV_ROUND_CLOSEST(delay, + (rate / 1000) * 36 * + (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); + + delay_num = (u8) min_t(u32, delay, 255); raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c742cfd7674e..23b6c8e8701c 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -387,6 +387,24 @@ out: return ERR_PTR(err); } +static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr, + struct mmc_blk_ioc_data *idata) +{ + struct mmc_ioc_cmd *ic = &idata->ic; + + if (copy_to_user(&(ic_ptr->response), ic->response, + sizeof(ic->response))) + return -EFAULT; + + if (!idata->ic.write_flag) { + if (copy_to_user((void __user *)(unsigned long)ic->data_ptr, + idata->buf, idata->buf_bytes)) + return -EFAULT; + } + + return 0; +} + static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, u32 retries_max) { @@ -447,12 +465,9 @@ out: return err; } -static int mmc_blk_ioctl_cmd(struct block_device *bdev, - struct mmc_ioc_cmd __user *ic_ptr) +static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, + struct mmc_blk_ioc_data *idata) { - struct mmc_blk_ioc_data *idata; - struct mmc_blk_data *md; - struct mmc_card *card; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct mmc_request mrq = {NULL}; @@ -461,33 +476,12 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, int is_rpmb = false; u32 status = 0; - /* - * The caller must have CAP_SYS_RAWIO, and must be calling this on the - * whole block device, not on a partition. This prevents overspray - * between sibling partitions. - */ - if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) - return -EPERM; - - idata = mmc_blk_ioctl_copy_from_user(ic_ptr); - if (IS_ERR(idata)) - return PTR_ERR(idata); - - md = mmc_blk_get(bdev->bd_disk); - if (!md) { - err = -EINVAL; - goto cmd_err; - } + if (!card || !md || !idata) + return -EINVAL; if (md->area_type & MMC_BLK_DATA_AREA_RPMB) is_rpmb = true; - card = md->queue.card; - if (IS_ERR(card)) { - err = PTR_ERR(card); - goto cmd_done; - } - cmd.opcode = idata->ic.opcode; cmd.arg = idata->ic.arg; cmd.flags = idata->ic.flags; @@ -530,23 +524,21 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, mrq.cmd = &cmd; - mmc_get_card(card); - err = mmc_blk_part_switch(card, md); if (err) - goto cmd_rel_host; + return err; if (idata->ic.is_acmd) { err = mmc_app_cmd(card->host, card); if (err) - goto cmd_rel_host; + return err; } if (is_rpmb) { err = mmc_set_blockcount(card, data.blocks, idata->ic.write_flag & (1 << 31)); if (err) - goto cmd_rel_host; + return err; } if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) && @@ -557,7 +549,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, pr_err("%s: ioctl_do_sanitize() failed. err = %d", __func__, err); - goto cmd_rel_host; + return err; } mmc_wait_for_req(card->host, &mrq); @@ -565,14 +557,12 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, if (cmd.error) { dev_err(mmc_dev(card->host), "%s: cmd error %d\n", __func__, cmd.error); - err = cmd.error; - goto cmd_rel_host; + return cmd.error; } if (data.error) { dev_err(mmc_dev(card->host), "%s: data error %d\n", __func__, data.error); - err = data.error; - goto cmd_rel_host; + return data.error; } /* @@ -582,18 +572,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, if (idata->ic.postsleep_min_us) usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us); - if (copy_to_user(&(ic_ptr->response), cmd.resp, sizeof(cmd.resp))) { - err = -EFAULT; - goto cmd_rel_host; - } - - if (!idata->ic.write_flag) { - if (copy_to_user((void __user *)(unsigned long) idata->ic.data_ptr, - idata->buf, idata->buf_bytes)) { - err = -EFAULT; - goto cmd_rel_host; - } - } + memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); if (is_rpmb) { /* @@ -607,24 +586,132 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, __func__, status, err); } -cmd_rel_host: + return err; +} + +static int mmc_blk_ioctl_cmd(struct block_device *bdev, + struct mmc_ioc_cmd __user *ic_ptr) +{ + struct mmc_blk_ioc_data *idata; + struct mmc_blk_data *md; + struct mmc_card *card; + int err = 0, ioc_err = 0; + + idata = mmc_blk_ioctl_copy_from_user(ic_ptr); + if (IS_ERR(idata)) + return PTR_ERR(idata); + + md = mmc_blk_get(bdev->bd_disk); + if (!md) { + err = -EINVAL; + goto cmd_err; + } + + card = md->queue.card; + if (IS_ERR(card)) { + err = PTR_ERR(card); + goto cmd_done; + } + + mmc_get_card(card); + + ioc_err = __mmc_blk_ioctl_cmd(card, md, idata); + mmc_put_card(card); + err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); + cmd_done: mmc_blk_put(md); cmd_err: kfree(idata->buf); kfree(idata); - return err; + return ioc_err ? ioc_err : err; +} + +static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, + struct mmc_ioc_multi_cmd __user *user) +{ + struct mmc_blk_ioc_data **idata = NULL; + struct mmc_ioc_cmd __user *cmds = user->cmds; + struct mmc_card *card; + struct mmc_blk_data *md; + int i, err = 0, ioc_err = 0; + __u64 num_of_cmds; + + if (copy_from_user(&num_of_cmds, &user->num_of_cmds, + sizeof(num_of_cmds))) + return -EFAULT; + + if (num_of_cmds > MMC_IOC_MAX_CMDS) + return -EINVAL; + + idata = kcalloc(num_of_cmds, sizeof(*idata), GFP_KERNEL); + if (!idata) + return -ENOMEM; + + for (i = 0; i < num_of_cmds; i++) { + idata[i] = mmc_blk_ioctl_copy_from_user(&cmds[i]); + if (IS_ERR(idata[i])) { + err = PTR_ERR(idata[i]); + num_of_cmds = i; + goto cmd_err; + } + } + + md = mmc_blk_get(bdev->bd_disk); + if (!md) + goto cmd_err; + + card = md->queue.card; + if (IS_ERR(card)) { + err = PTR_ERR(card); + goto cmd_done; + } + + mmc_get_card(card); + + for (i = 0; i < num_of_cmds && !ioc_err; i++) + ioc_err = __mmc_blk_ioctl_cmd(card, md, idata[i]); + + mmc_put_card(card); + + /* copy to user if data and response */ + for (i = 0; i < num_of_cmds && !err; i++) + err = mmc_blk_ioctl_copy_to_user(&cmds[i], idata[i]); + +cmd_done: + mmc_blk_put(md); +cmd_err: + for (i = 0; i < num_of_cmds; i++) { + kfree(idata[i]->buf); + kfree(idata[i]); + } + kfree(idata); + return ioc_err ? ioc_err : err; } static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - int ret = -EINVAL; - if (cmd == MMC_IOC_CMD) - ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg); - return ret; + /* + * The caller must have CAP_SYS_RAWIO, and must be calling this on the + * whole block device, not on a partition. This prevents overspray + * between sibling partitions. + */ + if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) + return -EPERM; + + switch (cmd) { + case MMC_IOC_CMD: + return mmc_blk_ioctl_cmd(bdev, + (struct mmc_ioc_cmd __user *)arg); + case MMC_IOC_MULTI_CMD: + return mmc_blk_ioctl_multi_cmd(bdev, + (struct mmc_ioc_multi_cmd __user *)arg); + default: + return -EINVAL; + } } #ifdef CONFIG_COMPAT diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 9ebee72d9c3f..4c33d7690f2f 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -1,13 +1,3 @@ # # MMC core configuration # - -config MMC_CLKGATE - bool "MMC host clock gating" - help - This will attempt to aggressively gate the clock to the MMC card. - This is done to save power due to gating off the logic and bus - noise when the MMC card is not in use. Your host driver has to - support handling this in order for it to be of any use. - - If unsure, say N. diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index a3eb20bdcd97..5ae89e48fd85 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -187,8 +187,6 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) if (mrq->done) mrq->done(mrq); - - mmc_host_clk_release(host); } } @@ -206,6 +204,23 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) return; } + /* + * For sdio rw commands we must wait for card busy otherwise some + * sdio devices won't work properly. + */ + if (mmc_is_io_op(mrq->cmd->opcode) && host->ops->card_busy) { + int tries = 500; /* Wait aprox 500ms at maximum */ + + while (host->ops->card_busy(host) && --tries) + mmc_delay(1); + + if (tries == 0) { + mrq->cmd->error = -EBUSY; + mmc_request_done(host, mrq); + return; + } + } + host->ops->request(host, mrq); } @@ -275,7 +290,6 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->stop->mrq = mrq; } } - mmc_host_clk_hold(host); led_trigger_event(host->led, LED_FULL); __mmc_start_request(host, mrq); @@ -525,11 +539,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host, static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, bool is_first_req) { - if (host->ops->pre_req) { - mmc_host_clk_hold(host); + if (host->ops->pre_req) host->ops->pre_req(host, mrq, is_first_req); - mmc_host_clk_release(host); - } } /** @@ -544,11 +555,8 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq, static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq, int err) { - if (host->ops->post_req) { - mmc_host_clk_hold(host); + if (host->ops->post_req) host->ops->post_req(host, mrq, err); - mmc_host_clk_release(host); - } } /** @@ -833,9 +841,9 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) unsigned int timeout_us, limit_us; timeout_us = data->timeout_ns / 1000; - if (mmc_host_clk_rate(card->host)) + if (card->host->ios.clock) timeout_us += data->timeout_clks * 1000 / - (mmc_host_clk_rate(card->host) / 1000); + (card->host->ios.clock / 1000); if (data->flags & MMC_DATA_WRITE) /* @@ -1033,8 +1041,6 @@ static inline void mmc_set_ios(struct mmc_host *host) ios->power_mode, ios->chip_select, ios->vdd, ios->bus_width, ios->timing); - if (ios->clock > 0) - mmc_set_ungated(host); host->ops->set_ios(host, ios); } @@ -1043,17 +1049,15 @@ static inline void mmc_set_ios(struct mmc_host *host) */ void mmc_set_chip_select(struct mmc_host *host, int mode) { - mmc_host_clk_hold(host); host->ios.chip_select = mode; mmc_set_ios(host); - mmc_host_clk_release(host); } /* * Sets the host clock to the highest possible frequency that * is below "hz". */ -static void __mmc_set_clock(struct mmc_host *host, unsigned int hz) +void mmc_set_clock(struct mmc_host *host, unsigned int hz) { WARN_ON(hz && hz < host->f_min); @@ -1064,68 +1068,6 @@ static void __mmc_set_clock(struct mmc_host *host, unsigned int hz) mmc_set_ios(host); } -void mmc_set_clock(struct mmc_host *host, unsigned int hz) -{ - mmc_host_clk_hold(host); - __mmc_set_clock(host, hz); - mmc_host_clk_release(host); -} - -#ifdef CONFIG_MMC_CLKGATE -/* - * This gates the clock by setting it to 0 Hz. - */ -void mmc_gate_clock(struct mmc_host *host) -{ - unsigned long flags; - - spin_lock_irqsave(&host->clk_lock, flags); - host->clk_old = host->ios.clock; - host->ios.clock = 0; - host->clk_gated = true; - spin_unlock_irqrestore(&host->clk_lock, flags); - mmc_set_ios(host); -} - -/* - * This restores the clock from gating by using the cached - * clock value. - */ -void mmc_ungate_clock(struct mmc_host *host) -{ - /* - * We should previously have gated the clock, so the clock shall - * be 0 here! The clock may however be 0 during initialization, - * when some request operations are performed before setting - * the frequency. When ungate is requested in that situation - * we just ignore the call. - */ - if (host->clk_old) { - BUG_ON(host->ios.clock); - /* This call will also set host->clk_gated to false */ - __mmc_set_clock(host, host->clk_old); - } -} - -void mmc_set_ungated(struct mmc_host *host) -{ - unsigned long flags; - - /* - * We've been given a new frequency while the clock is gated, - * so make sure we regard this as ungating it. - */ - spin_lock_irqsave(&host->clk_lock, flags); - host->clk_gated = false; - spin_unlock_irqrestore(&host->clk_lock, flags); -} - -#else -void mmc_set_ungated(struct mmc_host *host) -{ -} -#endif - int mmc_execute_tuning(struct mmc_card *card) { struct mmc_host *host = card->host; @@ -1140,9 +1082,7 @@ int mmc_execute_tuning(struct mmc_card *card) else opcode = MMC_SEND_TUNING_BLOCK; - mmc_host_clk_hold(host); err = host->ops->execute_tuning(host, opcode); - mmc_host_clk_release(host); if (err) pr_err("%s: tuning execution failed\n", mmc_hostname(host)); @@ -1157,10 +1097,8 @@ int mmc_execute_tuning(struct mmc_card *card) */ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) { - mmc_host_clk_hold(host); host->ios.bus_mode = mode; mmc_set_ios(host); - mmc_host_clk_release(host); } /* @@ -1168,10 +1106,8 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) */ void mmc_set_bus_width(struct mmc_host *host, unsigned int width) { - mmc_host_clk_hold(host); host->ios.bus_width = width; mmc_set_ios(host); - mmc_host_clk_release(host); } /* @@ -1341,6 +1277,40 @@ struct device_node *mmc_of_find_child_device(struct mmc_host *host, #ifdef CONFIG_REGULATOR /** + * mmc_ocrbitnum_to_vdd - Convert a OCR bit number to its voltage + * @vdd_bit: OCR bit number + * @min_uV: minimum voltage value (mV) + * @max_uV: maximum voltage value (mV) + * + * This function returns the voltage range according to the provided OCR + * bit number. If conversion is not possible a negative errno value returned. + */ +static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV) +{ + int tmp; + + if (!vdd_bit) + return -EINVAL; + + /* + * REVISIT mmc_vddrange_to_ocrmask() may have set some + * bits this regulator doesn't quite support ... don't + * be too picky, most cards and regulators are OK with + * a 0.1V range goof (it's a small error percentage). + */ + tmp = vdd_bit - ilog2(MMC_VDD_165_195); + if (tmp == 0) { + *min_uV = 1650 * 1000; + *max_uV = 1950 * 1000; + } else { + *min_uV = 1900 * 1000 + tmp * 100 * 1000; + *max_uV = *min_uV + 100 * 1000; + } + + return 0; +} + +/** * mmc_regulator_get_ocrmask - return mask of supported voltages * @supply: regulator to use * @@ -1403,22 +1373,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, int min_uV, max_uV; if (vdd_bit) { - int tmp; - - /* - * REVISIT mmc_vddrange_to_ocrmask() may have set some - * bits this regulator doesn't quite support ... don't - * be too picky, most cards and regulators are OK with - * a 0.1V range goof (it's a small error percentage). - */ - tmp = vdd_bit - ilog2(MMC_VDD_165_195); - if (tmp == 0) { - min_uV = 1650 * 1000; - max_uV = 1950 * 1000; - } else { - min_uV = 1900 * 1000 + tmp * 100 * 1000; - max_uV = min_uV + 100 * 1000; - } + mmc_ocrbitnum_to_vdd(vdd_bit, &min_uV, &max_uV); result = regulator_set_voltage(supply, min_uV, max_uV); if (result == 0 && !mmc->regulator_enabled) { @@ -1439,6 +1394,84 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc, } EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr); +static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator, + int min_uV, int target_uV, + int max_uV) +{ + /* + * Check if supported first to avoid errors since we may try several + * signal levels during power up and don't want to show errors. + */ + if (!regulator_is_supported_voltage(regulator, min_uV, max_uV)) + return -EINVAL; + + return regulator_set_voltage_triplet(regulator, min_uV, target_uV, + max_uV); +} + +/** + * mmc_regulator_set_vqmmc - Set VQMMC as per the ios + * + * For 3.3V signaling, we try to match VQMMC to VMMC as closely as possible. + * That will match the behavior of old boards where VQMMC and VMMC were supplied + * by the same supply. The Bus Operating conditions for 3.3V signaling in the + * SD card spec also define VQMMC in terms of VMMC. + * If this is not possible we'll try the full 2.7-3.6V of the spec. + * + * For 1.2V and 1.8V signaling we'll try to get as close as possible to the + * requested voltage. This is definitely a good idea for UHS where there's a + * separate regulator on the card that's trying to make 1.8V and it's best if + * we match. + * + * This function is expected to be used by a controller's + * start_signal_voltage_switch() function. |
