mbox series

[V8,0/9] mmc: add support for sdhci 4.0

Message ID 1535617305-16952-1-git-send-email-zhang.chunyan@linaro.org
Headers show
Series mmc: add support for sdhci 4.0 | expand

Message

Chunyan Zhang Aug. 30, 2018, 8:21 a.m. UTC
From the SD host controller version 4.0 on, SDHCI implementation either
is version 3 compatible or version 4 mode. This patch-set covers those
changes which are common for SDHCI 4.0 version, regardless of whether
they are used with SD or eMMC storage devices.

This patchset also added a new sdhci driver for Spreadtrum's controller
which supports v4.0 mode.

This patchset has been tested on Spreadtrum's mobile phone, emmc can be
initialized, mounted, read and written, with these changes for common
sdhci framework and sdhci-sprd driver.

Changes from V7:
- Added Adrian's acked-by on patch 1-6;
- Addressed comments.

Previous patch series:
v7: https://lkml.org/lkml/2018/8/29/130
v6: http://lkml.org/lkml/2018/8/24/205
v5: https://lkml.org/lkml/2018/8/16/122
v4: https://lkml.org/lkml/2018/7/23/269
v3: https://lkml.org/lkml/2018/7/8/239
v2: https://lkml.org/lkml/2018/6/14/936
v1: https://lkml.org/lkml/2018/6/8/108

Chunyan Zhang (9):
  mmc: sdhci: Add version V4 definition
  mmc: sdhci: Add sd host v4 mode
  mmc: sdhci: Change SDMA address register for v4 mode
  mmc: sdhci: Add ADMA2 64-bit addressing support for V4 mode
  mmc: sdhci: Add 32-bit block count support for v4 mode
  mmc: sdhci: Add Auto CMD Auto Select support
  mmc: sdhci: SDMA may use Auto-CMD23 in v4 mode
  mmc: sdhci-sprd: Add Spreadtrum's initial host controller
  dt-bindings: sdhci-sprd: Add bindings for the sdhci-sprd controller

 .../devicetree/bindings/mmc/sdhci-sprd.txt         |  41 ++
 drivers/mmc/host/Kconfig                           |  13 +
 drivers/mmc/host/Makefile                          |   1 +
 drivers/mmc/host/sdhci-sprd.c                      | 498 +++++++++++++++++++++
 drivers/mmc/host/sdhci.c                           | 223 +++++++--
 drivers/mmc/host/sdhci.h                           |  28 +-
 6 files changed, 754 insertions(+), 50 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-sprd.txt
 create mode 100644 drivers/mmc/host/sdhci-sprd.c

-- 
2.7.4

Comments

Adrian Hunter Aug. 30, 2018, 8:34 a.m. UTC | #1
On 30/08/18 11:21, Chunyan Zhang wrote:
> When Host Version 4 Enable is set to 1, SDMA uses ADMA System Address

> register (05Fh-058h) instead of using register (000h-004h) to indicate

> its system address of data location. The register (000h-004h) is

> re-assigned to 32-bit Block Count and Auto CMD23 argument, so then SDMA

> may use Auto CMD23.

> 

> Signed-off-by: Chunyan Zhang <zhang.chunyan@linaro.org>


Acked-by: Adrian Hunter <adrian.hunter@intel.com>


> ---

>  drivers/mmc/host/sdhci.c | 7 +++++--

>  1 file changed, 5 insertions(+), 2 deletions(-)

> 

> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c

> index 62d843ac90..606d331 100644

> --- a/drivers/mmc/host/sdhci.c

> +++ b/drivers/mmc/host/sdhci.c

> @@ -3834,10 +3834,13 @@ int sdhci_setup_host(struct sdhci_host *host)

>  	if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)

>  		host->flags |= SDHCI_AUTO_CMD12;

>  

> -	/* Auto-CMD23 stuff only works in ADMA or PIO. */

> +	/*

> +	 * For v3 mode, Auto-CMD23 stuff only works in ADMA or PIO.

> +	 * For v4 mode, SDMA may use Auto-CMD23 as well.

> +	 */

