drivers/mmc/host/uniphier-sd.c

Source file repositories/reference/linux-study-clean/drivers/mmc/host/uniphier-sd.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/uniphier-sd.c
Extension
.c
Size
20537 bytes
Lines
765
Domain
Driver Families
Bucket
drivers/mmc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct uniphier_sd_priv {
	struct tmio_mmc_data tmio_data;
	struct pinctrl *pinctrl;
	struct pinctrl_state *pinstate_uhs;
	struct clk *clk;
	struct reset_control *rst;
	struct reset_control *rst_br;
	struct reset_control *rst_hw;
	struct dma_chan *chan;
	enum dma_data_direction dma_dir;
	struct regmap *sdctrl_regmap;
	u32 sdctrl_ch;
	unsigned long clk_rate;
	unsigned long caps;
};

static void *uniphier_sd_priv(struct tmio_mmc_host *host)
{
	return container_of(host->pdata, struct uniphier_sd_priv, tmio_data);
}

static void uniphier_sd_dma_endisable(struct tmio_mmc_host *host, int enable)
{
	sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? DMA_ENABLE_DMASDRW : 0);
}

/* external DMA engine */
static void uniphier_sd_external_dma_issue(struct work_struct *t)
{
	struct tmio_mmc_host *host = from_work(host, t, dma_issue);
	struct uniphier_sd_priv *priv = uniphier_sd_priv(host);

	uniphier_sd_dma_endisable(host, 1);
	dma_async_issue_pending(priv->chan);
}

static void uniphier_sd_external_dma_callback(void *param,
					const struct dmaengine_result *result)
{
	struct tmio_mmc_host *host = param;
	struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
	unsigned long flags;

	dma_unmap_sg(mmc_dev(host->mmc), host->sg_ptr, host->sg_len,
		     priv->dma_dir);

	spin_lock_irqsave(&host->lock, flags);

	if (result->result == DMA_TRANS_NOERROR) {
		/*
		 * When the external DMA engine is enabled, strangely enough,
		 * the DATAEND flag can be asserted even if the DMA engine has
		 * not been kicked yet.  Enable the TMIO_STAT_DATAEND irq only
		 * after we make sure the DMA engine finishes the transfer,
		 * hence, in this callback.
		 */
		tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
	} else {
		host->data->error = -ETIMEDOUT;
		tmio_mmc_do_data_irq(host);
	}

	spin_unlock_irqrestore(&host->lock, flags);
}

static void uniphier_sd_external_dma_start(struct tmio_mmc_host *host,
					   struct mmc_data *data)
{
	struct uniphier_sd_priv *priv = uniphier_sd_priv(host);
	enum dma_transfer_direction dma_tx_dir;
	struct dma_async_tx_descriptor *desc;
	dma_cookie_t cookie;
	int sg_len;

	if (!priv->chan)
		goto force_pio;

	if (data->flags & MMC_DATA_READ) {
		priv->dma_dir = DMA_FROM_DEVICE;
		dma_tx_dir = DMA_DEV_TO_MEM;
	} else {
		priv->dma_dir = DMA_TO_DEVICE;
		dma_tx_dir = DMA_MEM_TO_DEV;
	}

	sg_len = dma_map_sg(mmc_dev(host->mmc), host->sg_ptr, host->sg_len,
			    priv->dma_dir);
	if (sg_len == 0)
		goto force_pio;

Annotation

Implementation Notes