Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01259620 authored by Ulf Hansson's avatar Ulf Hansson Committed by Russell King
Browse files

ARM: 7726/1: mmc: mmci: Add card_busy function to improve UHS card support



To verify a signal voltage switch at initialization of UHS cards the
.card_busy callback is used. For some of the ST-variants, card busy
detection on the DAT0 pin is supported.

We extend the variant struct with a busy_detect flag to indicate
support for it. A corresponding busy detect function, which polls the
busy status bit, is then set to the .card_busy callback.

Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 9cc639a2
Loading
Loading
Loading
Loading
+32 −1
Original line number Original line Diff line number Diff line
@@ -61,6 +61,7 @@ static unsigned int fmax = 515633;
 * @pwrreg_powerup: power up value for MMCIPOWER register
 * @pwrreg_powerup: power up value for MMCIPOWER register
 * @signal_direction: input/out direction of bus signals can be indicated
 * @signal_direction: input/out direction of bus signals can be indicated
 * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
 * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
 * @busy_detect: true if busy detection on dat0 is supported
 */
 */
struct variant_data {
struct variant_data {
	unsigned int		clkreg;
	unsigned int		clkreg;
@@ -74,6 +75,7 @@ struct variant_data {
	u32			pwrreg_powerup;
	u32			pwrreg_powerup;
	bool			signal_direction;
	bool			signal_direction;
	bool			pwrreg_clkgate;
	bool			pwrreg_clkgate;
	bool			busy_detect;
};
};


static struct variant_data variant_arm = {
static struct variant_data variant_arm = {
@@ -132,6 +134,7 @@ static struct variant_data variant_ux500 = {
	.pwrreg_powerup		= MCI_PWR_ON,
	.pwrreg_powerup		= MCI_PWR_ON,
	.signal_direction	= true,
	.signal_direction	= true,
	.pwrreg_clkgate		= true,
	.pwrreg_clkgate		= true,
	.busy_detect		= true,
};
};


static struct variant_data variant_ux500v2 = {
static struct variant_data variant_ux500v2 = {
@@ -146,8 +149,28 @@ static struct variant_data variant_ux500v2 = {
	.pwrreg_powerup		= MCI_PWR_ON,
	.pwrreg_powerup		= MCI_PWR_ON,
	.signal_direction	= true,
	.signal_direction	= true,
	.pwrreg_clkgate		= true,
	.pwrreg_clkgate		= true,
	.busy_detect		= true,
};
};


static int mmci_card_busy(struct mmc_host *mmc)
{
	struct mmci_host *host = mmc_priv(mmc);
	unsigned long flags;
	int busy = 0;

	pm_runtime_get_sync(mmc_dev(mmc));

	spin_lock_irqsave(&host->lock, flags);
	if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY)
		busy = 1;
	spin_unlock_irqrestore(&host->lock, flags);

	pm_runtime_mark_last_busy(mmc_dev(mmc));
	pm_runtime_put_autosuspend(mmc_dev(mmc));

	return busy;
}

/*
/*
 * Validate mmc prerequisites
 * Validate mmc prerequisites
 */
 */
@@ -193,6 +216,9 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
 */
 */
static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
{
{
	/* Keep ST Micro busy mode if enabled */
	datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE;

	if (host->datactrl_reg != datactrl) {
	if (host->datactrl_reg != datactrl) {
		host->datactrl_reg = datactrl;
		host->datactrl_reg = datactrl;
		writel(datactrl, host->base + MMCIDATACTRL);
		writel(datactrl, host->base + MMCIDATACTRL);
@@ -1319,7 +1345,7 @@ static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
	return IRQ_HANDLED;
	return IRQ_HANDLED;
}
}


static const struct mmc_host_ops mmci_ops = {
static struct mmc_host_ops mmci_ops = {
	.request	= mmci_request,
	.request	= mmci_request,
	.pre_req	= mmci_pre_request,
	.pre_req	= mmci_pre_request,
	.post_req	= mmci_post_request,
	.post_req	= mmci_post_request,
@@ -1455,6 +1481,11 @@ static int mmci_probe(struct amba_device *dev,
		goto clk_disable;
		goto clk_disable;
	}
	}


	if (variant->busy_detect) {
		mmci_ops.card_busy = mmci_card_busy;
		mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
	}

	mmc->ops = &mmci_ops;
	mmc->ops = &mmci_ops;
	/*
	/*
	 * The ARM and ST versions of the block have slightly different
	 * The ARM and ST versions of the block have slightly different
+2 −0
Original line number Original line Diff line number Diff line
@@ -94,6 +94,7 @@
/* Extended status bits for the ST Micro variants */
/* Extended status bits for the ST Micro variants */
#define MCI_ST_SDIOIT		(1 << 22)
#define MCI_ST_SDIOIT		(1 << 22)
#define MCI_ST_CEATAEND		(1 << 23)
#define MCI_ST_CEATAEND		(1 << 23)
#define MCI_ST_CARDBUSY		(1 << 24)


#define MMCICLEAR		0x038
#define MMCICLEAR		0x038
#define MCI_CMDCRCFAILCLR	(1 << 0)
#define MCI_CMDCRCFAILCLR	(1 << 0)
@@ -110,6 +111,7 @@
/* Extended status bits for the ST Micro variants */
/* Extended status bits for the ST Micro variants */
#define MCI_ST_SDIOITC		(1 << 22)
#define MCI_ST_SDIOITC		(1 << 22)
#define MCI_ST_CEATAENDC	(1 << 23)
#define MCI_ST_CEATAENDC	(1 << 23)
#define MCI_ST_BUSYENDC		(1 << 24)


#define MMCIMASK0		0x03c
#define MMCIMASK0		0x03c
#define MCI_CMDCRCFAILMASK	(1 << 0)
#define MCI_CMDCRCFAILMASK	(1 << 0)