>  	if ((host->version >= SDHCI_SPEC_300) &&

>  	    ((host->flags & SDHCI_USE_ADMA) ||

> -	     !(host->flags & SDHCI_USE_SDMA)) &&

> +	     !(host->flags & SDHCI_USE_SDMA) || host->v4_mode) &&

>  	     !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {

>  		host->flags |= SDHCI_AUTO_CMD23;

>  		DBG("Auto-CMD23 available\n");

>
Adrian Hunter Aug. 30, 2018, 8:41 a.m. UTC | #2
On 30/08/18 11:21, Chunyan Zhang wrote:
> From: Chunyan Zhang <chunyan.zhang@unisoc.com>

> 

> This patch adds the initial support of Secure Digital Host Controller

> Interface compliant controller found in some latest Spreadtrum chipsets.

> This patch has been tested on the version of SPRD-R11 controller.

> 

> R11 is a variant based on SD v4.0 specification.

> 

> With this driver, R11 mmc can be initialized, can be mounted, read and

> written.

> 

> Original-by: Billows Wu <billows.wu@unisoc.com>

> Signed-off-by: Chunyan Zhang <chunyan.zhang@unisoc.com>


Acked-by: Adrian Hunter <adrian.hunter@intel.com>


> ---

>  drivers/mmc/host/Kconfig      |  13 ++

>  drivers/mmc/host/Makefile     |   1 +

>  drivers/mmc/host/sdhci-sprd.c | 498 ++++++++++++++++++++++++++++++++++++++++++

>  3 files changed, 512 insertions(+)

>  create mode 100644 drivers/mmc/host/sdhci-sprd.c

> 

> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig

> index d09feb6..cf984f0 100644

> --- a/drivers/mmc/host/Kconfig

> +++ b/drivers/mmc/host/Kconfig

> @@ -593,6 +593,19 @@ config MMC_SDRICOH_CS

>  	  To compile this driver as a module, choose M here: the

>  	  module will be called sdricoh_cs.

>  

> +config MMC_SDHCI_SPRD

> +	tristate "Spreadtrum SDIO host Controller"

> +	depends on ARCH_SPRD

> +	depends on MMC_SDHCI_PLTFM

> +	select MMC_SDHCI_IO_ACCESSORS

> +	help

> +	  This selects the SDIO Host Controller in Spreadtrum

> +	  SoCs, this driver supports R11(IP version: R11P0).

> +

> +	  If you have a controller with this interface, say Y or M here.

> +

> +	  If unsure, say N.

> +

>  config MMC_TMIO_CORE

>  	tristate

>  

> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile

> index a835d1a..5363d06 100644

> --- a/drivers/mmc/host/Makefile

> +++ b/drivers/mmc/host/Makefile

> @@ -92,6 +92,7 @@ obj-$(CONFIG_MMC_SDHCI_ST)		+= sdhci-st.o

>  obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32)	+= sdhci-pic32.o

>  obj-$(CONFIG_MMC_SDHCI_BRCMSTB)		+= sdhci-brcmstb.o

>  obj-$(CONFIG_MMC_SDHCI_OMAP)		+= sdhci-omap.o

> +obj-$(CONFIG_MMC_SDHCI_SPRD)		+= sdhci-sprd.o

>  obj-$(CONFIG_MMC_CQHCI)			+= cqhci.o

>  

>  ifeq ($(CONFIG_CB710_DEBUG),y)

> diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c

> new file mode 100644

> index 0000000..3d5128e

> --- /dev/null

> +++ b/drivers/mmc/host/sdhci-sprd.c

> @@ -0,0 +1,498 @@

> +// SPDX-License-Identifier: GPL-2.0

> +//

> +// Secure Digital Host Controller

> +//

> +// Copyright (C) 2018 Spreadtrum, Inc.

> +// Author: Chunyan Zhang <chunyan.zhang@unisoc.com>

> +

> +#include <linux/delay.h>

> +#include <linux/dma-mapping.h>

> +#include <linux/highmem.h>

> +#include <linux/module.h>

> +#include <linux/of.h>

> +#include <linux/of_device.h>

> +#include <linux/of_gpio.h>

> +#include <linux/platform_device.h>

> +#include <linux/pm_runtime.h>

> +#include <linux/regulator/consumer.h>

> +#include <linux/slab.h>

> +

