mmc: spi: Pull out common DMA parts from MXS MMC
These parts will be used by the MXS SPI driver too. Signed-off-by: Marek Vasut <marex@denx.de> Acked-by: Chris Ball <cjb@laptop.org> Acked-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
This commit is contained in:
parent
646781d332
commit
65defb9b3b
|
@ -41,7 +41,6 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fsl/mxs-dma.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/stmp_device.h>
|
||||
#include <linux/mmc/mxs-mmc.h>
|
||||
|
@ -69,13 +68,6 @@ struct mxs_mmc_host {
|
|||
struct mmc_command *cmd;
|
||||
struct mmc_data *data;
|
||||
|
||||
int dma_channel;
|
||||
struct dma_chan *dmach;
|
||||
struct mxs_dma_data dma_data;
|
||||
unsigned int dma_dir;
|
||||
enum dma_transfer_direction slave_dirn;
|
||||
u32 ssp_pio_words[SSP_PIO_NUM];
|
||||
|
||||
unsigned char bus_width;
|
||||
spinlock_t lock;
|
||||
int sdio_irq_en;
|
||||
|
@ -163,7 +155,7 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host)
|
|||
|
||||
if (data) {
|
||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg,
|
||||
data->sg_len, host->dma_dir);
|
||||
data->sg_len, ssp->dma_dir);
|
||||
/*
|
||||
* If there was an error on any block, we mark all
|
||||
* data blocks as being in error.
|
||||
|
@ -232,6 +224,7 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id)
|
|||
static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
|
||||
struct mxs_mmc_host *host, unsigned long flags)
|
||||
{
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct mmc_data *data = host->data;
|
||||
struct scatterlist * sgl;
|
||||
|
@ -240,24 +233,24 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
|
|||
if (data) {
|
||||
/* data */
|
||||
dma_map_sg(mmc_dev(host->mmc), data->sg,
|
||||
data->sg_len, host->dma_dir);
|
||||
data->sg_len, ssp->dma_dir);
|
||||
sgl = data->sg;
|
||||
sg_len = data->sg_len;
|
||||
} else {
|
||||
/* pio */
|
||||
sgl = (struct scatterlist *) host->ssp_pio_words;
|
||||
sgl = (struct scatterlist *) ssp->ssp_pio_words;
|
||||
sg_len = SSP_PIO_NUM;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_sg(host->dmach,
|
||||
sgl, sg_len, host->slave_dirn, flags);
|
||||
desc = dmaengine_prep_slave_sg(ssp->dmach,
|
||||
sgl, sg_len, ssp->slave_dirn, flags);
|
||||
if (desc) {
|
||||
desc->callback = mxs_mmc_dma_irq_callback;
|
||||
desc->callback_param = host;
|
||||
} else {
|
||||
if (data)
|
||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg,
|
||||
data->sg_len, host->dma_dir);
|
||||
data->sg_len, ssp->dma_dir);
|
||||
}
|
||||
|
||||
return desc;
|
||||
|
@ -265,6 +258,7 @@ static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
|
|||
|
||||
static void mxs_mmc_bc(struct mxs_mmc_host *host)
|
||||
{
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
struct mmc_command *cmd = host->cmd;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
u32 ctrl0, cmd0, cmd1;
|
||||
|
@ -278,17 +272,17 @@ static void mxs_mmc_bc(struct mxs_mmc_host *host)
|
|||
cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
|
||||
}
|
||||
|
||||
host->ssp_pio_words[0] = ctrl0;
|
||||
host->ssp_pio_words[1] = cmd0;
|
||||
host->ssp_pio_words[2] = cmd1;
|
||||
host->dma_dir = DMA_NONE;
|
||||
host->slave_dirn = DMA_TRANS_NONE;
|
||||
ssp->ssp_pio_words[0] = ctrl0;
|
||||
ssp->ssp_pio_words[1] = cmd0;
|
||||
ssp->ssp_pio_words[2] = cmd1;
|
||||
ssp->dma_dir = DMA_NONE;
|
||||
ssp->slave_dirn = DMA_TRANS_NONE;
|
||||
desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
|
||||
if (!desc)
|
||||
goto out;
|
||||
|
||||
dmaengine_submit(desc);
|
||||
dma_async_issue_pending(host->dmach);
|
||||
dma_async_issue_pending(ssp->dmach);
|
||||
return;
|
||||
|
||||
out:
|
||||
|
@ -298,6 +292,7 @@ out:
|
|||
|
||||
static void mxs_mmc_ac(struct mxs_mmc_host *host)
|
||||
{
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
struct mmc_command *cmd = host->cmd;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
u32 ignore_crc, get_resp, long_resp;
|
||||
|
@ -319,17 +314,17 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host)
|
|||
cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
|
||||
}
|
||||
|
||||
host->ssp_pio_words[0] = ctrl0;
|
||||
host->ssp_pio_words[1] = cmd0;
|
||||
host->ssp_pio_words[2] = cmd1;
|
||||
host->dma_dir = DMA_NONE;
|
||||
host->slave_dirn = DMA_TRANS_NONE;
|
||||
ssp->ssp_pio_words[0] = ctrl0;
|
||||
ssp->ssp_pio_words[1] = cmd0;
|
||||
ssp->ssp_pio_words[2] = cmd1;
|
||||
ssp->dma_dir = DMA_NONE;
|
||||
ssp->slave_dirn = DMA_TRANS_NONE;
|
||||
desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
|
||||
if (!desc)
|
||||
goto out;
|
||||
|
||||
dmaengine_submit(desc);
|
||||
dma_async_issue_pending(host->dmach);
|
||||
dma_async_issue_pending(ssp->dmach);
|
||||
return;
|
||||
|
||||
out:
|
||||
|
@ -441,11 +436,11 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
|
|||
writel(val, ssp->base + HW_SSP_TIMING(ssp));
|
||||
|
||||
/* pio */
|
||||
host->ssp_pio_words[0] = ctrl0;
|
||||
host->ssp_pio_words[1] = cmd0;
|
||||
host->ssp_pio_words[2] = cmd1;
|
||||
host->dma_dir = DMA_NONE;
|
||||
host->slave_dirn = DMA_TRANS_NONE;
|
||||
ssp->ssp_pio_words[0] = ctrl0;
|
||||
ssp->ssp_pio_words[1] = cmd0;
|
||||
ssp->ssp_pio_words[2] = cmd1;
|
||||
ssp->dma_dir = DMA_NONE;
|
||||
ssp->slave_dirn = DMA_TRANS_NONE;
|
||||
desc = mxs_mmc_prep_dma(host, 0);
|
||||
if (!desc)
|
||||
goto out;
|
||||
|
@ -453,14 +448,14 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
|
|||
/* append data sg */
|
||||
WARN_ON(host->data != NULL);
|
||||
host->data = data;
|
||||
host->dma_dir = dma_data_dir;
|
||||
host->slave_dirn = slave_dirn;
|
||||
ssp->dma_dir = dma_data_dir;
|
||||
ssp->slave_dirn = slave_dirn;
|
||||
desc = mxs_mmc_prep_dma(host, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc)
|
||||
goto out;
|
||||
|
||||
dmaengine_submit(desc);
|
||||
dma_async_issue_pending(host->dmach);
|
||||
dma_async_issue_pending(ssp->dmach);
|
||||
return;
|
||||
out:
|
||||
dev_warn(mmc_dev(host->mmc),
|
||||
|
@ -557,14 +552,15 @@ static const struct mmc_host_ops mxs_mmc_ops = {
|
|||
static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct mxs_mmc_host *host = param;
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
|
||||
if (!mxs_dma_is_apbh(chan))
|
||||
return false;
|
||||
|
||||
if (chan->chan_id != host->dma_channel)
|
||||
if (chan->chan_id != ssp->dma_channel)
|
||||
return false;
|
||||
|
||||
chan->private = &host->dma_data;
|
||||
chan->private = &ssp->dma_data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -632,7 +628,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
* to use generic DMA binding later when the helpers get in.
|
||||
*/
|
||||
ret = of_property_read_u32(np, "fsl,ssp-dma-channel",
|
||||
&host->dma_channel);
|
||||
&ssp->dma_channel);
|
||||
if (ret) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"failed to get dma channel\n");
|
||||
|
@ -640,7 +636,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
}
|
||||
} else {
|
||||
ssp->devid = pdev->id_entry->driver_data;
|
||||
host->dma_channel = dmares->start;
|
||||
ssp->dma_channel = dmares->start;
|
||||
}
|
||||
|
||||
host->mmc = mmc;
|
||||
|
@ -673,9 +669,9 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
host->dma_data.chan_irq = irq_dma;
|
||||
host->dmach = dma_request_channel(mask, mxs_mmc_dma_filter, host);
|
||||
if (!host->dmach) {
|
||||
ssp->dma_data.chan_irq = irq_dma;
|
||||
ssp->dmach = dma_request_channel(mask, mxs_mmc_dma_filter, host);
|
||||
if (!ssp->dmach) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"%s: failed to request dma\n", __func__);
|
||||
goto out_clk_put;
|
||||
|
@ -714,7 +710,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
mmc->max_blk_size = 1 << 0xf;
|
||||
mmc->max_blk_count = (ssp_is_old(ssp)) ? 0xff : 0xffffff;
|
||||
mmc->max_req_size = (ssp_is_old(ssp)) ? 0xffff : 0xffffffff;
|
||||
mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev);
|
||||
mmc->max_seg_size = dma_get_max_seg_size(ssp->dmach->device->dev);
|
||||
|
||||
platform_set_drvdata(pdev, mmc);
|
||||
|
||||
|
@ -734,8 +730,8 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
out_free_dma:
|
||||
if (host->dmach)
|
||||
dma_release_channel(host->dmach);
|
||||
if (ssp->dmach)
|
||||
dma_release_channel(ssp->dmach);
|
||||
out_clk_put:
|
||||
clk_disable_unprepare(ssp->clk);
|
||||
clk_put(ssp->clk);
|
||||
|
@ -754,8 +750,8 @@ static int mxs_mmc_remove(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
if (host->dmach)
|
||||
dma_release_channel(host->dmach);
|
||||
if (ssp->dmach)
|
||||
dma_release_channel(ssp->dmach);
|
||||
|
||||
clk_disable_unprepare(ssp->clk);
|
||||
clk_put(ssp->clk);
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fsl/mxs-dma.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/stmp_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#ifndef __LINUX_SPI_MXS_SPI_H__
|
||||
#define __LINUX_SPI_MXS_SPI_H__
|
||||
|
||||
#include <linux/fsl/mxs-dma.h>
|
||||
|
||||
#define ssp_is_old(host) ((host)->devid == IMX23_SSP)
|
||||
|
||||
/* SSP registers */
|
||||
|
@ -134,6 +136,13 @@ struct mxs_ssp {
|
|||
struct clk *clk;
|
||||
unsigned int clk_rate;
|
||||
enum mxs_ssp_id devid;
|
||||
|
||||
int dma_channel;
|
||||
struct dma_chan *dmach;
|
||||
struct mxs_dma_data dma_data;
|
||||
unsigned int dma_dir;
|
||||
enum dma_transfer_direction slave_dirn;
|
||||
u32 ssp_pio_words[SSP_PIO_NUM];
|
||||
};
|
||||
|
||||
void mxs_ssp_set_clk_rate(struct mxs_ssp *ssp, unsigned int rate);
|
||||
|
|
Loading…
Reference in a new issue