mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
MMC core:
- Improve RPMB frame handling code
- Add support for a new max-sd-hs-hz DT property to limit frequency
- Add support to manage regulator-under-voltage events
- Support regulator-under-voltage for eMMC to mitigate data corruptions
- Add mmc_read_tuning() to allow a host to validate its tuning sequence
- Add some helpers to align checks for CMD23 support
- Read the CCCR register for SDIO over SPI rather than the unsupported CMD7
MMC host:
- Add COMPILE_TEST option for a couple of drivers
- Convert drivers to use the modern PM macros
- dw_mmc-exynos: Enable support for the Exynos8890 variant
- mmc_spi: Don't use crc ack during multiple block read
- renesas_sdhi: Enable 64-bit polling mode for R-Car gen3 and RZ/G2L SoCs
- rtsx_usb: Add support for over-current-protection
- sdhci-cadence: Add support for multi-block read gap tuning
- sdhci-msm: Add support for tuning for SDR50 mode for SD cards
- sdhci-msm: Enable support for the Lemans variant
- sdhci-pci: Disable SD card clock before update for a few Intel platforms
- sdhci-pxav3: Add support for UHS pinctrl settings
- tmio: Add 64-bit read/write support in polling mode
MEMSTICK:
- Convert to use timeouts to prevent indefinite waiting
- rtsx_usb: Add support for over-current-protection
-----BEGIN PGP SIGNATURE-----
iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmjafZQXHHVsZi5oYW5z
c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCmSng//QMGmS6uWiPeVG237VwtZ0qir
XB7N4H0ig0wa/Qxqc9soXrBDmlKKVFaf/VvZOsqKHy3QjDGV+i6a2WVj+rao4vzi
/M3jmJK+vKGjNah/jbZEu7hUMY22buiPiRbUUv3UUmpBTxqXdsyTX+hmHJdiRQ7B
jC5GGPMbv1wMUj3ivkuwwlabRYFMy1QwFfDZxQzhEI4Codfs1P0nr2PFvCJ/r8nq
TsPYkDWevxItnyxSkaDK7bK4yGFOKnnhf7aj1d4NMS6AX2FH3QPDP09rmdHwrdZb
prgbccQusxoK2zJFwOqoTucYeNmhXgyAvuoj9kGtBkzbyTjorh2fdXwzGAnAkYqZ
ygoIvq/lPQj6ppXd5BTfldAt69/Yyj6tyWuVMJ2EdoL0yfO2xPv0lnUdrN73ATZB
jaRJdvF9EiGSfG2DzzK0W1CTpKvHg4pRA6InGgok1xIVM68iOwQcBDcU9D3tDkZo
4HpuEGVJnso0q9xh0dO36HmryKsQge5jfq3mTe3Y+kHTteWYMh7VO4FhZL+AV2fp
LDL1aLn21Q71TH+aqYA6DVn3wrXWkhg9U2Uz//SU4lv18o3Fc47GJBtbvb0nEqXX
1BUJ5QcAeNMHo2Xm7yc5YwBpghCTCZDJOogzyXaQW0nbMvn+11X4gCREYgNBP7cv
mrygbFCHLJDKscE0ZkY=
=D2yD
-----END PGP SIGNATURE-----
Merge tag 'mmc-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Improve RPMB frame handling code
- Add support for a new max-sd-hs-hz DT property to limit frequency
- Add support to manage regulator-under-voltage events
- Support regulator-under-voltage for eMMC to mitigate data
corruptions
- Add mmc_read_tuning() to allow a host to validate its tuning
sequence
- Add some helpers to align checks for CMD23 support
- Read the CCCR register for SDIO over SPI rather than the
unsupported CMD7
MMC host:
- Add COMPILE_TEST option for a couple of drivers
- Convert drivers to use the modern PM macros
- dw_mmc-exynos: Enable support for the Exynos8890 variant
- mmc_spi: Don't use crc ack during multiple block read
- renesas_sdhi: Enable 64-bit polling mode for R-Car gen3 and
RZ/G2L SoCs
- rtsx_usb: Add support for over-current-protection
- sdhci-cadence: Add support for multi-block read gap tuning
- sdhci-msm:
- Add support for tuning for SDR50 mode for SD cards
- Enable support for the Lemans variant
- sdhci-pci: Disable SD card clock before update for a few
Intel platforms
- sdhci-pxav3: Add support for UHS pinctrl settings
- tmio: Add 64-bit read/write support in polling mode
MEMSTICK:
- Convert to use timeouts to prevent indefinite waiting
- rtsx_usb: Add support for over-current-protection"
* tag 'mmc-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (77 commits)
dt-bindings: mmc: samsung,exynos-dw-mshc: add specific compatible for exynos8890
mmc: select REGMAP_MMIO with MMC_LOONGSON2
mmc: add COMPILE_TEST to multiple drivers
mmc: core: Improve RPMB frame handling code
mmc: core: Fix variable shadowing in mmc_route_rpmb_frames()
mmc: core: Parse and use the new max-sd-hs-hz DT property
dt-bindings: mmc: controller: Add max-sd-hs-hz property
mmc: sdhci-msm: Enable tuning for SDR50 mode for SD card
dt-bindings: mmc: sdhci-msm: Document the Lemans compatible
mmc: sh_mmcif: Remove dummy PM resume callback
dt-bindings: mmc: sdhci-pxa: Add minItems to pinctrl-names
mmc: sdio: Drop dev_pm_domain_detach() call
mmc: dw_mmc-rockchip: use modern PM macros
mmc: dw_mmc-pci: use modern PM macros
mmc: dw_mmc-k3: use modern PM macros
mmc: dw_mmc: exynos: use modern PM macros
mmc: via-sdmmc: use modern PM macros
mmc: sdhci-msm: use modern PM macros
mmc: mtk-sd: use modern PM macros
mmc: wmt-sdmmc: use modern PM macros
...
This commit is contained in:
commit
2d27453624
|
|
@ -90,6 +90,7 @@ required:
|
|||
|
||||
allOf:
|
||||
- $ref: sdhci-common.yaml#
|
||||
- $ref: mmc-controller-common.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,14 @@ properties:
|
|||
minimum: 400000
|
||||
maximum: 384000000
|
||||
|
||||
max-sd-hs-hz:
|
||||
description: |
|
||||
Maximum frequency (in Hz) to be used for SD cards operating in
|
||||
High-Speed (HS) mode.
|
||||
minimum: 400000
|
||||
maximum: 50000000
|
||||
default: 50000000
|
||||
|
||||
disable-wp:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ properties:
|
|||
- samsung,exynos5433-dw-mshc-smu
|
||||
- samsung,exynos7885-dw-mshc-smu
|
||||
- samsung,exynos850-dw-mshc-smu
|
||||
- samsung,exynos8890-dw-mshc-smu
|
||||
- samsung,exynos8895-dw-mshc-smu
|
||||
- const: samsung,exynos7-dw-mshc-smu
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ properties:
|
|||
- qcom,qcs615-sdhci
|
||||
- qcom,qcs8300-sdhci
|
||||
- qcom,qdu1000-sdhci
|
||||
- qcom,sa8775p-sdhci
|
||||
- qcom,sar2130p-sdhci
|
||||
- qcom,sc7180-sdhci
|
||||
- qcom,sc7280-sdhci
|
||||
|
|
|
|||
|
|
@ -44,12 +44,29 @@ allOf:
|
|||
items:
|
||||
- const: default
|
||||
- const: state_cmd_gpio
|
||||
pinctrl-0:
|
||||
description:
|
||||
Should contain default pinctrl.
|
||||
minItems: 1
|
||||
|
||||
pinctrl-1:
|
||||
description:
|
||||
Should switch CMD pin to GPIO mode as a high output.
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: mrvl,pxav3-mmc
|
||||
then:
|
||||
properties:
|
||||
pinctrl-names:
|
||||
description:
|
||||
Optional for increasing stability of the controller at fast bus clocks.
|
||||
items:
|
||||
- const: default
|
||||
- const: state_uhs
|
||||
minItems: 1
|
||||
|
||||
pinctrl-1:
|
||||
description:
|
||||
Should switch the drive strength of the data pins to high.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
@ -82,6 +99,14 @@ properties:
|
|||
- const: io
|
||||
- const: core
|
||||
|
||||
pinctrl-names: true
|
||||
|
||||
pinctrl-0:
|
||||
description:
|
||||
Should contain default pinctrl.
|
||||
|
||||
pinctrl-1: true
|
||||
|
||||
mrvl,clk-delay-cycles:
|
||||
description: Specify a number of cycles to delay for tuning.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
|
|
|||
|
|
@ -370,7 +370,9 @@ int memstick_set_rw_addr(struct memstick_dev *card)
|
|||
{
|
||||
card->next_request = h_memstick_set_rw_addr;
|
||||
memstick_new_req(card->host);
|
||||
wait_for_completion(&card->mrq_complete);
|
||||
if (!wait_for_completion_timeout(&card->mrq_complete,
|
||||
msecs_to_jiffies(500)))
|
||||
card->current_mrq.error = -ETIMEDOUT;
|
||||
|
||||
return card->current_mrq.error;
|
||||
}
|
||||
|
|
@ -404,7 +406,9 @@ static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
|
|||
|
||||
card->next_request = h_memstick_read_dev_id;
|
||||
memstick_new_req(host);
|
||||
wait_for_completion(&card->mrq_complete);
|
||||
if (!wait_for_completion_timeout(&card->mrq_complete,
|
||||
msecs_to_jiffies(500)))
|
||||
card->current_mrq.error = -ETIMEDOUT;
|
||||
|
||||
if (card->current_mrq.error)
|
||||
goto err_out;
|
||||
|
|
|
|||
|
|
@ -216,7 +216,10 @@ static int ms_power_off(struct rtsx_usb_ms *host)
|
|||
|
||||
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0);
|
||||
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0);
|
||||
|
||||
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
|
||||
POWER_MASK, POWER_OFF);
|
||||
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
|
||||
POWER_MASK | LDO3318_PWR_MASK, POWER_OFF | LDO_SUSPEND);
|
||||
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -552,6 +552,10 @@ static int rtsx_usb_reset_chip(struct rtsx_ucr *ucr)
|
|||
ret = rtsx_usb_send_cmd(ucr, MODE_C, 100);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* config OCP */
|
||||
rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_DETECT_EN, MS_OCP_DETECT_EN);
|
||||
rtsx_usb_write_register(ucr, OCPPARA1, 0xF0, 0x50);
|
||||
rtsx_usb_write_register(ucr, OCPPARA2, 0x7, 0x3);
|
||||
|
||||
/* config non-crystal mode */
|
||||
rtsx_usb_read_register(ucr, CFG_MODE, &val);
|
||||
|
|
@ -722,6 +726,9 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
|
|||
if (val & (SD_CD | MS_CD)) {
|
||||
device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child);
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
/* if the card does not exists, clear OCP status */
|
||||
rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_CLEAR, MS_OCP_CLEAR);
|
||||
}
|
||||
} else {
|
||||
/* There is an ongoing operation*/
|
||||
|
|
|
|||
|
|
@ -121,6 +121,10 @@ struct rpmb_frame {
|
|||
#define RPMB_READ_DATA 0x4 /* Read data from RPMB partition */
|
||||
#define RPMB_RESULT_READ 0x5 /* Read result request (Internal) */
|
||||
|
||||
#define RPMB_FRAME_SIZE sizeof(struct rpmb_frame)
|
||||
#define CHECK_SIZE_NEQ(val) ((val) != sizeof(struct rpmb_frame))
|
||||
#define CHECK_SIZE_ALIGNED(val) IS_ALIGNED((val), sizeof(struct rpmb_frame))
|
||||
|
||||
static DEFINE_MUTEX(block_mutex);
|
||||
|
||||
/*
|
||||
|
|
@ -1768,8 +1772,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
|||
* these, while retaining features like reliable writes.
|
||||
*/
|
||||
if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
|
||||
(do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
|
||||
do_data_tag)) {
|
||||
(do_rel_wr || !mmc_card_blk_no_cmd23(card) || do_data_tag)) {
|
||||
brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
|
||||
brq->sbc.arg = brq->data.blocks |
|
||||
(do_rel_wr ? (1 << 31) : 0) |
|
||||
|
|
@ -2618,13 +2621,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
|||
*/
|
||||
md->read_only = mmc_blk_readonly(card);
|
||||
|
||||
if (mmc_host_can_cmd23(card->host)) {
|
||||
if ((mmc_card_mmc(card) &&
|
||||
card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
|
||||
(mmc_card_sd(card) && !mmc_card_ult_capacity(card) &&
|
||||
card->scr.cmds & SD_SCR_CMD23_SUPPORT))
|
||||
md->flags |= MMC_BLK_CMD23;
|
||||
}
|
||||
if (mmc_host_can_cmd23(card->host) && mmc_card_can_cmd23(card))
|
||||
md->flags |= MMC_BLK_CMD23;
|
||||
|
||||
if (md->flags & MMC_BLK_CMD23 &&
|
||||
((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||
|
||||
|
|
@ -2864,12 +2862,12 @@ static void set_idata(struct mmc_blk_ioc_data *idata, u32 opcode,
|
|||
* The size of an RPMB frame must match what's expected by the
|
||||
* hardware.
|
||||
*/
|
||||
BUILD_BUG_ON(sizeof(struct rpmb_frame) != 512);
|
||||
static_assert(!CHECK_SIZE_NEQ(512), "RPMB frame size must be 512 bytes");
|
||||
|
||||
idata->ic.opcode = opcode;
|
||||
idata->ic.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
idata->ic.write_flag = write_flag;
|
||||
idata->ic.blksz = sizeof(struct rpmb_frame);
|
||||
idata->ic.blksz = RPMB_FRAME_SIZE;
|
||||
idata->ic.blocks = buf_bytes / idata->ic.blksz;
|
||||
idata->buf = buf;
|
||||
idata->buf_bytes = buf_bytes;
|
||||
|
|
@ -2893,32 +2891,28 @@ static int mmc_route_rpmb_frames(struct device *dev, u8 *req,
|
|||
if (IS_ERR(md->queue.card))
|
||||
return PTR_ERR(md->queue.card);
|
||||
|
||||
if (req_len < sizeof(*frm))
|
||||
if (req_len < RPMB_FRAME_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
req_type = be16_to_cpu(frm->req_resp);
|
||||
switch (req_type) {
|
||||
case RPMB_PROGRAM_KEY:
|
||||
if (req_len != sizeof(struct rpmb_frame) ||
|
||||
resp_len != sizeof(struct rpmb_frame))
|
||||
if (CHECK_SIZE_NEQ(req_len) || CHECK_SIZE_NEQ(resp_len))
|
||||
return -EINVAL;
|
||||
write = true;
|
||||
break;
|
||||
case RPMB_GET_WRITE_COUNTER:
|
||||
if (req_len != sizeof(struct rpmb_frame) ||
|
||||
resp_len != sizeof(struct rpmb_frame))
|
||||
if (CHECK_SIZE_NEQ(req_len) || CHECK_SIZE_NEQ(resp_len))
|
||||
return -EINVAL;
|
||||
write = false;
|
||||
break;
|
||||
case RPMB_WRITE_DATA:
|
||||
if (req_len % sizeof(struct rpmb_frame) ||
|
||||
resp_len != sizeof(struct rpmb_frame))
|
||||
if (!CHECK_SIZE_ALIGNED(req_len) || CHECK_SIZE_NEQ(resp_len))
|
||||
return -EINVAL;
|
||||
write = true;
|
||||
break;
|
||||
case RPMB_READ_DATA:
|
||||
if (req_len != sizeof(struct rpmb_frame) ||
|
||||
resp_len % sizeof(struct rpmb_frame))
|
||||
if (CHECK_SIZE_NEQ(req_len) || !CHECK_SIZE_ALIGNED(resp_len))
|
||||
return -EINVAL;
|
||||
write = false;
|
||||
break;
|
||||
|
|
@ -2926,25 +2920,23 @@ static int mmc_route_rpmb_frames(struct device *dev, u8 *req,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (write)
|
||||
cmd_count = 3;
|
||||
else
|
||||
cmd_count = 2;
|
||||
/* Write operations require 3 commands, read operations require 2 */
|
||||
cmd_count = write ? 3 : 2;
|
||||
|
||||
idata = alloc_idata(rpmb, cmd_count);
|
||||
if (!idata)
|
||||
return -ENOMEM;
|
||||
|
||||
if (write) {
|
||||
struct rpmb_frame *frm = (struct rpmb_frame *)resp;
|
||||
struct rpmb_frame *resp_frm = (struct rpmb_frame *)resp;
|
||||
|
||||
/* Send write request frame(s) */
|
||||
set_idata(idata[0], MMC_WRITE_MULTIPLE_BLOCK,
|
||||
1 | MMC_CMD23_ARG_REL_WR, req, req_len);
|
||||
|
||||
/* Send result request frame */
|
||||
memset(frm, 0, sizeof(*frm));
|
||||
frm->req_resp = cpu_to_be16(RPMB_RESULT_READ);
|
||||
memset(resp_frm, 0, RPMB_FRAME_SIZE);
|
||||
resp_frm->req_resp = cpu_to_be16(RPMB_RESULT_READ);
|
||||
set_idata(idata[1], MMC_WRITE_MULTIPLE_BLOCK, 1, resp,
|
||||
resp_len);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "card.h"
|
||||
|
|
@ -383,6 +384,14 @@ int mmc_add_card(struct mmc_card *card)
|
|||
|
||||
mmc_card_set_present(card);
|
||||
|
||||
/*
|
||||
* Register for undervoltage notification if the card supports
|
||||
* power-off notification, enabling emergency shutdowns.
|
||||
*/
|
||||
if (mmc_card_mmc(card) &&
|
||||
card->ext_csd.power_off_notification == EXT_CSD_POWER_ON)
|
||||
mmc_regulator_register_undervoltage_notifier(card->host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -394,6 +403,9 @@ void mmc_remove_card(struct mmc_card *card)
|
|||
{
|
||||
struct mmc_host *host = card->host;
|
||||
|
||||
if (mmc_card_present(card))
|
||||
mmc_regulator_unregister_undervoltage_notifier(host);
|
||||
|
||||
mmc_remove_card_debugfs(card);
|
||||
|
||||
if (mmc_card_present(card)) {
|
||||
|
|
|
|||
|
|
@ -245,14 +245,19 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
|
|||
return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
|
||||
}
|
||||
|
||||
static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
|
||||
{
|
||||
return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
|
||||
}
|
||||
|
||||
static inline int mmc_card_disable_cd(const struct mmc_card *c)
|
||||
{
|
||||
return c->quirks & MMC_QUIRK_DISABLE_CD;
|
||||
}
|
||||
|
||||
static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
|
||||
static inline int mmc_card_blk_no_cmd23(const struct mmc_card *c)
|
||||
{
|
||||
return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
|
||||
return c->quirks & MMC_QUIRK_BLK_NO_CMD23;
|
||||
}
|
||||
|
||||
static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c)
|
||||
|
|
|
|||
|
|
@ -1398,6 +1398,29 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr)
|
|||
mmc_power_up(host, ocr);
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_handle_undervoltage - Handle an undervoltage event on the MMC bus
|
||||
* @host: The MMC host that detected the undervoltage condition
|
||||
*
|
||||
* This function is called when an undervoltage event is detected on one of
|
||||
* the MMC regulators.
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mmc_handle_undervoltage(struct mmc_host *host)
|
||||
{
|
||||
/* Stop the host to prevent races with card removal */
|
||||
__mmc_stop_host(host);
|
||||
|
||||
if (!host->bus_ops || !host->bus_ops->handle_undervoltage)
|
||||
return 0;
|
||||
|
||||
dev_warn(mmc_dev(host), "%s: Undervoltage detected, initiating emergency stop\n",
|
||||
mmc_hostname(host));
|
||||
|
||||
return host->bus_ops->handle_undervoltage(host);
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign a mmc bus handler to a host. Only one bus handler may control a
|
||||
* host at any given time.
|
||||
|
|
@ -1875,6 +1898,15 @@ bool mmc_card_can_secure_erase_trim(struct mmc_card *card)
|
|||
}
|
||||
EXPORT_SYMBOL(mmc_card_can_secure_erase_trim);
|
||||
|
||||
bool mmc_card_can_cmd23(struct mmc_card *card)
|
||||
{
|
||||
return ((mmc_card_mmc(card) &&
|
||||
card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
|
||||
(mmc_card_sd(card) && !mmc_card_ult_capacity(card) &&
|
||||
card->scr.cmds & SD_SCR_CMD23_SUPPORT));
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_card_can_cmd23);
|
||||
|
||||
int mmc_erase_group_aligned(struct mmc_card *card, sector_t from,
|
||||
unsigned int nr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ struct mmc_bus_ops {
|
|||
int (*sw_reset)(struct mmc_host *);
|
||||
bool (*cache_enabled)(struct mmc_host *);
|
||||
int (*flush_cache)(struct mmc_host *);
|
||||
int (*handle_undervoltage)(struct mmc_host *host);
|
||||
};
|
||||
|
||||
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
|
||||
|
|
@ -59,6 +60,10 @@ void mmc_power_off(struct mmc_host *host);
|
|||
void mmc_power_cycle(struct mmc_host *host, u32 ocr);
|
||||
void mmc_set_initial_state(struct mmc_host *host);
|
||||
u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max);
|
||||
int mmc_handle_undervoltage(struct mmc_host *host);
|
||||
void mmc_regulator_register_undervoltage_notifier(struct mmc_host *host);
|
||||
void mmc_regulator_unregister_undervoltage_notifier(struct mmc_host *host);
|
||||
void mmc_undervoltage_workfn(struct work_struct *work);
|
||||
|
||||
static inline void mmc_delay(unsigned int ms)
|
||||
{
|
||||
|
|
@ -123,6 +128,7 @@ bool mmc_card_can_trim(struct mmc_card *card);
|
|||
bool mmc_card_can_discard(struct mmc_card *card);
|
||||
bool mmc_card_can_sanitize(struct mmc_card *card);
|
||||
bool mmc_card_can_secure_erase_trim(struct mmc_card *card);
|
||||
bool mmc_card_can_cmd23(struct mmc_card *card);
|
||||
int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr);
|
||||
unsigned int mmc_calc_max_discard(struct mmc_card *card);
|
||||
|
||||
|
|
|
|||
|
|
@ -302,6 +302,8 @@ int mmc_of_parse(struct mmc_host *host)
|
|||
/* f_max is obtained from the optional "max-frequency" property */
|
||||
device_property_read_u32(dev, "max-frequency", &host->f_max);
|
||||
|
||||
device_property_read_u32(dev, "max-sd-hs-hz", &host->max_sd_hs_hz);
|
||||
|
||||
/*
|
||||
* Configure CD and WP pins. They are both by default active low to
|
||||
* match the SDHCI spec. If GPIOs are provided for CD and / or WP, the
|
||||
|
|
@ -564,6 +566,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
|||
INIT_WORK(&host->sdio_irq_work, sdio_irq_work);
|
||||
timer_setup(&host->retune_timer, mmc_retune_timer, 0);
|
||||
|
||||
INIT_WORK(&host->supply.uv_work, mmc_undervoltage_workfn);
|
||||
|
||||
/*
|
||||
* By default, hosts do not support SGIO or large requests.
|
||||
* They have to set these according to their abilities.
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
enum mmc_poweroff_type {
|
||||
MMC_POWEROFF_SUSPEND,
|
||||
MMC_POWEROFF_SHUTDOWN,
|
||||
MMC_POWEROFF_UNDERVOLTAGE,
|
||||
MMC_POWEROFF_UNBIND,
|
||||
};
|
||||
|
||||
|
|
@ -2132,9 +2133,15 @@ static int _mmc_suspend(struct mmc_host *host, enum mmc_poweroff_type pm_type)
|
|||
if (mmc_card_suspended(host->card))
|
||||
goto out;
|
||||
|
||||
err = _mmc_flush_cache(host);
|
||||
if (err)
|
||||
goto out;
|
||||
/*
|
||||
* For the undervoltage case, we care more about device integrity.
|
||||
* Avoid cache flush and notify the device to power off quickly.
|
||||
*/
|
||||
if (pm_type != MMC_POWEROFF_UNDERVOLTAGE) {
|
||||
err = _mmc_flush_cache(host);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mmc_card_can_poweroff_notify(host->card) &&
|
||||
mmc_host_can_poweroff_notify(host, pm_type))
|
||||
|
|
@ -2212,6 +2219,13 @@ static int mmc_shutdown(struct mmc_host *host)
|
|||
{
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* In case of undervoltage, the card will be powered off (removed) by
|
||||
* _mmc_handle_undervoltage()
|
||||
*/
|
||||
if (mmc_card_removed(host->card))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the card remains suspended at this point and it was done by using
|
||||
* the sleep-cmd (CMD5), we may need to re-initialize it first, to allow
|
||||
|
|
@ -2302,6 +2316,55 @@ static int _mmc_hw_reset(struct mmc_host *host)
|
|||
return mmc_init_card(host, card->ocr, card);
|
||||
}
|
||||
|
||||
/**
|
||||
* _mmc_handle_undervoltage - Handle an undervoltage event for MMC/eMMC devices
|
||||
* @host: MMC host structure
|
||||
*
|
||||
* This function is triggered when an undervoltage condition is detected.
|
||||
* It attempts to transition the device into a low-power or safe state to
|
||||
* prevent data corruption.
|
||||
*
|
||||
* Steps performed:
|
||||
* - Perform an emergency suspend using EXT_CSD_POWER_OFF_SHORT if possible.
|
||||
* - If power-off notify is not supported, fallback mechanisms like sleep or
|
||||
* deselecting the card are attempted.
|
||||
* - Cache flushing is skipped to reduce execution time.
|
||||
* - Mark the card as removed to prevent further interactions after
|
||||
* undervoltage.
|
||||
*
|
||||
* Note: This function does not handle host claiming or releasing. The caller
|
||||
* must ensure that the host is properly claimed before calling this
|
||||
* function and released afterward.
|
||||
*
|
||||
* Returns: 0 on success, or a negative error code if any step fails.
|
||||
*/
|
||||
static int _mmc_handle_undervoltage(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_card *card = host->card;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Perform an emergency suspend to power off the eMMC quickly.
|
||||
* This ensures the device enters a safe state before power is lost.
|
||||
* We first attempt EXT_CSD_POWER_OFF_SHORT, but if power-off notify
|
||||
* is not supported, we fall back to sleep mode or deselecting the card.
|
||||
* Cache flushing is skipped to minimize delay.
|
||||
*/
|
||||
err = _mmc_suspend(host, MMC_POWEROFF_UNDERVOLTAGE);
|
||||
if (err)
|
||||
pr_err("%s: undervoltage suspend failed: %pe\n",
|
||||
mmc_hostname(host), ERR_PTR(err));
|
||||
|
||||
/*
|
||||
* Mark the card as removed to prevent further operations.
|
||||
* This ensures the system does not attempt to access the device
|
||||
* after an undervoltage event, avoiding potential corruption.
|
||||
*/
|
||||
mmc_card_set_removed(card);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct mmc_bus_ops mmc_ops = {
|
||||
.remove = mmc_remove,
|
||||
.detect = mmc_detect,
|
||||
|
|
@ -2314,6 +2377,7 @@ static const struct mmc_bus_ops mmc_ops = {
|
|||
.hw_reset = _mmc_hw_reset,
|
||||
.cache_enabled = _mmc_cache_enabled,
|
||||
.flush_cache = _mmc_flush_cache,
|
||||
.handle_undervoltage = _mmc_handle_undervoltage,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1077,3 +1077,75 @@ int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms)
|
|||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_sanitize);
|
||||
|
||||
/**
|
||||
* mmc_read_tuning() - read data blocks from the mmc
|
||||
* @host: mmc host doing the read
|
||||
* @blksz: data block size
|
||||
* @blocks: number of blocks to read
|
||||
*
|
||||
* Read one or more blocks of data from the beginning of the mmc. This is a
|
||||
* low-level helper for tuning operation. It is assumed that CMD23 can be used
|
||||
* for multi-block read if the host supports it.
|
||||
*
|
||||
* Note: Allocate and free a temporary buffer to store the data read. The data
|
||||
* is not available outside of the function, only the status of the read
|
||||
* operation.
|
||||
*
|
||||
* Return: 0 in case of success, otherwise -EIO / -ENOMEM / -E2BIG
|
||||
*/
|
||||
int mmc_read_tuning(struct mmc_host *host, unsigned int blksz, unsigned int blocks)
|
||||
{
|
||||
struct mmc_request mrq = {};
|
||||
struct mmc_command sbc = {};
|
||||
struct mmc_command cmd = {};
|
||||
struct mmc_command stop = {};
|
||||
struct mmc_data data = {};
|
||||
struct scatterlist sg;
|
||||
void *buf;
|
||||
unsigned int len;
|
||||
|
||||
if (blocks > 1) {
|
||||
if (mmc_host_can_cmd23(host)) {
|
||||
mrq.sbc = &sbc;
|
||||
sbc.opcode = MMC_SET_BLOCK_COUNT;
|
||||
sbc.arg = blocks;
|
||||
sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
}
|
||||
cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
|
||||
mrq.stop = &stop;
|
||||
stop.opcode = MMC_STOP_TRANSMISSION;
|
||||
stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
|
||||
} else {
|
||||
cmd.opcode = MMC_READ_SINGLE_BLOCK;
|
||||
}
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
|
||||
mrq.data = &data;
|
||||
data.flags = MMC_DATA_READ;
|
||||
data.blksz = blksz;
|
||||
data.blocks = blocks;
|
||||
data.blk_addr = 0;
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
data.timeout_ns = 1000000000;
|
||||
|
||||
if (check_mul_overflow(blksz, blocks, &len))
|
||||
return -E2BIG;
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
sg_init_one(&sg, buf, len);
|
||||
|
||||
mmc_wait_for_req(host, &mrq);
|
||||
kfree(buf);
|
||||
|
||||
if (sbc.error || cmd.error || data.error)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_read_tuning);
|
||||
|
|
|
|||
|
|
@ -180,20 +180,14 @@ static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
|
|||
return mmc_set_blocklen(test->card, size);
|
||||
}
|
||||
|
||||
static bool mmc_test_card_cmd23(struct mmc_card *card)
|
||||
{
|
||||
return mmc_card_mmc(card) ||
|
||||
(mmc_card_sd(card) && card->scr.cmds & SD_SCR_CMD23_SUPPORT);
|
||||
}
|
||||
|
||||
static void mmc_test_prepare_sbc(struct mmc_test_card *test,
|
||||
struct mmc_request *mrq, unsigned int blocks)
|
||||
{
|
||||
struct mmc_card *card = test->card;
|
||||
|
||||
if (!mrq->sbc || !mmc_host_can_cmd23(card->host) ||
|
||||
!mmc_test_card_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) ||
|
||||
(card->quirks & MMC_QUIRK_BLK_NO_CMD23)) {
|
||||
!mmc_card_can_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) ||
|
||||
mmc_card_blk_no_cmd23(card)) {
|
||||
mrq->sbc = NULL;
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
|
|
@ -262,6 +263,82 @@ static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
|
|||
|
||||
#endif /* CONFIG_REGULATOR */
|
||||
|
||||
/* To be called from a high-priority workqueue */
|
||||
void mmc_undervoltage_workfn(struct work_struct *work)
|
||||
{
|
||||
struct mmc_supply *supply;
|
||||
struct mmc_host *host;
|
||||
|
||||
supply = container_of(work, struct mmc_supply, uv_work);
|
||||
host = container_of(supply, struct mmc_host, supply);
|
||||
|
||||
mmc_handle_undervoltage(host);
|
||||
}
|
||||
|
||||
static int mmc_handle_regulator_event(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct mmc_supply *supply = container_of(nb, struct mmc_supply,
|
||||
vmmc_nb);
|
||||
struct mmc_host *host = container_of(supply, struct mmc_host, supply);
|
||||
unsigned long flags;
|
||||
|
||||
switch (event) {
|
||||
case REGULATOR_EVENT_UNDER_VOLTAGE:
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
if (host->undervoltage) {
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
host->undervoltage = true;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
queue_work(system_highpri_wq, &host->supply.uv_work);
|
||||
break;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_regulator_register_undervoltage_notifier - Register for undervoltage
|
||||
* events
|
||||
* @host: MMC host
|
||||
*
|
||||
* To be called by a bus driver when a card supporting graceful shutdown
|
||||
* is attached.
|
||||
*/
|
||||
void mmc_regulator_register_undervoltage_notifier(struct mmc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(host->supply.vmmc))
|
||||
return;
|
||||
|
||||
host->supply.vmmc_nb.notifier_call = mmc_handle_regulator_event;
|
||||
ret = regulator_register_notifier(host->supply.vmmc,
|
||||
&host->supply.vmmc_nb);
|
||||
if (ret)
|
||||
dev_warn(mmc_dev(host), "Failed to register vmmc notifier: %d\n", ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_regulator_unregister_undervoltage_notifier - Unregister undervoltage
|
||||
* notifier
|
||||
* @host: MMC host
|
||||
*/
|
||||
void mmc_regulator_unregister_undervoltage_notifier(struct mmc_host *host)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(host->supply.vmmc))
|
||||
return;
|
||||
|
||||
regulator_unregister_notifier(host->supply.vmmc, &host->supply.vmmc_nb);
|
||||
cancel_work_sync(&host->supply.uv_work);
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_regulator_get_supply - try to get VMMC and VQMMC regulators for a host
|
||||
* @mmc: the host to regulate
|
||||
|
|
|
|||
|
|
@ -359,7 +359,7 @@ static int mmc_read_switch(struct mmc_card *card)
|
|||
}
|
||||
|
||||
if (status[13] & SD_MODE_HIGH_SPEED)
|
||||
card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR;
|
||||
card->sw_caps.hs_max_dtr = card->host->max_sd_hs_hz ?: HIGH_SPEED_MAX_DTR;
|
||||
|
||||
if (card->scr.sda_spec3) {
|
||||
card->sw_caps.sd3_bus_mode = status[13];
|
||||
|
|
|
|||
|
|
@ -945,7 +945,11 @@ static void mmc_sdio_remove(struct mmc_host *host)
|
|||
*/
|
||||
static int mmc_sdio_alive(struct mmc_host *host)
|
||||
{
|
||||
return mmc_select_card(host->card);
|
||||
if (!mmc_host_is_spi(host))
|
||||
return mmc_select_card(host->card);
|
||||
else
|
||||
return mmc_io_rw_direct(host->card, 0, 0, SDIO_CCCR_CCCR, 0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -200,7 +200,6 @@ static int sdio_bus_probe(struct device *dev)
|
|||
atomic_dec(&func->card->sdio_funcs_probed);
|
||||
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
|
||||
pm_runtime_put_noidle(dev);
|
||||
dev_pm_domain_detach(dev, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -231,8 +230,6 @@ static void sdio_bus_remove(struct device *dev)
|
|||
/* Then undo the runtime PM settings in sdio_bus_probe() */
|
||||
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
dev_pm_domain_detach(dev, false);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sdio_bus_pm_ops = {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ config MMC_STM32_SDMMC
|
|||
|
||||
config MMC_PXA
|
||||
tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
|
||||
depends on ARCH_PXA
|
||||
depends on ARCH_PXA || COMPILE_TEST
|
||||
help
|
||||
This selects the Intel(R) PXA(R) Multimedia card Interface.
|
||||
If you have a PXA(R) platform with a Multimedia Card slot,
|
||||
|
|
@ -359,7 +359,7 @@ config MMC_SDHCI_S3C
|
|||
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
|
||||
help
|
||||
This selects the Secure Digital Host Controller Interface (SDHCI)
|
||||
often referrered to as the HSMMC block in some of the Samsung
|
||||
often referred to as the HSMMC block in some of the Samsung
|
||||
S3C6410, S5Pv210 and Exynos (Exynso4210, Exynos4412) SoCs.
|
||||
|
||||
If you have a controller with this interface (thereforeyou build for
|
||||
|
|
@ -401,7 +401,7 @@ config MMC_SDHCI_SPEAR
|
|||
depends on OF
|
||||
help
|
||||
This selects the Secure Digital Host Controller Interface (SDHCI)
|
||||
often referrered to as the HSMMC block in some of the ST SPEAR range
|
||||
often referred to as the HSMMC block in some of the ST SPEAR range
|
||||
of SoC
|
||||
|
||||
If you have a controller with this interface, say Y or M here.
|
||||
|
|
@ -608,7 +608,7 @@ config MMC_SDHCI_MSM
|
|||
|
||||
config MMC_MXC
|
||||
tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support"
|
||||
depends on ARCH_MXC || PPC_MPC512x
|
||||
depends on ARCH_MXC || PPC_MPC512x || COMPILE_TEST
|
||||
help
|
||||
This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x
|
||||
Multimedia Card Interface. If you have an i.MX or MPC512x platform
|
||||
|
|
@ -866,7 +866,8 @@ config MMC_DW_PCI
|
|||
|
||||
config MMC_DW_ROCKCHIP
|
||||
tristate "Rockchip specific extensions for Synopsys DW Memory Card Interface"
|
||||
depends on MMC_DW && ARCH_ROCKCHIP
|
||||
depends on MMC_DW
|
||||
depends on ARCH_ROCKCHIP || COMPILE_TEST
|
||||
select MMC_DW_PLTFM
|
||||
help
|
||||
This selects support for Rockchip SoC specific extensions to the
|
||||
|
|
@ -948,7 +949,7 @@ config MMC_USHC
|
|||
|
||||
config MMC_WMT
|
||||
tristate "Wondermedia SD/MMC Host Controller support"
|
||||
depends on ARCH_VT8500
|
||||
depends on ARCH_VT8500 || COMPILE_TEST
|
||||
default y
|
||||
help
|
||||
This selects support for the SD/MMC Host Controller on
|
||||
|
|
@ -1115,6 +1116,7 @@ config MMC_LOONGSON2
|
|||
tristate "Loongson-2K SD/SDIO/eMMC Host Interface support"
|
||||
depends on LOONGARCH || COMPILE_TEST
|
||||
depends on HAS_DMA
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
This selects support for the SD/SDIO/eMMC Host Controller on
|
||||
Loongson-2K series CPUs.
|
||||
|
|
|
|||
|
|
@ -1129,7 +1129,6 @@ static void alcor_pci_sdmmc_drv_remove(struct platform_device *pdev)
|
|||
mmc_remove_host(mmc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int alcor_pci_sdmmc_suspend(struct device *dev)
|
||||
{
|
||||
struct alcor_sdmmc_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -1150,10 +1149,9 @@ static int alcor_pci_sdmmc_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(alcor_mmc_pm_ops, alcor_pci_sdmmc_suspend,
|
||||
alcor_pci_sdmmc_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(alcor_mmc_pm_ops, alcor_pci_sdmmc_suspend,
|
||||
alcor_pci_sdmmc_resume);
|
||||
|
||||
static const struct platform_device_id alcor_pci_sdmmc_ids[] = {
|
||||
{
|
||||
|
|
@ -1171,7 +1169,7 @@ static struct platform_driver alcor_pci_sdmmc_driver = {
|
|||
.driver = {
|
||||
.name = DRV_NAME_ALCOR_PCI_SDMMC,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &alcor_mmc_pm_ops
|
||||
.pm = pm_sleep_ptr(&alcor_mmc_pm_ops),
|
||||
},
|
||||
};
|
||||
module_platform_driver(alcor_pci_sdmmc_driver);
|
||||
|
|
|
|||
|
|
@ -2622,7 +2622,6 @@ static void atmci_remove(struct platform_device *pdev)
|
|||
pm_runtime_put_noidle(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int atmci_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct atmel_mci *host = dev_get_drvdata(dev);
|
||||
|
|
@ -2642,12 +2641,10 @@ static int atmci_runtime_resume(struct device *dev)
|
|||
|
||||
return clk_prepare_enable(host->mck);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops atmci_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver atmci_driver = {
|
||||
|
|
@ -2657,7 +2654,7 @@ static struct platform_driver atmci_driver = {
|
|||
.name = "atmel_mci",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = atmci_dt_ids,
|
||||
.pm = &atmci_dev_pm_ops,
|
||||
.pm = pm_ptr(&atmci_dev_pm_ops),
|
||||
},
|
||||
};
|
||||
module_platform_driver(atmci_driver);
|
||||
|
|
|
|||
|
|
@ -1150,10 +1150,9 @@ static void au1xmmc_remove(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int au1xmmc_suspend(struct device *dev)
|
||||
{
|
||||
struct au1xmmc_host *host = platform_get_drvdata(pdev);
|
||||
struct au1xmmc_host *host = dev_get_drvdata(dev);
|
||||
|
||||
__raw_writel(0, HOST_CONFIG2(host));
|
||||
__raw_writel(0, HOST_CONFIG(host));
|
||||
|
|
@ -1164,27 +1163,24 @@ static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int au1xmmc_resume(struct platform_device *pdev)
|
||||
static int au1xmmc_resume(struct device *dev)
|
||||
{
|
||||
struct au1xmmc_host *host = platform_get_drvdata(pdev);
|
||||
struct au1xmmc_host *host = dev_get_drvdata(dev);
|
||||
|
||||
au1xmmc_reset_controller(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define au1xmmc_suspend NULL
|
||||
#define au1xmmc_resume NULL
|
||||
#endif
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(au1xmmc_pmops, au1xmmc_suspend, au1xmmc_resume);
|
||||
|
||||
static struct platform_driver au1xmmc_driver = {
|
||||
.probe = au1xmmc_probe,
|
||||
.remove = au1xmmc_remove,
|
||||
.suspend = au1xmmc_suspend,
|
||||
.resume = au1xmmc_resume,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = pm_sleep_ptr(&au1xmmc_pmops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -664,25 +664,25 @@ static const struct mmc_host_ops cb710_mmc_host = {
|
|||
.get_cd = cb710_mmc_get_cd,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int cb710_mmc_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
|
||||
|
||||
cb710_mmc_enable_irq(slot, 0, ~0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cb710_mmc_resume(struct platform_device *pdev)
|
||||
static int cb710_mmc_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
|
||||
|
||||
cb710_mmc_enable_irq(slot, 0, ~0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(cb710_mmc_pmops, cb710_mmc_suspend, cb710_mmc_resume);
|
||||
|
||||
static int cb710_mmc_init(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -767,13 +767,12 @@ static void cb710_mmc_exit(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static struct platform_driver cb710_mmc_driver = {
|
||||
.driver.name = "cb710-mmc",
|
||||
.driver = {
|
||||
.name = "cb710-mmc",
|
||||
.pm = pm_sleep_ptr(&cb710_mmc_pmops),
|
||||
},
|
||||
.probe = cb710_mmc_init,
|
||||
.remove = cb710_mmc_exit,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cb710_mmc_suspend,
|
||||
.resume = cb710_mmc_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
module_platform_driver(cb710_mmc_driver);
|
||||
|
|
|
|||
|
|
@ -588,7 +588,7 @@ static void mmc_davinci_request(struct mmc_host *mmc, struct mmc_request *req)
|
|||
cpu_relax();
|
||||
}
|
||||
if (mmcst1 & MMCST1_BUSY) {
|
||||
dev_err(mmc_dev(host->mmc), "still BUSY? bad ... \n");
|
||||
dev_err(mmc_dev(host->mmc), "still BUSY? bad ...\n");
|
||||
req->cmd->error = -ETIMEDOUT;
|
||||
mmc_request_done(mmc, req);
|
||||
return;
|
||||
|
|
@ -1347,7 +1347,6 @@ static void davinci_mmcsd_remove(struct platform_device *pdev)
|
|||
clk_disable_unprepare(host->clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int davinci_mmcsd_suspend(struct device *dev)
|
||||
{
|
||||
struct mmc_davinci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -1373,21 +1372,14 @@ static int davinci_mmcsd_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops davinci_mmcsd_pm = {
|
||||
.suspend = davinci_mmcsd_suspend,
|
||||
.resume = davinci_mmcsd_resume,
|
||||
};
|
||||
|
||||
#define davinci_mmcsd_pm_ops (&davinci_mmcsd_pm)
|
||||
#else
|
||||
#define davinci_mmcsd_pm_ops NULL
|
||||
#endif
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(davinci_mmcsd_pm_ops,
|
||||
davinci_mmcsd_suspend, davinci_mmcsd_resume);
|
||||
|
||||
static struct platform_driver davinci_mmcsd_driver = {
|
||||
.driver = {
|
||||
.name = "davinci_mmc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = davinci_mmcsd_pm_ops,
|
||||
.pm = pm_sleep_ptr(&davinci_mmcsd_pm_ops),
|
||||
.of_match_table = davinci_mmc_dt_ids,
|
||||
},
|
||||
.probe = davinci_mmcsd_probe,
|
||||
|
|
|
|||
|
|
@ -189,7 +189,6 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
|
|||
set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->slot->flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int dw_mci_exynos_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct dw_mci *host = dev_get_drvdata(dev);
|
||||
|
|
@ -203,9 +202,7 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
* dw_mci_exynos_suspend_noirq - Exynos-specific suspend code
|
||||
* @dev: Device to suspend (this device)
|
||||
|
|
@ -265,7 +262,6 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
|
||||
{
|
||||
|
|
@ -712,11 +708,8 @@ static void dw_mci_exynos_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops dw_mci_exynos_pmops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq,
|
||||
dw_mci_exynos_resume_noirq)
|
||||
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
|
||||
dw_mci_exynos_runtime_resume,
|
||||
NULL)
|
||||
NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq, dw_mci_exynos_resume_noirq)
|
||||
RUNTIME_PM_OPS(dw_mci_runtime_suspend, dw_mci_exynos_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver dw_mci_exynos_pltfm_driver = {
|
||||
|
|
@ -726,7 +719,7 @@ static struct platform_driver dw_mci_exynos_pltfm_driver = {
|
|||
.name = "dwmmc_exynos",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = dw_mci_exynos_match,
|
||||
.pm = &dw_mci_exynos_pmops,
|
||||
.pm = pm_ptr(&dw_mci_exynos_pmops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -461,11 +461,8 @@ static int dw_mci_k3_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops dw_mci_k3_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
|
||||
dw_mci_runtime_resume,
|
||||
NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(dw_mci_runtime_suspend, dw_mci_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver dw_mci_k3_pltfm_driver = {
|
||||
|
|
@ -475,7 +472,7 @@ static struct platform_driver dw_mci_k3_pltfm_driver = {
|
|||
.name = "dwmmc_k3",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = dw_mci_k3_match,
|
||||
.pm = &dw_mci_k3_dev_pm_ops,
|
||||
.pm = pm_ptr(&dw_mci_k3_dev_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -75,11 +75,8 @@ static void dw_mci_pci_remove(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops dw_mci_pci_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
|
||||
dw_mci_runtime_resume,
|
||||
NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(dw_mci_runtime_suspend, dw_mci_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct pci_device_id dw_mci_pci_id[] = {
|
||||
|
|
@ -94,7 +91,7 @@ static struct pci_driver dw_mci_pci_driver = {
|
|||
.probe = dw_mci_pci_probe,
|
||||
.remove = dw_mci_pci_remove,
|
||||
.driver = {
|
||||
.pm = &dw_mci_pci_dev_pm_ops,
|
||||
.pm = pm_ptr(&dw_mci_pci_dev_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -568,11 +568,8 @@ static void dw_mci_rockchip_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
|
||||
dw_mci_runtime_resume,
|
||||
NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(dw_mci_runtime_suspend, dw_mci_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver dw_mci_rockchip_pltfm_driver = {
|
||||
|
|
@ -582,7 +579,7 @@ static struct platform_driver dw_mci_rockchip_pltfm_driver = {
|
|||
.name = "dwmmc_rockchip",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = dw_mci_rockchip_match,
|
||||
.pm = &dw_mci_rockchip_dev_pm_ops,
|
||||
.pm = pm_ptr(&dw_mci_rockchip_dev_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -541,6 +541,9 @@ extern void dw_mci_remove(struct dw_mci *host);
|
|||
#ifdef CONFIG_PM
|
||||
extern int dw_mci_runtime_suspend(struct device *device);
|
||||
extern int dw_mci_runtime_resume(struct device *device);
|
||||
#else
|
||||
static inline int dw_mci_runtime_suspend(struct device *device) { return -EOPNOTSUPP; }
|
||||
static inline int dw_mci_runtime_resume(struct device *device) { return -EOPNOTSUPP; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -84,10 +84,8 @@ static int meson_mx_sdhc_gate_clk_hw_register(struct device *dev,
|
|||
return ret;
|
||||
|
||||
clk_bulk_data[bulk_index].clk = devm_clk_hw_get_clk(dev, hw, name_suffix);
|
||||
if (IS_ERR(clk_bulk_data[bulk_index].clk))
|
||||
return PTR_ERR(clk_bulk_data[bulk_index].clk);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(clk_bulk_data[bulk_index].clk);
|
||||
}
|
||||
|
||||
int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base,
|
||||
|
|
|
|||
|
|
@ -563,10 +563,10 @@ mmc_spi_setup_data_message(struct mmc_spi_host *host, bool multiple, bool write)
|
|||
* the next token (next data block, or STOP_TRAN). We can try to
|
||||
* minimize I/O ops by using a single read to collect end-of-busy.
|
||||
*/
|
||||
if (multiple || write) {
|
||||
if (write) {
|
||||
t = &host->early_status;
|
||||
memset(t, 0, sizeof(*t));
|
||||
t->len = write ? sizeof(scratch->status) : 1;
|
||||
t->len = sizeof(scratch->status);
|
||||
t->tx_buf = host->ones;
|
||||
t->rx_buf = scratch->status;
|
||||
t->cs_change = 1;
|
||||
|
|
|
|||
|
|
@ -2516,7 +2516,6 @@ static void mmci_remove(struct amba_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void mmci_save(struct mmci_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
|
@ -2581,12 +2580,10 @@ static int mmci_runtime_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops mmci_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct amba_id mmci_ids[] = {
|
||||
|
|
@ -2675,7 +2672,7 @@ MODULE_DEVICE_TABLE(amba, mmci_ids);
|
|||
static struct amba_driver mmci_driver = {
|
||||
.drv = {
|
||||
.name = DRIVER_NAME,
|
||||
.pm = &mmci_dev_pm_ops,
|
||||
.pm = pm_ptr(&mmci_dev_pm_ops),
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.probe = mmci_probe,
|
||||
|
|
|
|||
|
|
@ -3278,7 +3278,7 @@ static void msdc_restore_reg(struct msdc_host *host)
|
|||
__msdc_enable_sdio_irq(host, 1);
|
||||
}
|
||||
|
||||
static int __maybe_unused msdc_runtime_suspend(struct device *dev)
|
||||
static int msdc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
|
@ -3300,7 +3300,7 @@ static int __maybe_unused msdc_runtime_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused msdc_runtime_resume(struct device *dev)
|
||||
static int msdc_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
|
@ -3323,7 +3323,7 @@ static int __maybe_unused msdc_runtime_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused msdc_suspend(struct device *dev)
|
||||
static int msdc_suspend(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
|
@ -3348,7 +3348,7 @@ static int __maybe_unused msdc_suspend(struct device *dev)
|
|||
return pm_runtime_force_suspend(dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused msdc_resume(struct device *dev)
|
||||
static int msdc_resume(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
|
@ -3360,8 +3360,8 @@ static int __maybe_unused msdc_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops msdc_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(msdc_suspend, msdc_resume)
|
||||
SET_RUNTIME_PM_OPS(msdc_runtime_suspend, msdc_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(msdc_suspend, msdc_resume)
|
||||
RUNTIME_PM_OPS(msdc_runtime_suspend, msdc_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver mt_msdc_driver = {
|
||||
|
|
@ -3371,7 +3371,7 @@ static struct platform_driver mt_msdc_driver = {
|
|||
.name = "mtk-msdc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = msdc_of_ids,
|
||||
.pm = &msdc_dev_pm_ops,
|
||||
.pm = pm_ptr(&msdc_dev_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -680,7 +680,6 @@ static void mxs_mmc_remove(struct platform_device *pdev)
|
|||
clk_disable_unprepare(ssp->clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mxs_mmc_suspend(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
|
|
@ -699,9 +698,8 @@ static int mxs_mmc_resume(struct device *dev)
|
|||
|
||||
return clk_prepare_enable(ssp->clk);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume);
|
||||
|
||||
static struct platform_driver mxs_mmc_driver = {
|
||||
.probe = mxs_mmc_probe,
|
||||
|
|
@ -709,7 +707,7 @@ static struct platform_driver mxs_mmc_driver = {
|
|||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &mxs_mmc_pm_ops,
|
||||
.pm = pm_sleep_ptr(&mxs_mmc_pm_ops),
|
||||
.of_match_table = mxs_mmc_dt_ids,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -620,8 +620,6 @@ static void omap_hsmmc_set_bus_mode(struct omap_hsmmc_host *host)
|
|||
OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/*
|
||||
* Restore the MMC host context, if it was lost as result of a
|
||||
* power state change.
|
||||
|
|
@ -689,6 +687,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* Save the MMC host context (store the number of power state changes so far).
|
||||
*/
|
||||
|
|
@ -1990,7 +1989,6 @@ static void omap_hsmmc_remove(struct platform_device *pdev)
|
|||
clk_disable_unprepare(host->dbclk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int omap_hsmmc_suspend(struct device *dev)
|
||||
{
|
||||
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -2032,9 +2030,7 @@ static int omap_hsmmc_resume(struct device *dev)
|
|||
pm_runtime_put_autosuspend(host->dev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int omap_hsmmc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct omap_hsmmc_host *host;
|
||||
|
|
@ -2102,11 +2098,10 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
|
|||
spin_unlock_irqrestore(&host->irq_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume)
|
||||
SET_RUNTIME_PM_OPS(omap_hsmmc_runtime_suspend, omap_hsmmc_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume)
|
||||
RUNTIME_PM_OPS(omap_hsmmc_runtime_suspend, omap_hsmmc_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver omap_hsmmc_driver = {
|
||||
|
|
@ -2115,7 +2110,7 @@ static struct platform_driver omap_hsmmc_driver = {
|
|||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &omap_hsmmc_dev_pm_ops,
|
||||
.pm = pm_ptr(&omap_hsmmc_dev_pm_ops),
|
||||
.of_match_table = of_match_ptr(omap_mmc_of_match),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -222,7 +222,11 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
|
|||
clk &= ~0xff;
|
||||
}
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
|
||||
clock = clk & CLK_CTL_DIV_MASK;
|
||||
if (clock != CLK_CTL_DIV_MASK)
|
||||
host->mmc->actual_clock /= (1 << (ffs(clock) + 1));
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clock);
|
||||
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
|
||||
usleep_range(10000, 11000);
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,8 @@ static const struct renesas_sdhi_of_data of_data_rza2 = {
|
|||
|
||||
static const struct renesas_sdhi_of_data of_data_rcar_gen3 = {
|
||||
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
|
||||
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
|
||||
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 |
|
||||
TMIO_MMC_64BIT_DATA_PORT,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
|
||||
MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY,
|
||||
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE,
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ struct rtsx_usb_sdmmc {
|
|||
bool ddr_mode;
|
||||
|
||||
unsigned char power_mode;
|
||||
|
||||
u16 ocp_stat;
|
||||
#ifdef RTSX_USB_USE_LEDS_CLASS
|
||||
struct led_classdev led;
|
||||
char led_name[32];
|
||||
|
|
@ -789,12 +789,20 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
|
|||
if (err)
|
||||
goto no_card;
|
||||
|
||||
/* get OCP status */
|
||||
host->ocp_stat = (val >> 4) & 0x03;
|
||||
|
||||
if (val & SD_CD) {
|
||||
host->card_exist = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
no_card:
|
||||
/* clear OCP status */
|
||||
if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) {
|
||||
rtsx_usb_write_register(ucr, OCPCTL, MS_OCP_CLEAR, MS_OCP_CLEAR);
|
||||
host->ocp_stat = 0;
|
||||
}
|
||||
host->card_exist = false;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -818,7 +826,11 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||
cmd->error = -ENOMEDIUM;
|
||||
goto finish_detect_card;
|
||||
}
|
||||
|
||||
/* check OCP stat */
|
||||
if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) {
|
||||
cmd->error = -ENOMEDIUM;
|
||||
goto finish_detect_card;
|
||||
}
|
||||
mutex_lock(&ucr->dev_mutex);
|
||||
|
||||
mutex_lock(&host->host_mutex);
|
||||
|
|
@ -952,6 +964,10 @@ static int sd_power_on(struct rtsx_usb_sdmmc *host)
|
|||
struct rtsx_ucr *ucr = host->ucr;
|
||||
int err;
|
||||
|
||||
if (host->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) {
|
||||
dev_dbg(sdmmc_dev(host), "over current\n");
|
||||
return -EIO;
|
||||
}
|
||||
dev_dbg(sdmmc_dev(host), "%s\n", __func__);
|
||||
rtsx_usb_init_cmd(ucr);
|
||||
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL);
|
||||
|
|
@ -977,9 +993,19 @@ static int sd_power_on(struct rtsx_usb_sdmmc *host)
|
|||
|
||||
usleep_range(800, 1000);
|
||||
|
||||
rtsx_usb_init_cmd(ucr);
|
||||
/* WA OCP issue: after OCP, there were problems with reopen card power */
|
||||
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK, POWER_ON);
|
||||
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, FPDCTL, SSC_POWER_MASK, SSC_POWER_DOWN);
|
||||
err = rtsx_usb_send_cmd(ucr, MODE_C, 100);
|
||||
if (err)
|
||||
return err;
|
||||
msleep(20);
|
||||
rtsx_usb_write_register(ucr, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
|
||||
usleep_range(180, 200);
|
||||
rtsx_usb_init_cmd(ucr);
|
||||
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
|
||||
POWER_MASK|LDO3318_PWR_MASK, POWER_ON|LDO_ON);
|
||||
LDO3318_PWR_MASK, LDO_ON);
|
||||
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE,
|
||||
SD_OUTPUT_EN, SD_OUTPUT_EN);
|
||||
|
||||
|
|
@ -1332,6 +1358,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
|
|||
mmc->max_req_size = 524288;
|
||||
|
||||
host->power_mode = MMC_POWER_OFF;
|
||||
host->ocp_stat = 0;
|
||||
}
|
||||
|
||||
static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
|
||||
|
|
@ -1428,7 +1455,6 @@ static void rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
|
|||
": Realtek USB SD/MMC module has been removed\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int rtsx_usb_sdmmc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
|
||||
|
|
@ -1446,11 +1472,9 @@ static int rtsx_usb_sdmmc_runtime_resume(struct device *dev)
|
|||
mmc_detect_change(host->mmc, 0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops rtsx_usb_sdmmc_dev_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(rtsx_usb_sdmmc_runtime_suspend,
|
||||
rtsx_usb_sdmmc_runtime_resume, NULL)
|
||||
RUNTIME_PM_OPS(rtsx_usb_sdmmc_runtime_suspend, rtsx_usb_sdmmc_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct platform_device_id rtsx_usb_sdmmc_ids[] = {
|
||||
|
|
@ -1469,7 +1493,7 @@ static struct platform_driver rtsx_usb_sdmmc_driver = {
|
|||
.driver = {
|
||||
.name = "rtsx_usb_sdmmc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &rtsx_usb_sdmmc_dev_pm_ops,
|
||||
.pm = pm_ptr(&rtsx_usb_sdmmc_dev_pm_ops),
|
||||
},
|
||||
};
|
||||
module_platform_driver(rtsx_usb_sdmmc_driver);
|
||||
|
|
|
|||
|
|
@ -973,8 +973,7 @@ static void sdhci_acpi_remove(struct platform_device *pdev)
|
|||
c->slot->free_slot(pdev);
|
||||
}
|
||||
|
||||
static void __maybe_unused sdhci_acpi_reset_signal_voltage_if_needed(
|
||||
struct device *dev)
|
||||
static void sdhci_acpi_reset_signal_voltage_if_needed(struct device *dev)
|
||||
{
|
||||
struct sdhci_acpi_host *c = dev_get_drvdata(dev);
|
||||
struct sdhci_host *host = c->host;
|
||||
|
|
@ -989,8 +988,6 @@ static void __maybe_unused sdhci_acpi_reset_signal_voltage_if_needed(
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int sdhci_acpi_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_acpi_host *c = dev_get_drvdata(dev);
|
||||
|
|
@ -1017,10 +1014,6 @@ static int sdhci_acpi_resume(struct device *dev)
|
|||
return sdhci_resume_host(c->host);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int sdhci_acpi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_acpi_host *c = dev_get_drvdata(dev);
|
||||
|
|
@ -1045,12 +1038,9 @@ static int sdhci_acpi_runtime_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_acpi_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sdhci_acpi_suspend, sdhci_acpi_resume)
|
||||
SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend,
|
||||
sdhci_acpi_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(sdhci_acpi_suspend, sdhci_acpi_resume)
|
||||
RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend, sdhci_acpi_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_acpi_driver = {
|
||||
|
|
@ -1058,7 +1048,7 @@ static struct platform_driver sdhci_acpi_driver = {
|
|||
.name = "sdhci-acpi",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.acpi_match_table = sdhci_acpi_ids,
|
||||
.pm = &sdhci_acpi_pm_ops,
|
||||
.pm = pm_ptr(&sdhci_acpi_pm_ops),
|
||||
},
|
||||
.probe = sdhci_acpi_probe,
|
||||
.remove = sdhci_acpi_remove,
|
||||
|
|
|
|||
|
|
@ -496,7 +496,6 @@ static void sdhci_brcmstb_shutdown(struct platform_device *pdev)
|
|||
|
||||
MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_brcmstb_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -540,17 +539,14 @@ static int sdhci_brcmstb_resume(struct device *dev)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_brcmstb_pmops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sdhci_brcmstb_suspend, sdhci_brcmstb_resume)
|
||||
};
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(sdhci_brcmstb_pmops, sdhci_brcmstb_suspend, sdhci_brcmstb_resume);
|
||||
|
||||
static struct platform_driver sdhci_brcmstb_driver = {
|
||||
.driver = {
|
||||
.name = "sdhci-brcmstb",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &sdhci_brcmstb_pmops,
|
||||
.pm = pm_sleep_ptr(&sdhci_brcmstb_pmops),
|
||||
.of_match_table = of_match_ptr(sdhci_brcm_of_match),
|
||||
},
|
||||
.probe = sdhci_brcmstb_probe,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,24 @@
|
|||
#define SDHCI_CDNS_HRS06_MODE_MMC_HS400 0x5
|
||||
#define SDHCI_CDNS_HRS06_MODE_MMC_HS400ES 0x6
|
||||
|
||||
/* Read block gap */
|
||||
#define SDHCI_CDNS_HRS37 0x94 /* interface mode select */
|
||||
#define SDHCI_CDNS_HRS37_MODE_DS 0x0
|
||||
#define SDHCI_CDNS_HRS37_MODE_HS 0x1
|
||||
#define SDHCI_CDNS_HRS37_MODE_UDS_SDR12 0x8
|
||||
#define SDHCI_CDNS_HRS37_MODE_UDS_SDR25 0x9
|
||||
#define SDHCI_CDNS_HRS37_MODE_UDS_SDR50 0xa
|
||||
#define SDHCI_CDNS_HRS37_MODE_UDS_SDR104 0xb
|
||||
#define SDHCI_CDNS_HRS37_MODE_UDS_DDR50 0xc
|
||||
#define SDHCI_CDNS_HRS37_MODE_MMC_LEGACY 0x20
|
||||
#define SDHCI_CDNS_HRS37_MODE_MMC_SDR 0x21
|
||||
#define SDHCI_CDNS_HRS37_MODE_MMC_DDR 0x22
|
||||
#define SDHCI_CDNS_HRS37_MODE_MMC_HS200 0x23
|
||||
#define SDHCI_CDNS_HRS37_MODE_MMC_HS400 0x24
|
||||
#define SDHCI_CDNS_HRS37_MODE_MMC_HS400ES 0x25
|
||||
#define SDHCI_CDNS_HRS38 0x98 /* Read block gap coefficient */
|
||||
#define SDHCI_CDNS_HRS38_BLKGAP_MAX 0xf
|
||||
|
||||
/* SRS - Slot Register Set (SDHCI-compatible) */
|
||||
#define SDHCI_CDNS_SRS_BASE 0x200
|
||||
|
||||
|
|
@ -251,6 +269,43 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sdhci_cdns_tune_blkgap() - tune multi-block read gap
|
||||
* @mmc: MMC host
|
||||
*
|
||||
* Tune delay used in multi block read. To do so,
|
||||
* try sending multi-block read command with incremented gap, unless
|
||||
* it succeeds.
|
||||
*
|
||||
* Return: error code
|
||||
*/
|
||||
static int sdhci_cdns_tune_blkgap(struct mmc_host *mmc)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_cdns_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
void __iomem *hrs37_reg = priv->hrs_addr + SDHCI_CDNS_HRS37;
|
||||
void __iomem *hrs38_reg = priv->hrs_addr + SDHCI_CDNS_HRS38;
|
||||
int ret;
|
||||
u32 gap;
|
||||
|
||||
/* Currently only needed in HS200 mode */
|
||||
if (host->timing != MMC_TIMING_MMC_HS200)
|
||||
return 0;
|
||||
|
||||
writel(SDHCI_CDNS_HRS37_MODE_MMC_HS200, hrs37_reg);
|
||||
|
||||
for (gap = 0; gap <= SDHCI_CDNS_HRS38_BLKGAP_MAX; gap++) {
|
||||
writel(gap, hrs38_reg);
|
||||
ret = mmc_read_tuning(mmc, 512, 32);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(mmc_dev(mmc), "read block gap tune %s, gap %d\n", ret ? "failed" : "OK", gap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* In SD mode, software must not use the hardware tuning and instead perform
|
||||
* an almost identical procedure to eMMC.
|
||||
|
|
@ -261,6 +316,7 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
|
|||
int max_streak = 0;
|
||||
int end_of_streak = 0;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Do not execute tuning for UHS_SDR50 or UHS_DDR50.
|
||||
|
|
@ -288,7 +344,11 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
|
||||
ret = sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sdhci_cdns_tune_blkgap(host->mmc);
|
||||
}
|
||||
|
||||
static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
|
||||
|
|
@ -551,7 +611,6 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
|
|||
return sdhci_add_host(host);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_cdns_resume(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -578,11 +637,8 @@ static int sdhci_cdns_resume(struct device *dev)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_cdns_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_cdns_resume)
|
||||
};
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(sdhci_cdns_pm_ops, sdhci_pltfm_suspend, sdhci_cdns_resume);
|
||||
|
||||
static const struct of_device_id sdhci_cdns_match[] = {
|
||||
{
|
||||
|
|
@ -606,7 +662,7 @@ static struct platform_driver sdhci_cdns_driver = {
|
|||
.driver = {
|
||||
.name = "sdhci-cdns",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &sdhci_cdns_pm_ops,
|
||||
.pm = pm_sleep_ptr(&sdhci_cdns_pm_ops),
|
||||
.of_match_table = sdhci_cdns_match,
|
||||
},
|
||||
.probe = sdhci_cdns_probe,
|
||||
|
|
|
|||
|
|
@ -1650,7 +1650,6 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static void sdhc_esdhc_tuning_save(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -1707,7 +1706,6 @@ static void sdhc_esdhc_tuning_restore(struct sdhci_host *host)
|
|||
host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void esdhc_cqe_enable(struct mmc_host *mmc)
|
||||
{
|
||||
|
|
@ -2016,7 +2014,6 @@ static void sdhci_esdhc_imx_remove(struct platform_device *pdev)
|
|||
cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_esdhc_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -2112,9 +2109,7 @@ static int sdhci_esdhc_resume(struct device *dev)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sdhci_esdhc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -2188,12 +2183,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
|
|||
cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_esdhc_pmops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume)
|
||||
SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
|
||||
sdhci_esdhc_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume)
|
||||
RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend, sdhci_esdhc_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_esdhc_imx_driver = {
|
||||
|
|
@ -2201,7 +2194,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
|
|||
.name = "sdhci-esdhc-imx",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = imx_esdhc_dt_ids,
|
||||
.pm = &sdhci_esdhc_pmops,
|
||||
.pm = pm_ptr(&sdhci_esdhc_pmops),
|
||||
},
|
||||
.probe = sdhci_esdhc_imx_probe,
|
||||
.remove = sdhci_esdhc_imx_remove,
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
#define CORE_IO_PAD_PWR_SWITCH_EN BIT(15)
|
||||
#define CORE_IO_PAD_PWR_SWITCH BIT(16)
|
||||
#define CORE_HC_SELECT_IN_EN BIT(18)
|
||||
#define CORE_HC_SELECT_IN_SDR50 (4 << 19)
|
||||
#define CORE_HC_SELECT_IN_HS400 (6 << 19)
|
||||
#define CORE_HC_SELECT_IN_MASK (7 << 19)
|
||||
|
||||
|
|
@ -1133,6 +1134,10 @@ static bool sdhci_msm_is_tuning_needed(struct sdhci_host *host)
|
|||
{
|
||||
struct mmc_ios *ios = &host->mmc->ios;
|
||||
|
||||
if (ios->timing == MMC_TIMING_UHS_SDR50 &&
|
||||
host->flags & SDHCI_SDR50_NEEDS_TUNING)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Tuning is required for SDR104, HS200 and HS400 cards and
|
||||
* if clock frequency is greater than 100MHz in these modes.
|
||||
|
|
@ -1201,6 +1206,8 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||
struct mmc_ios ios = host->mmc->ios;
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||
const struct sdhci_msm_offset *msm_offset = msm_host->offset;
|
||||
u32 config;
|
||||
|
||||
if (!sdhci_msm_is_tuning_needed(host)) {
|
||||
msm_host->use_cdr = false;
|
||||
|
|
@ -1217,6 +1224,14 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||
*/
|
||||
msm_host->tuning_done = 0;
|
||||
|
||||
if (ios.timing == MMC_TIMING_UHS_SDR50 &&
|
||||
host->flags & SDHCI_SDR50_NEEDS_TUNING) {
|
||||
config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
|
||||
config &= ~CORE_HC_SELECT_IN_MASK;
|
||||
config |= CORE_HC_SELECT_IN_EN | CORE_HC_SELECT_IN_SDR50;
|
||||
writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
|
||||
}
|
||||
|
||||
/*
|
||||
* For HS400 tuning in HS200 timing requires:
|
||||
* - select MCLK/2 in VENDOR_SPEC
|
||||
|
|
@ -1943,7 +1958,7 @@ static void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host)
|
|||
qcom_ice_enable(msm_host->ice);
|
||||
}
|
||||
|
||||
static __maybe_unused int sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host)
|
||||
static int sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host)
|
||||
{
|
||||
if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)
|
||||
return qcom_ice_resume(msm_host->ice);
|
||||
|
|
@ -1951,7 +1966,7 @@ static __maybe_unused int sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int sdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host)
|
||||
static int sdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host)
|
||||
{
|
||||
if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)
|
||||
return qcom_ice_suspend(msm_host->ice);
|
||||
|
|
@ -2011,13 +2026,13 @@ static inline void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host)
|
|||
{
|
||||
}
|
||||
|
||||
static inline __maybe_unused int
|
||||
static inline int
|
||||
sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline __maybe_unused int
|
||||
static inline int
|
||||
sdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host)
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -2801,7 +2816,7 @@ static void sdhci_msm_remove(struct platform_device *pdev)
|
|||
clk_disable_unprepare(msm_host->bus_clk);
|
||||
}
|
||||
|
||||
static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev)
|
||||
static int sdhci_msm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -2820,7 +2835,7 @@ static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev)
|
|||
return sdhci_msm_ice_suspend(msm_host);
|
||||
}
|
||||
|
||||
static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev)
|
||||
static int sdhci_msm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -2856,11 +2871,8 @@ static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops sdhci_msm_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend,
|
||||
sdhci_msm_runtime_resume,
|
||||
NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_msm_driver = {
|
||||
|
|
@ -2869,7 +2881,7 @@ static struct platform_driver sdhci_msm_driver = {
|
|||
.driver = {
|
||||
.name = "sdhci_msm",
|
||||
.of_match_table = sdhci_msm_dt_match,
|
||||
.pm = &sdhci_msm_pm_ops,
|
||||
.pm = pm_ptr(&sdhci_msm_pm_ops),
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -605,7 +605,6 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
|
|||
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
* sdhci_arasan_suspend - Suspend method for the driver
|
||||
* @dev: Address of the device structure
|
||||
|
|
@ -699,10 +698,9 @@ static int sdhci_arasan_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif /* ! CONFIG_PM_SLEEP */
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
|
||||
sdhci_arasan_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
|
||||
sdhci_arasan_resume);
|
||||
|
||||
/**
|
||||
* sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate
|
||||
|
|
@ -2080,7 +2078,7 @@ static struct platform_driver sdhci_arasan_driver = {
|
|||
.name = "sdhci-arasan",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_arasan_of_match,
|
||||
.pm = &sdhci_arasan_dev_pm_ops,
|
||||
.pm = pm_sleep_ptr(&sdhci_arasan_dev_pm_ops),
|
||||
},
|
||||
.probe = sdhci_arasan_probe,
|
||||
.remove = sdhci_arasan_remove,
|
||||
|
|
|
|||
|
|
@ -229,7 +229,6 @@ static int sdhci_at91_set_clks_presets(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_at91_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -243,9 +242,7 @@ static int sdhci_at91_suspend(struct device *dev)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sdhci_at91_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -302,13 +299,10 @@ static int sdhci_at91_runtime_resume(struct device *dev)
|
|||
sdhci_runtime_resume_host(host, 0);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct dev_pm_ops sdhci_at91_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sdhci_at91_suspend, pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(sdhci_at91_runtime_suspend,
|
||||
sdhci_at91_runtime_resume,
|
||||
NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(sdhci_at91_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(sdhci_at91_runtime_suspend, sdhci_at91_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static int sdhci_at91_probe(struct platform_device *pdev)
|
||||
|
|
@ -460,7 +454,7 @@ static struct platform_driver sdhci_at91_driver = {
|
|||
.name = "sdhci-at91",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_at91_dt_match,
|
||||
.pm = &sdhci_at91_dev_pm_ops,
|
||||
.pm = pm_ptr(&sdhci_at91_dev_pm_ops),
|
||||
},
|
||||
.probe = sdhci_at91_probe,
|
||||
.remove = sdhci_at91_remove,
|
||||
|
|
|
|||
|
|
@ -1499,7 +1499,6 @@ static void dwcmshc_remove(struct platform_device *pdev)
|
|||
clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dwcmshc_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -1570,9 +1569,6 @@ static int dwcmshc_resume(struct device *dev)
|
|||
clk_disable_unprepare(pltfm_host->clk);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static void dwcmshc_enable_card_clk(struct sdhci_host *host)
|
||||
{
|
||||
|
|
@ -1603,12 +1599,9 @@ static int dwcmshc_runtime_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops dwcmshc_pmops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend, dwcmshc_resume)
|
||||
SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend,
|
||||
dwcmshc_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend, dwcmshc_resume)
|
||||
RUNTIME_PM_OPS(dwcmshc_runtime_suspend, dwcmshc_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_dwcmshc_driver = {
|
||||
|
|
@ -1617,7 +1610,7 @@ static struct platform_driver sdhci_dwcmshc_driver = {
|
|||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_dwcmshc_dt_ids,
|
||||
.acpi_match_table = ACPI_PTR(sdhci_dwcmshc_acpi_ids),
|
||||
.pm = &dwcmshc_pmops,
|
||||
.pm = pm_ptr(&dwcmshc_pmops),
|
||||
},
|
||||
.probe = dwcmshc_probe,
|
||||
.remove = dwcmshc_remove,
|
||||
|
|
|
|||
|
|
@ -1234,7 +1234,6 @@ static u32 esdhc_irq(struct sdhci_host *host, u32 intmask)
|
|||
return intmask;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static u32 esdhc_proctl;
|
||||
static int esdhc_of_suspend(struct device *dev)
|
||||
{
|
||||
|
|
@ -1260,11 +1259,8 @@ static int esdhc_of_resume(struct device *dev)
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops,
|
||||
esdhc_of_suspend,
|
||||
esdhc_of_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops, esdhc_of_suspend, esdhc_of_resume);
|
||||
|
||||
static const struct sdhci_ops sdhci_esdhc_be_ops = {
|
||||
.read_l = esdhc_be_readl,
|
||||
|
|
@ -1511,7 +1507,7 @@ static struct platform_driver sdhci_esdhc_driver = {
|
|||
.name = "sdhci-esdhc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_esdhc_of_match,
|
||||
.pm = &esdhc_of_dev_pm_ops,
|
||||
.pm = pm_sleep_ptr(&esdhc_of_dev_pm_ops),
|
||||
},
|
||||
.probe = sdhci_esdhc_probe,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
|
|
|
|||
|
|
@ -1400,8 +1400,7 @@ static void sdhci_omap_remove(struct platform_device *pdev)
|
|||
pm_runtime_force_suspend(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void __maybe_unused sdhci_omap_context_save(struct sdhci_omap_host *omap_host)
|
||||
static void sdhci_omap_context_save(struct sdhci_omap_host *omap_host)
|
||||
{
|
||||
omap_host->con = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON);
|
||||
omap_host->hctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL);
|
||||
|
|
@ -1412,7 +1411,7 @@ static void __maybe_unused sdhci_omap_context_save(struct sdhci_omap_host *omap_
|
|||
}
|
||||
|
||||
/* Order matters here, HCTL must be restored in two phases */
|
||||
static void __maybe_unused sdhci_omap_context_restore(struct sdhci_omap_host *omap_host)
|
||||
static void sdhci_omap_context_restore(struct sdhci_omap_host *omap_host)
|
||||
{
|
||||
sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl);
|
||||
sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, omap_host->capa);
|
||||
|
|
@ -1424,7 +1423,7 @@ static void __maybe_unused sdhci_omap_context_restore(struct sdhci_omap_host *om
|
|||
sdhci_omap_writel(omap_host, SDHCI_OMAP_ISE, omap_host->ise);
|
||||
}
|
||||
|
||||
static int __maybe_unused sdhci_omap_runtime_suspend(struct device *dev)
|
||||
static int sdhci_omap_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -1443,7 +1442,7 @@ static int __maybe_unused sdhci_omap_runtime_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused sdhci_omap_runtime_resume(struct device *dev)
|
||||
static int sdhci_omap_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -1458,13 +1457,10 @@ static int __maybe_unused sdhci_omap_runtime_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_omap_dev_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(sdhci_omap_runtime_suspend,
|
||||
sdhci_omap_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(sdhci_omap_runtime_suspend, sdhci_omap_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_omap_driver = {
|
||||
|
|
@ -1473,7 +1469,7 @@ static struct platform_driver sdhci_omap_driver = {
|
|||
.driver = {
|
||||
.name = "sdhci-omap",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &sdhci_omap_dev_pm_ops,
|
||||
.pm = pm_ptr(&sdhci_omap_dev_pm_ops),
|
||||
.of_match_table = omap_sdhci_match,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -679,8 +679,19 @@ static int intel_start_signal_voltage_switch(struct mmc_host *mmc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void sdhci_intel_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
/* Stop card clock separately to avoid glitches on clock line */
|
||||
if (clk & SDHCI_CLOCK_CARD_EN)
|
||||
sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
sdhci_set_clock(host, clock);
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_intel_byt_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_clock = sdhci_intel_set_clock,
|
||||
.set_power = sdhci_intel_set_power,
|
||||
.enable_dma = sdhci_pci_enable_dma,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
|
|
@ -690,7 +701,7 @@ static const struct sdhci_ops sdhci_intel_byt_ops = {
|
|||
};
|
||||
|
||||
static const struct sdhci_ops sdhci_intel_glk_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_clock = sdhci_intel_set_clock,
|
||||
.set_power = sdhci_intel_set_power,
|
||||
.enable_dma = sdhci_pci_enable_dma,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/mbus.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include "sdhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
|
|
@ -51,6 +53,9 @@ struct sdhci_pxa {
|
|||
struct clk *clk_io;
|
||||
u8 power_mode;
|
||||
void __iomem *sdio3_conf_reg;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default;
|
||||
struct pinctrl_state *pins_uhs;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -313,8 +318,20 @@ static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
|
|||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
|
||||
}
|
||||
|
||||
static void pxav3_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
struct sdhci_pltfm_host *phost = sdhci_priv(host);
|
||||
struct sdhci_pxa *pxa = sdhci_pltfm_priv(phost);
|
||||
struct pinctrl_state *pins = clock < 100 * HZ_PER_MHZ ? pxa->pins_default : pxa->pins_uhs;
|
||||
|
||||
if (pins)
|
||||
pinctrl_select_state(pxa->pinctrl, pins);
|
||||
|
||||
sdhci_set_clock(host, clock);
|
||||
}
|
||||
|
||||
static const struct sdhci_ops pxav3_sdhci_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_clock = pxav3_set_clock,
|
||||
.set_power = pxav3_set_power,
|
||||
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
|
||||
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||
|
|
@ -366,6 +383,19 @@ static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct pinctrl_state *pxav3_lookup_pinstate(struct device *dev, struct pinctrl *pinctrl,
|
||||
const char *name)
|
||||
{
|
||||
struct pinctrl_state *pins = pinctrl_lookup_state(pinctrl, name);
|
||||
|
||||
if (IS_ERR(pins)) {
|
||||
dev_dbg(dev, "could not get pinstate '%s': %ld\n", name, PTR_ERR(pins));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pins;
|
||||
}
|
||||
|
||||
static int sdhci_pxav3_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
|
|
@ -440,6 +470,15 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
|
|||
host->mmc->pm_caps |= pdata->pm_caps;
|
||||
}
|
||||
|
||||
pxa->pinctrl = devm_pinctrl_get(dev);
|
||||
if (!IS_ERR(pxa->pinctrl)) {
|
||||
pxa->pins_default = pxav3_lookup_pinstate(dev, pxa->pinctrl, "default");
|
||||
if (pxa->pins_default)
|
||||
pxa->pins_uhs = pxav3_lookup_pinstate(dev, pxa->pinctrl, "state_uhs");
|
||||
} else {
|
||||
dev_dbg(dev, "could not get pinctrl handle: %ld\n", PTR_ERR(pxa->pinctrl));
|
||||
}
|
||||
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS);
|
||||
|
|
@ -484,7 +523,6 @@ static void sdhci_pxav3_remove(struct platform_device *pdev)
|
|||
clk_disable_unprepare(pxa->clk_core);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_pxav3_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -510,9 +548,7 @@ static int sdhci_pxav3_resume(struct device *dev)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sdhci_pxav3_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -544,12 +580,10 @@ static int sdhci_pxav3_runtime_resume(struct device *dev)
|
|||
sdhci_runtime_resume_host(host, 0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_pxav3_pmops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume)
|
||||
SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend,
|
||||
sdhci_pxav3_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume)
|
||||
RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend, sdhci_pxav3_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_pxav3_driver = {
|
||||
|
|
@ -557,7 +591,7 @@ static struct platform_driver sdhci_pxav3_driver = {
|
|||
.name = "sdhci-pxav3",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = of_match_ptr(sdhci_pxav3_of_match),
|
||||
.pm = &sdhci_pxav3_pmops,
|
||||
.pm = pm_ptr(&sdhci_pxav3_pmops),
|
||||
},
|
||||
.probe = sdhci_pxav3_probe,
|
||||
.remove = sdhci_pxav3_remove,
|
||||
|
|
|
|||
|
|
@ -681,7 +681,6 @@ static void sdhci_s3c_remove(struct platform_device *pdev)
|
|||
clk_disable_unprepare(sc->clk_io);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_s3c_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -698,9 +697,7 @@ static int sdhci_s3c_resume(struct device *dev)
|
|||
|
||||
return sdhci_resume_host(host);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sdhci_s3c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -730,12 +727,10 @@ static int sdhci_s3c_runtime_resume(struct device *dev)
|
|||
sdhci_runtime_resume_host(host, 0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_s3c_pmops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume)
|
||||
SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume,
|
||||
NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume)
|
||||
RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct platform_device_id sdhci_s3c_driver_ids[] = {
|
||||
|
|
@ -770,7 +765,7 @@ static struct platform_driver sdhci_s3c_driver = {
|
|||
.name = "s3c-sdhci",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = of_match_ptr(sdhci_s3c_dt_match),
|
||||
.pm = &sdhci_s3c_pmops,
|
||||
.pm = pm_ptr(&sdhci_s3c_pmops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ static void sdhci_remove(struct platform_device *pdev)
|
|||
clk_disable_unprepare(sdhci->clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -161,9 +160,8 @@ static int sdhci_resume(struct device *dev)
|
|||
|
||||
return sdhci_resume_host(host);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume);
|
||||
|
||||
static const struct of_device_id sdhci_spear_id_table[] = {
|
||||
{ .compatible = "st,spear300-sdhci" },
|
||||
|
|
@ -175,7 +173,7 @@ static struct platform_driver sdhci_driver = {
|
|||
.driver = {
|
||||
.name = "sdhci",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &sdhci_pm_ops,
|
||||
.pm = pm_sleep_ptr(&sdhci_pm_ops),
|
||||
.of_match_table = sdhci_spear_id_table,
|
||||
},
|
||||
.probe = sdhci_probe,
|
||||
|
|
|
|||
|
|
@ -903,7 +903,6 @@ static const struct of_device_id sdhci_sprd_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, sdhci_sprd_of_match);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sdhci_sprd_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -950,13 +949,10 @@ static int sdhci_sprd_runtime_resume(struct device *dev)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_sprd_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(sdhci_sprd_runtime_suspend,
|
||||
sdhci_sprd_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(sdhci_sprd_runtime_suspend, sdhci_sprd_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_sprd_driver = {
|
||||
|
|
@ -966,7 +962,7 @@ static struct platform_driver sdhci_sprd_driver = {
|
|||
.name = "sdhci_sprd_r11",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_sprd_of_match,
|
||||
.pm = &sdhci_sprd_pm_ops,
|
||||
.pm = pm_ptr(&sdhci_sprd_pm_ops),
|
||||
},
|
||||
};
|
||||
module_platform_driver(sdhci_sprd_driver);
|
||||
|
|
|
|||
|
|
@ -445,7 +445,6 @@ static void sdhci_st_remove(struct platform_device *pdev)
|
|||
reset_control_assert(rstc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_st_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -492,9 +491,8 @@ static int sdhci_st_resume(struct device *dev)
|
|||
|
||||
return sdhci_resume_host(host);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(sdhci_st_pmops, sdhci_st_suspend, sdhci_st_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(sdhci_st_pmops, sdhci_st_suspend, sdhci_st_resume);
|
||||
|
||||
static const struct of_device_id st_sdhci_match[] = {
|
||||
{ .compatible = "st,sdhci" },
|
||||
|
|
@ -509,7 +507,7 @@ static struct platform_driver sdhci_st_driver = {
|
|||
.driver = {
|
||||
.name = "sdhci-st",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &sdhci_st_pmops,
|
||||
.pm = pm_sleep_ptr(&sdhci_st_pmops),
|
||||
.of_match_table = st_sdhci_match,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1831,7 +1831,7 @@ static void sdhci_tegra_remove(struct platform_device *pdev)
|
|||
clk_disable_unprepare(tegra_host->tmclk);
|
||||
}
|
||||
|
||||
static int __maybe_unused sdhci_tegra_runtime_suspend(struct device *dev)
|
||||
static int sdhci_tegra_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -1841,7 +1841,7 @@ static int __maybe_unused sdhci_tegra_runtime_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused sdhci_tegra_runtime_resume(struct device *dev)
|
||||
static int sdhci_tegra_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -1849,7 +1849,6 @@ static int __maybe_unused sdhci_tegra_runtime_resume(struct device *dev)
|
|||
return clk_prepare_enable(pltfm_host->clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_tegra_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -1910,12 +1909,10 @@ static int sdhci_tegra_resume(struct device *dev)
|
|||
pm_runtime_force_suspend(dev);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_tegra_dev_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(sdhci_tegra_runtime_suspend, sdhci_tegra_runtime_resume,
|
||||
NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sdhci_tegra_suspend, sdhci_tegra_resume)
|
||||
RUNTIME_PM_OPS(sdhci_tegra_runtime_suspend, sdhci_tegra_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(sdhci_tegra_suspend, sdhci_tegra_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_tegra_driver = {
|
||||
|
|
@ -1923,7 +1920,7 @@ static struct platform_driver sdhci_tegra_driver = {
|
|||
.name = "sdhci-tegra",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_tegra_dt_match,
|
||||
.pm = &sdhci_tegra_dev_pm_ops,
|
||||
.pm = pm_ptr(&sdhci_tegra_dev_pm_ops),
|
||||
},
|
||||
.probe = sdhci_tegra_probe,
|
||||
.remove = sdhci_tegra_remove,
|
||||
|
|
|
|||
|
|
@ -622,7 +622,6 @@ static void xenon_remove(struct platform_device *pdev)
|
|||
clk_disable_unprepare(pltfm_host->clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int xenon_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -635,9 +634,7 @@ static int xenon_suspend(struct device *dev)
|
|||
priv->restore_needed = true;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int xenon_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -685,14 +682,10 @@ static int xenon_runtime_resume(struct device *dev)
|
|||
clk_disable_unprepare(pltfm_host->clk);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(xenon_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(xenon_runtime_suspend,
|
||||
xenon_runtime_resume,
|
||||
NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(xenon_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(xenon_runtime_suspend, xenon_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct of_device_id sdhci_xenon_dt_ids[] = {
|
||||
|
|
@ -721,7 +714,7 @@ static struct platform_driver sdhci_xenon_driver = {
|
|||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_xenon_dt_ids,
|
||||
.acpi_match_table = ACPI_PTR(sdhci_xenon_acpi_ids),
|
||||
.pm = &sdhci_xenon_dev_pm_ops,
|
||||
.pm = pm_ptr(&sdhci_xenon_dev_pm_ops),
|
||||
},
|
||||
.probe = xenon_probe,
|
||||
.remove = xenon_remove,
|
||||
|
|
|
|||
|
|
@ -880,6 +880,13 @@ int sdhci_suspend_host(struct sdhci_host *host);
|
|||
int sdhci_resume_host(struct sdhci_host *host);
|
||||
void sdhci_runtime_suspend_host(struct sdhci_host *host);
|
||||
void sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset);
|
||||
#else
|
||||
static inline bool sdhci_enable_irq_wakeups(struct sdhci_host *host) { return false; }
|
||||
static inline void sdhci_disable_irq_wakeups(struct sdhci_host *host) {}
|
||||
static inline int sdhci_suspend_host(struct sdhci_host *host) { return -EOPNOTSUPP; }
|
||||
static inline int sdhci_resume_host(struct sdhci_host *host) { return -EOPNOTSUPP; }
|
||||
static inline void sdhci_runtime_suspend_host(struct sdhci_host *host) {}
|
||||
static inline void sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset) {}
|
||||
#endif
|
||||
|
||||
void sdhci_cqe_enable(struct mmc_host *mmc);
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@ static const struct regmap_config sdhci_am654_regmap_config = {
|
|||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
struct timing_data {
|
||||
|
|
@ -1036,7 +1035,6 @@ static void sdhci_am654_remove(struct platform_device *pdev)
|
|||
pm_runtime_put_noidle(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sdhci_am654_restore(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -1124,20 +1122,17 @@ static int sdhci_am654_runtime_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sdhci_am654_dev_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(sdhci_am654_runtime_suspend,
|
||||
sdhci_am654_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(sdhci_am654_runtime_suspend, sdhci_am654_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver sdhci_am654_driver = {
|
||||
.driver = {
|
||||
.name = "sdhci-am654",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &sdhci_am654_dev_pm_ops,
|
||||
.pm = pm_ptr(&sdhci_am654_dev_pm_ops),
|
||||
.of_match_table = sdhci_am654_of_match,
|
||||
},
|
||||
.probe = sdhci_am654_probe,
|
||||
|
|
|
|||
|
|
@ -1568,7 +1568,6 @@ static void sh_mmcif_remove(struct platform_device *pdev)
|
|||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sh_mmcif_suspend(struct device *dev)
|
||||
{
|
||||
struct sh_mmcif_host *host = dev_get_drvdata(dev);
|
||||
|
|
@ -1580,15 +1579,7 @@ static int sh_mmcif_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sh_mmcif_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sh_mmcif_suspend, sh_mmcif_resume)
|
||||
};
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(sh_mmcif_dev_pm_ops, sh_mmcif_suspend, NULL);
|
||||
|
||||
static struct platform_driver sh_mmcif_driver = {
|
||||
.probe = sh_mmcif_probe,
|
||||
|
|
@ -1596,7 +1587,7 @@ static struct platform_driver sh_mmcif_driver = {
|
|||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &sh_mmcif_dev_pm_ops,
|
||||
.pm = pm_sleep_ptr(&sh_mmcif_dev_pm_ops),
|
||||
.of_match_table = sh_mmcif_of_match,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1495,7 +1495,6 @@ static void sunxi_mmc_remove(struct platform_device *pdev)
|
|||
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sunxi_mmc_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
|
|
@ -1530,14 +1529,10 @@ static int sunxi_mmc_runtime_suspend(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sunxi_mmc_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(sunxi_mmc_runtime_suspend,
|
||||
sunxi_mmc_runtime_resume,
|
||||
NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(sunxi_mmc_runtime_suspend, sunxi_mmc_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver sunxi_mmc_driver = {
|
||||
|
|
@ -1545,7 +1540,7 @@ static struct platform_driver sunxi_mmc_driver = {
|
|||
.name = "sunxi-mmc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sunxi_mmc_of_match,
|
||||
.pm = &sunxi_mmc_pm_ops,
|
||||
.pm = pm_ptr(&sunxi_mmc_pm_ops),
|
||||
},
|
||||
.probe = sunxi_mmc_probe,
|
||||
.remove = sunxi_mmc_remove,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
|
@ -242,6 +243,20 @@ static inline void sd_ctrl_read32_rep(struct tmio_mmc_host *host, int addr,
|
|||
ioread32_rep(host->ctl + (addr << host->bus_shift), buf, count);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
static inline void sd_ctrl_read64_rep(struct tmio_mmc_host *host, int addr,
|
||||
u64 *buf, int count)
|
||||
{
|
||||
readsq(host->ctl + (addr << host->bus_shift), buf, count);
|
||||
}
|
||||
|
||||
static inline void sd_ctrl_write64_rep(struct tmio_mmc_host *host, int addr,
|
||||
const u64 *buf, int count)
|
||||
{
|
||||
writesq(host->ctl + (addr << host->bus_shift), buf, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr,
|
||||
u16 val)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -349,6 +349,39 @@ static void tmio_mmc_transfer_data(struct tmio_mmc_host *host,
|
|||
/*
|
||||
* Transfer the data
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
if (host->pdata->flags & TMIO_MMC_64BIT_DATA_PORT) {
|
||||
u64 *buf64 = (u64 *)buf;
|
||||
u64 data = 0;
|
||||
|
||||
if (count >= 8) {
|
||||
if (is_read)
|
||||
sd_ctrl_read64_rep(host, CTL_SD_DATA_PORT,
|
||||
buf64, count >> 3);
|
||||
else
|
||||
sd_ctrl_write64_rep(host, CTL_SD_DATA_PORT,
|
||||
buf64, count >> 3);
|
||||
}
|
||||
|
||||
/* if count was multiple of 8 */
|
||||
if (!(count & 0x7))
|
||||
return;
|
||||
|
||||
buf64 += count >> 3;
|
||||
count %= 8;
|
||||
|
||||
if (is_read) {
|
||||
sd_ctrl_read64_rep(host, CTL_SD_DATA_PORT, &data, 1);
|
||||
memcpy(buf64, &data, count);
|
||||
} else {
|
||||
memcpy(&data, buf64, count);
|
||||
sd_ctrl_write64_rep(host, CTL_SD_DATA_PORT, &data, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (host->pdata->flags & TMIO_MMC_32BIT_DATA_PORT) {
|
||||
u32 data = 0;
|
||||
u32 *buf32 = (u32 *)buf;
|
||||
|
|
|
|||
|
|
@ -567,7 +567,6 @@ static void toshsd_powerdown(struct toshsd_host *host)
|
|||
pci_write_config_byte(host->pdev, SD_PCICFG_CLKSTOP, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int toshsd_pm_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
|
@ -599,7 +598,6 @@ static int toshsd_pm_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
|
|
@ -688,16 +686,14 @@ static void toshsd_remove(struct pci_dev *pdev)
|
|||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops toshsd_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(toshsd_pm_suspend, toshsd_pm_resume)
|
||||
};
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(toshsd_pm_ops, toshsd_pm_suspend, toshsd_pm_resume);
|
||||
|
||||
static struct pci_driver toshsd_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pci_ids,
|
||||
.probe = toshsd_probe,
|
||||
.remove = toshsd_remove,
|
||||
.driver.pm = &toshsd_pm_ops,
|
||||
.driver.pm = pm_sleep_ptr(&toshsd_pm_ops),
|
||||
};
|
||||
|
||||
module_pci_driver(toshsd_driver);
|
||||
|
|
|
|||
|
|
@ -1218,7 +1218,7 @@ static void via_sd_remove(struct pci_dev *pcidev)
|
|||
pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device);
|
||||
}
|
||||
|
||||
static void __maybe_unused via_init_sdc_pm(struct via_crdr_mmc_host *host)
|
||||
static void via_init_sdc_pm(struct via_crdr_mmc_host *host)
|
||||
{
|
||||
struct sdhcreg *pm_sdhcreg;
|
||||
void __iomem *addrbase;
|
||||
|
|
@ -1252,7 +1252,7 @@ static void __maybe_unused via_init_sdc_pm(struct via_crdr_mmc_host *host)
|
|||
via_print_sdchc(host);
|
||||
}
|
||||
|
||||
static int __maybe_unused via_sd_suspend(struct device *dev)
|
||||
static int via_sd_suspend(struct device *dev)
|
||||
{
|
||||
struct via_crdr_mmc_host *host;
|
||||
unsigned long flags;
|
||||
|
|
@ -1269,7 +1269,7 @@ static int __maybe_unused via_sd_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused via_sd_resume(struct device *dev)
|
||||
static int via_sd_resume(struct device *dev)
|
||||
{
|
||||
struct via_crdr_mmc_host *sdhost;
|
||||
u8 gatt;
|
||||
|
|
@ -1295,14 +1295,14 @@ static int __maybe_unused via_sd_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(via_sd_pm_ops, via_sd_suspend, via_sd_resume);
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(via_sd_pm_ops, via_sd_suspend, via_sd_resume);
|
||||
|
||||
static struct pci_driver via_sd_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = via_ids,
|
||||
.probe = via_sd_probe,
|
||||
.remove = via_sd_remove,
|
||||
.driver.pm = &via_sd_pm_ops,
|
||||
.driver.pm = pm_sleep_ptr(&via_sd_pm_ops),
|
||||
};
|
||||
|
||||
module_pci_driver(via_sd_driver);
|
||||
|
|
|
|||
|
|
@ -911,7 +911,6 @@ static void wmt_mci_remove(struct platform_device *pdev)
|
|||
dev_info(&pdev->dev, "WMT MCI device removed\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wmt_mci_suspend(struct device *dev)
|
||||
{
|
||||
u32 reg_tmp;
|
||||
|
|
@ -963,18 +962,7 @@ static int wmt_mci_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops wmt_mci_pm = {
|
||||
.suspend = wmt_mci_suspend,
|
||||
.resume = wmt_mci_resume,
|
||||
};
|
||||
|
||||
#define wmt_mci_pm_ops (&wmt_mci_pm)
|
||||
|
||||
#else /* !CONFIG_PM */
|
||||
|
||||
#define wmt_mci_pm_ops NULL
|
||||
|
||||
#endif
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(wmt_mci_pm_ops, wmt_mci_suspend, wmt_mci_resume);
|
||||
|
||||
static struct platform_driver wmt_mci_driver = {
|
||||
.probe = wmt_mci_probe,
|
||||
|
|
@ -982,7 +970,7 @@ static struct platform_driver wmt_mci_driver = {
|
|||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = wmt_mci_pm_ops,
|
||||
.pm = pm_sleep_ptr(&wmt_mci_pm_ops),
|
||||
.of_match_table = wmt_mci_dt_ids,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -337,11 +337,15 @@ struct mmc_slot {
|
|||
|
||||
struct regulator;
|
||||
struct mmc_pwrseq;
|
||||
struct notifier_block;
|
||||
|
||||
struct mmc_supply {
|
||||
struct regulator *vmmc; /* Card power supply */
|
||||
struct regulator *vqmmc; /* Optional Vccq supply */
|
||||
struct regulator *vqmmc2; /* Optional supply for phy */
|
||||
|
||||
struct notifier_block vmmc_nb; /* Notifier for vmmc */
|
||||
struct work_struct uv_work; /* Undervoltage work */
|
||||
};
|
||||
|
||||
struct mmc_ctx {
|
||||
|
|
@ -494,6 +498,13 @@ struct mmc_host {
|
|||
unsigned int can_dma_map_merge:1; /* merging can be used */
|
||||
unsigned int vqmmc_enabled:1; /* vqmmc regulator is enabled */
|
||||
|
||||
/*
|
||||
* Indicates if an undervoltage event has already been handled.
|
||||
* This prevents repeated regulator notifiers from triggering
|
||||
* multiple REGULATOR_EVENT_UNDER_VOLTAGE events.
|
||||
*/
|
||||
unsigned int undervoltage:1; /* Undervoltage state */
|
||||
|
||||
int rescan_disable; /* disable card detection */
|
||||
int rescan_entered; /* used with nonremovable devices */
|
||||
|
||||
|
|
@ -565,6 +576,7 @@ struct mmc_host {
|
|||
int hsq_depth;
|
||||
|
||||
u32 err_stats[MMC_ERR_MAX];
|
||||
u32 max_sd_hs_hz;
|
||||
unsigned long private[] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
|
|
@ -743,5 +755,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status);
|
|||
int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
|
||||
int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
|
||||
int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
|
||||
int mmc_read_tuning(struct mmc_host *host, unsigned int blksz, unsigned int blocks);
|
||||
|
||||
#endif /* LINUX_MMC_HOST_H */
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@
|
|||
/* Some controllers have a CBSY bit */
|
||||
#define TMIO_MMC_HAVE_CBSY BIT(11)
|
||||
|
||||
/* Some controllers have a 64-bit wide data port register */
|
||||
#define TMIO_MMC_64BIT_DATA_PORT BIT(12)
|
||||
|
||||
struct tmio_mmc_data {
|
||||
void *chan_priv_tx;
|
||||
void *chan_priv_rx;
|
||||
|
|
|
|||
|
|
@ -99,6 +99,17 @@ extern int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card);
|
|||
#define CD_MASK (SD_CD | MS_CD | XD_CD)
|
||||
#define SD_WP 0x08
|
||||
|
||||
/* OCPCTL */
|
||||
#define MS_OCP_DETECT_EN 0x08
|
||||
#define MS_OCP_INT_EN 0x04
|
||||
#define MS_OCP_INT_CLR 0x02
|
||||
#define MS_OCP_CLEAR 0x01
|
||||
|
||||
/* OCPSTAT */
|
||||
#define MS_OCP_DETECT 0x80
|
||||
#define MS_OCP_NOW 0x02
|
||||
#define MS_OCP_EVER 0x01
|
||||
|
||||
/* reader command field offset & parameters */
|
||||
#define READ_REG_CMD 0
|
||||
#define WRITE_REG_CMD 1
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user