> +#include "sdhci-pltfm.h"

> +

> +/* SDHCI_ARGUMENT2 register high 16bit */

> +#define SDHCI_SPRD_ARG2_STUFF		GENMASK(31, 16)

> +

> +#define SDHCI_SPRD_REG_32_DLL_DLY_OFFSET	0x208

> +#define  SDHCIBSPRD_IT_WR_DLY_INV		BIT(5)

> +#define  SDHCI_SPRD_BIT_CMD_DLY_INV		BIT(13)

> +#define  SDHCI_SPRD_BIT_POSRD_DLY_INV		BIT(21)

> +#define  SDHCI_SPRD_BIT_NEGRD_DLY_INV		BIT(29)

> +

> +#define SDHCI_SPRD_REG_32_BUSY_POSI		0x250

> +#define  SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN	BIT(25)

> +#define  SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN	BIT(24)

> +

> +#define SDHCI_SPRD_REG_DEBOUNCE		0x28C

> +#define  SDHCI_SPRD_BIT_DLL_BAK		BIT(0)

> +#define  SDHCI_SPRD_BIT_DLL_VAL		BIT(1)

> +

> +#define  SDHCI_SPRD_INT_SIGNAL_MASK	0x1B7F410B

> +

> +/* SDHCI_HOST_CONTROL2 */

> +#define  SDHCI_SPRD_CTRL_HS200		0x0005

> +#define  SDHCI_SPRD_CTRL_HS400		0x0006

> +

> +/*

> + * According to the standard specification, BIT(3) of SDHCI_SOFTWARE_RESET is

> + * reserved, and only used on Spreadtrum's design, the hardware cannot work

> + * if this bit is cleared.

> + * 1 : normal work

> + * 0 : hardware reset

> + */

> +#define  SDHCI_HW_RESET_CARD		BIT(3)

> +

> +#define SDHCI_SPRD_MAX_CUR		0xFFFFFF

> +#define SDHCI_SPRD_CLK_MAX_DIV		1023

> +

> +#define SDHCI_SPRD_CLK_DEF_RATE		26000000

> +

> +struct sdhci_sprd_host {

> +	u32 version;

> +	struct clk *clk_sdio;

> +	struct clk *clk_enable;

> +	u32 base_rate;

> +	int flags; /* backup of host attribute */

> +};

> +

> +#define TO_SPRD_HOST(host) sdhci_pltfm_priv(sdhci_priv(host))

> +

> +static void sdhci_sprd_init_config(struct sdhci_host *host)

> +{

> +	u16 val;

> +

> +	/* set dll backup mode */

> +	val = sdhci_readl(host, SDHCI_SPRD_REG_DEBOUNCE);

> +	val |= SDHCI_SPRD_BIT_DLL_BAK | SDHCI_SPRD_BIT_DLL_VAL;

> +	sdhci_writel(host, val, SDHCI_SPRD_REG_DEBOUNCE);

> +}

> +

> +static inline u32 sdhci_sprd_readl(struct sdhci_host *host, int reg)

> +{

> +	if (unlikely(reg == SDHCI_MAX_CURRENT))

> +		return SDHCI_SPRD_MAX_CUR;

> +

> +	return readl_relaxed(host->ioaddr + reg);

> +}

> +

> +static inline void sdhci_sprd_writel(struct sdhci_host *host, u32 val, int reg)

> +{

> +	/* SDHCI_MAX_CURRENT is reserved on Spreadtrum's platform */

> +	if (unlikely(reg == SDHCI_MAX_CURRENT))

> +		return;

> +

> +	if (unlikely(reg == SDHCI_SIGNAL_ENABLE || reg == SDHCI_INT_ENABLE))

> +		val = val & SDHCI_SPRD_INT_SIGNAL_MASK;

> +

> +	writel_relaxed(val, host->ioaddr + reg);

> +}

> +

> +static inline void sdhci_sprd_writew(struct sdhci_host *host, u16 val, int reg)

> +{

> +	/* SDHCI_BLOCK_COUNT is Read Only on Spreadtrum's platform */

> +	if (unlikely(reg == SDHCI_BLOCK_COUNT))

> +		return;

> +

> +	writew_relaxed(val, host->ioaddr + reg);

> +}

> +

> +static inline void sdhci_sprd_writeb(struct sdhci_host *host, u8 val, int reg)

> +{

> +	/*

> +	 * Since BIT(3) of SDHCI_SOFTWARE_RESET is reserved according to the

> +	 * standard specification, sdhci_reset() write this register directly

> +	 * without checking other reserved bits, that will clear BIT(3) which

> +	 * is defined as hardware reset on Spreadtrum's platform and clearing

> +	 * it by mistake will lead the card not work. So here we need to work

> +	 * around it.

> +	 */

> +	if (unlikely(reg == SDHCI_SOFTWARE_RESET)) {

> +		if (readb_relaxed(host->ioaddr + reg) & SDHCI_HW_RESET_CARD)

> +			val |= SDHCI_HW_RESET_CARD;

> +	}

> +

> +	writeb_relaxed(val, host->ioaddr + reg);

> +}

> +

> +static inline void sdhci_sprd_sd_clk_off(struct sdhci_host *host)

> +{

> +	u16 ctrl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);

> +

> +	ctrl &= ~SDHCI_CLOCK_CARD_EN;

> +	sdhci_writew(host, ctrl, SDHCI_CLOCK_CONTROL);

> +}

> +

> +static inline void

> +sdhci_sprd_set_dll_invert(struct sdhci_host *host, u32 mask, bool en)

> +{

> +	u32 dll_dly_offset;

> +

> +	dll_dly_offset = sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_DLY_OFFSET);

> +	if (en)

> +		dll_dly_offset |= mask;

> +	else

> +		dll_dly_offset &= ~mask;

> +	sdhci_writel(host, dll_dly_offset, SDHCI_SPRD_REG_32_DLL_DLY_OFFSET);

> +}

> +

> +static inline u32 sdhci_sprd_calc_div(u32 base_clk, u32 clk)

> +{

> +	u32 div;

> +

> +	/* select 2x clock source */

> +	if (base_clk <= clk * 2)

> +		return 0;

> +

> +	div = (u32) (base_clk / (clk * 2));

> +

> +	if ((base_clk / div) > (clk * 2))

> +		div++;

> +

> +	if (div > SDHCI_SPRD_CLK_MAX_DIV)

> +		div = SDHCI_SPRD_CLK_MAX_DIV;

> +

> +	if (div % 2)

> +		div = (div + 1) / 2;

> +	else

> +		div = div / 2;

> +

> +	return div;

> +}

> +

> +static inline void _sdhci_sprd_set_clock(struct sdhci_host *host,

> +					unsigned int clk)

> +{

> +	struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);

> +	u32 div, val, mask;

> +

> +	div = sdhci_sprd_calc_div(sprd_host->base_rate, clk);

> +

> +	clk |= ((div & 0x300) >> 2) | ((div & 0xFF) << 8);

> +	sdhci_enable_clk(host, clk);

> +

> +	/* enable auto gate sdhc_enable_auto_gate */

> +	val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI);

> +	mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN |

> +	       SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN;

> +	if (mask != (val & mask)) {

> +		val |= mask;

> +		sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI);

> +	}

> +}

> +

> +static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)

> +{

> +	bool en = false;

> +

> +	if (clock == 0) {

> +		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);

> +	} else if (clock != host->clock) {

> +		sdhci_sprd_sd_clk_off(host);

> +		_sdhci_sprd_set_clock(host, clock);

> +

> +		if (clock <= 400000)

> +			en = true;

> +		sdhci_sprd_set_dll_invert(host, SDHCI_SPRD_BIT_CMD_DLY_INV |

> +					  SDHCI_SPRD_BIT_POSRD_DLY_INV, en);

> +	} else {

> +		_sdhci_sprd_set_clock(host, clock);

> +	}

> +}

> +

> +static unsigned int sdhci_sprd_get_max_clock(struct sdhci_host *host)

> +{

> +	struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);

> +

> +	return clk_round_rate(sprd_host->clk_sdio, ULONG_MAX);

> +}

> +

> +static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host)

> +{

> +	return 400000;

> +}

> +

> +static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,

> +					 unsigned int timing)

> +{

> +	u16 ctrl_2;

> +

> +	if (timing == host->timing)

> +		return;

> +

> +	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);

> +	/* Select Bus Speed Mode for host */

> +	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;

> +	switch (timing) {

> +	case MMC_TIMING_UHS_SDR12:

> +		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;

> +		break;

> +	case MMC_TIMING_MMC_HS:

> +	case MMC_TIMING_SD_HS:

> +	case MMC_TIMING_UHS_SDR25:

> +		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;

> +		break;

> +	case MMC_TIMING_UHS_SDR50:

> +		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;

> +		break;

> +	case MMC_TIMING_UHS_SDR104:

> +		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;

> +		break;

> +	case MMC_TIMING_UHS_DDR50:

> +	case MMC_TIMING_MMC_DDR52:

> +		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;

> +		break;

> +	case MMC_TIMING_MMC_HS200:

> +		ctrl_2 |= SDHCI_SPRD_CTRL_HS200;

> +		break;

> +	case MMC_TIMING_MMC_HS400:

> +		ctrl_2 |= SDHCI_SPRD_CTRL_HS400;

> +		break;

> +	default:

> +		break;

> +	}

> +

> +	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);

> +}

> +

> +static void sdhci_sprd_hw_reset(struct sdhci_host *host)

> +{

> +	int val;

> +

> +	/*

> +	 * Note: don't use sdhci_writeb() API here since it is redirected to

> +	 * sdhci_sprd_writeb() in which we have a workaround for

> +	 * SDHCI_SOFTWARE_RESET which would make bit SDHCI_HW_RESET_CARD can

> +	 * not be cleared.

> +	 */

> +	val = readb_relaxed(host->ioaddr + SDHCI_SOFTWARE_RESET);

> +	val &= ~SDHCI_HW_RESET_CARD;

> +	writeb_relaxed(val, host->ioaddr + SDHCI_SOFTWARE_RESET);

> +	/* wait for 10 us */

> +	usleep_range(10, 20);

> +

> +	val |= SDHCI_HW_RESET_CARD;

> +	writeb_relaxed(val, host->ioaddr + SDHCI_SOFTWARE_RESET);

> +	usleep_range(300, 500);

> +}

> +

> +static struct sdhci_ops sdhci_sprd_ops = {

> +	.read_l = sdhci_sprd_readl,

> +	.write_l = sdhci_sprd_writel,

> +	.write_b = sdhci_sprd_writeb,

> +	.set_clock = sdhci_sprd_set_clock,

> +	.get_max_clock = sdhci_sprd_get_max_clock,

> +	.get_min_clock = sdhci_sprd_get_min_clock,

> +	.set_bus_width = sdhci_set_bus_width,

> +	.reset = sdhci_reset,

> +	.set_uhs_signaling = sdhci_sprd_set_uhs_signaling,

> +	.hw_reset = sdhci_sprd_hw_reset,

> +};

> +

> +static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq)

> +{

> +	struct sdhci_host *host = mmc_priv(mmc);

> +	struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);

> +

> +	host->flags |= sprd_host->flags & SDHCI_AUTO_CMD23;

> +

> +	/*

> +	 * From version 4.10 onward, ARGUMENT2 register is also as 32-bit

> +	 * block count register which doesn't support stuff bits of

> +	 * CMD23 argument on Spreadtrum's sd host controller.

> +	 */

> +	if (host->version >= SDHCI_SPEC_410 &&

> +	    mrq->sbc && (mrq->sbc->arg & SDHCI_SPRD_ARG2_STUFF) &&

> +	    (host->flags & SDHCI_AUTO_CMD23))

> +		host->flags &= ~SDHCI_AUTO_CMD23;

> +

> +	sdhci_request(mmc, mrq);

> +}

> +

> +static const struct sdhci_pltfm_data sdhci_sprd_pdata = {

> +	.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,

> +	.quirks2 = SDHCI_QUIRK2_BROKEN_HS200 |

> +		   SDHCI_QUIRK2_USE_32BIT_BLK_CNT,

> +	.ops = &sdhci_sprd_ops,

> +};

> +

> +static int sdhci_sprd_probe(struct platform_device *pdev)

> +{

> +	struct sdhci_host *host;

> +	struct sdhci_sprd_host *sprd_host;

> +	struct clk *clk;

> +	int ret = 0;

> +

> +	host = sdhci_pltfm_init(pdev, &sdhci_sprd_pdata, sizeof(*sprd_host));

> +	if (IS_ERR(host))

> +		return PTR_ERR(host);

> +

> +	host->dma_mask = DMA_BIT_MASK(64);

> +	pdev->dev.dma_mask = &host->dma_mask;

> +	host->mmc_host_ops.request = sdhci_sprd_request;

> +

> +	host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |

> +		MMC_CAP_ERASE | MMC_CAP_CMD23;

> +	ret = mmc_of_parse(host->mmc);

> +	if (ret)

> +		goto pltfm_free;

> +

> +	sprd_host = TO_SPRD_HOST(host);

> +

> +	clk = devm_clk_get(&pdev->dev, "sdio");

> +	if (IS_ERR(clk)) {

> +		ret = PTR_ERR(clk);

> +		goto pltfm_free;

> +	}

> +	sprd_host->clk_sdio = clk;

> +	sprd_host->base_rate = clk_get_rate(sprd_host->clk_sdio);

> +	if (!sprd_host->base_rate)

> +		sprd_host->base_rate = SDHCI_SPRD_CLK_DEF_RATE;

> +

> +	clk = devm_clk_get(&pdev->dev, "enable");

> +	if (IS_ERR(clk)) {

> +		ret = PTR_ERR(clk);

> +		goto pltfm_free;

> +	}

> +	sprd_host->clk_enable = clk;

> +

> +	ret = clk_prepare_enable(sprd_host->clk_sdio);

> +	if (ret)

> +		goto pltfm_free;

> +

> +	clk_prepare_enable(sprd_host->clk_enable);

> +	if (ret)

> +		goto clk_disable;

> +

> +	sdhci_sprd_init_config(host);

> +	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);

> +	sprd_host->version = ((host->version & SDHCI_VENDOR_VER_MASK) >>

> +			       SDHCI_VENDOR_VER_SHIFT);

> +

> +	pm_runtime_get_noresume(&pdev->dev);

> +	pm_runtime_set_active(&pdev->dev);

> +	pm_runtime_enable(&pdev->dev);

> +	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);

> +	pm_runtime_use_autosuspend(&pdev->dev);

> +	pm_suspend_ignore_children(&pdev->dev, 1);

> +

> +	sdhci_enable_v4_mode(host);

> +

> +	ret = sdhci_setup_host(host);

> +	if (ret)

> +		goto pm_runtime_disable;

> +

> +	sprd_host->flags = host->flags;

> +

> +	ret = __sdhci_add_host(host);

> +	if (ret)

> +		goto err_cleanup_host;

> +

> +	pm_runtime_mark_last_busy(&pdev->dev);

> +	pm_runtime_put_autosuspend(&pdev->dev);

> +

> +	return 0;

> +

> +err_cleanup_host:

> +	sdhci_cleanup_host(host);

> +

> +pm_runtime_disable:

> +	pm_runtime_disable(&pdev->dev);

> +	pm_runtime_set_suspended(&pdev->dev);

> +

> +	clk_disable_unprepare(sprd_host->clk_enable);

> +

> +clk_disable:

> +	clk_disable_unprepare(sprd_host->clk_sdio);

> +

> +pltfm_free:

> +	sdhci_pltfm_free(pdev);

> +	return ret;

> +}

> +

> +static int sdhci_sprd_remove(struct platform_device *pdev)

> +{

> +	struct sdhci_host *host = platform_get_drvdata(pdev);

> +	struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);

> +	struct mmc_host *mmc = host->mmc;

> +

> +	mmc_remove_host(mmc);

> +	clk_disable_unprepare(sprd_host->clk_sdio);

> +	clk_disable_unprepare(sprd_host->clk_enable);

> +

> +	mmc_free_host(mmc);

> +

> +	return 0;

> +}

> +

> +static const struct of_device_id sdhci_sprd_of_match[] = {

> +	{ .compatible = "sprd,sdhci-r11", },

> +	{ }

> +};

> +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);

> +	struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);

> +

> +	sdhci_runtime_suspend_host(host);

> +

> +	clk_disable_unprepare(sprd_host->clk_sdio);

> +	clk_disable_unprepare(sprd_host->clk_enable);

> +

> +	return 0;

> +}

> +

> +static int sdhci_sprd_runtime_resume(struct device *dev)

> +{

> +	struct sdhci_host *host = dev_get_drvdata(dev);

> +	struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host);

> +	int ret;

> +

> +	ret = clk_prepare_enable(sprd_host->clk_enable);

> +	if (ret)

> +		return ret;

> +

> +	ret = clk_prepare_enable(sprd_host->clk_sdio);

> +	if (ret) {

> +		clk_disable_unprepare(sprd_host->clk_enable);

> +		return ret;

> +	}

> +

> +	sdhci_runtime_resume_host(host);

> +

> +	return 0;

> +}

> +#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)

> +};

> +

> +static struct platform_driver sdhci_sprd_driver = {

> +	.probe = sdhci_sprd_probe,

> +	.remove = sdhci_sprd_remove,

> +	.driver = {

> +		.name = "sdhci_sprd_r11",

> +		.of_match_table = of_match_ptr(sdhci_sprd_of_match),

> +		.pm = &sdhci_sprd_pm_ops,

> +	},

> +};

> +module_platform_driver(sdhci_sprd_driver);

> +

> +MODULE_DESCRIPTION("Spreadtrum sdio host controller r11 driver");

> +MODULE_LICENSE("GPL v2");

> +MODULE_ALIAS("platform:sdhci-sprd-r11");

>
Ulf Hansson Sept. 7, 2018, 8:51 a.m. UTC | #3
On 30 August 2018 at 10:21, Chunyan Zhang <zhang.chunyan@linaro.org> wrote:
> From the SD host controller version 4.0 on, SDHCI implementation either

> is version 3 compatible or version 4 mode. This patch-set covers those

> changes which are common for SDHCI 4.0 version, regardless of whether

> they are used with SD or eMMC storage devices.

>

> This patchset also added a new sdhci driver for Spreadtrum's controller

> which supports v4.0 mode.

>

> This patchset has been tested on Spreadtrum's mobile phone, emmc can be

> initialized, mounted, read and written, with these changes for common

> sdhci framework and sdhci-sprd driver.

>

> Changes from V7:

> - Added Adrian's acked-by on patch 1-6;

> - Addressed comments.

>

> Previous patch series:

> v7: https://lkml.org/lkml/2018/8/29/130

> v6: http://lkml.org/lkml/2018/8/24/205

> v5: https://lkml.org/lkml/2018/8/16/122

> v4: https://lkml.org/lkml/2018/7/23/269

> v3: https://lkml.org/lkml/2018/7/8/239

> v2: https://lkml.org/lkml/2018/6/14/936

> v1: https://lkml.org/lkml/2018/6/8/108

>

> Chunyan Zhang (9):

>   mmc: sdhci: Add version V4 definition

>   mmc: sdhci: Add sd host v4 mode

>   mmc: sdhci: Change SDMA address register for v4 mode

>   mmc: sdhci: Add ADMA2 64-bit addressing support for V4 mode

>   mmc: sdhci: Add 32-bit block count support for v4 mode

>   mmc: sdhci: Add Auto CMD Auto Select support

>   mmc: sdhci: SDMA may use Auto-CMD23 in v4 mode

>   mmc: sdhci-sprd: Add Spreadtrum's initial host controller

>   dt-bindings: sdhci-sprd: Add bindings for the sdhci-sprd controller

>

>  .../devicetree/bindings/mmc/sdhci-sprd.txt         |  41 ++

>  drivers/mmc/host/Kconfig                           |  13 +

>  drivers/mmc/host/Makefile                          |   1 +

>  drivers/mmc/host/sdhci-sprd.c                      | 498 +++++++++++++++++++++

>  drivers/mmc/host/sdhci.c                           | 223 +++++++--

>  drivers/mmc/host/sdhci.h                           |  28 +-

>  6 files changed, 754 insertions(+), 50 deletions(-)

>  create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-sprd.txt

>  create mode 100644 drivers/mmc/host/sdhci-sprd.c

>

> --

> 2.7.4

>


Applied for next, thanks!

Kind regards
Uffe