mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
spi: Updates for v3.7
No framework work here, only a bunch of driver updates of varying sizes:
- Factoring out of the core hardware support from the MXS MMC driver by
Marek Vasut to allow the hardware to also be used for SPI.
- Lots of error handling cleanups from Guenter Roeck
- Removal of the existing Tegra driver which is quite comprehensively
broken as detailed in the changelog for the removal.
- DT suppport for the PL022 and GPIO drivers.
- pinctrl support for OMAP and PL022.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)
iQIcBAABAgAGBQJQarn8AAoJEOoSHmUN5Tg49U4QAKeAPTxlKBSwHuJUpvKsCFF7
rfN9wsViOigcItsk065C1g20wViw6t8pSFkNmRzmbsIdSofqCYZlJapgWM5j2cXp
BXs8z7za0JmK62ftS6C3IydacJPRDY/zd0fnSqXnhQOG7Z3YxDYJrM3Ugc97ZE6+
dg9NUn6rw9ZSwHEwpl08H8tLYqNkd8A+wayPYKr0GSWX7EAqS8cJEWjS0DtvDAm1
LxMx4BQHCorR6ydUZJrfhG6fLsubhIuMnXI4Ajhv/Ictl1qHH1Zx3mIAB+BNVV/B
RlaQxPycr0eSikZ9UPMNST2o8vCRvamSfguPfBHMzRdRBp8M3TOKkNM2PmEGzCJW
pgpDsMNAkEfktGqQfMTBJJMbAPLux1W5mPjfcjt7vOS+q6lkFPtecGdKbynnmLX6
Vf6nImwp1vyNIvcCip0YZId+j/LrQimuDfMQOH99mwxbkNqMMA401bsxEt8ELmut
Qt1XEFoS6Xxj8n2BhTS/lMgEzz8zOuH9uOJI0hpNtctOfue6vqPm76GaefVC1i/B
jpMpUwexwsFc6IhekVFG0MAkolMhFmhlTwk9N24yfgArH8D1pa3emBFN762BQUHE
Ba7pghcwZADm8rT5SFNoxblcyekT/hCSRSiQ55MHUpqdH77/eVA1Lah4PaHiOqxz
b0mu9Ae98K077vGP3Z6r
=ld23
-----END PGP SIGNATURE-----
Merge tag 'spi-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc
Pull spi updates from Mark Brown:
"No framework work here, only a bunch of driver updates of varying
sizes:
- Factoring out of the core hardware support from the MXS MMC driver
by Marek Vasut to allow the hardware to also be used for SPI.
- Lots of error handling cleanups from Guenter Roeck
- Removal of the existing Tegra driver which is quite comprehensively
broken as detailed in the changelog for the removal.
- DT suppport for the PL022 and GPIO drivers.
- pinctrl support for OMAP and PL022."
Pulling from Mark Brown as Grant Likely is still busy moving.
* tag 'spi-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc: (53 commits)
spi: remove completely broken Tegra driver
spi/imx: set the inactive state of the clock according to the clock polarity
spi/pl022: get/put resources on suspend/resume
spi/pl022: use more managed resources
spi/pl022: Devicetree support w/o platform data
spi/s3c64xx: Don't free controller_data on non-dt platforms
spi: omap2-mcspi: add pinctrl support
spi/pl022: adopt pinctrl support
spi: omap2-mcspi: Cleanup the omap2_mcspi_txrx_dma function
spi/gpio: Fix stub for spi_gpio_probe_dt()
spi/mxs: Make the SPI block clock speed configurable via DT
spi: spi-sh-hspi: drop frees of devm_ alloc'd data
spi/pl022: Fix chipselects pointer computation
spi: spi-tle62x0: Use module_spi_driver macro
mxs/spi: Rework the mxs_ssp_timeout to be more readable
mxs/spi: Decrement the DMA/PIO border
mxs/spi: Increment the transfer length only if transfer succeeded
mxs/spi: Fix issues when doing long continuous transfer
spi: spi-gpio: Add DT bindings
spi: spi-gpio: store chipselect information in private structure
...
This commit is contained in:
commit
7fe0b14b72
33 changed files with 2114 additions and 1260 deletions
|
|
@ -41,91 +41,13 @@
|
|||
#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>
|
||||
#include <linux/spi/mxs-spi.h>
|
||||
|
||||
#define DRIVER_NAME "mxs-mmc"
|
||||
|
||||
/* card detect polling timeout */
|
||||
#define MXS_MMC_DETECT_TIMEOUT (HZ/2)
|
||||
|
||||
#define ssp_is_old(host) ((host)->devid == IMX23_MMC)
|
||||
|
||||
/* SSP registers */
|
||||
#define HW_SSP_CTRL0 0x000
|
||||
#define BM_SSP_CTRL0_RUN (1 << 29)
|
||||
#define BM_SSP_CTRL0_SDIO_IRQ_CHECK (1 << 28)
|
||||
#define BM_SSP_CTRL0_IGNORE_CRC (1 << 26)
|
||||
#define BM_SSP_CTRL0_READ (1 << 25)
|
||||
#define BM_SSP_CTRL0_DATA_XFER (1 << 24)
|
||||
#define BP_SSP_CTRL0_BUS_WIDTH (22)
|
||||
#define BM_SSP_CTRL0_BUS_WIDTH (0x3 << 22)
|
||||
#define BM_SSP_CTRL0_WAIT_FOR_IRQ (1 << 21)
|
||||
#define BM_SSP_CTRL0_LONG_RESP (1 << 19)
|
||||
#define BM_SSP_CTRL0_GET_RESP (1 << 17)
|
||||
#define BM_SSP_CTRL0_ENABLE (1 << 16)
|
||||
#define BP_SSP_CTRL0_XFER_COUNT (0)
|
||||
#define BM_SSP_CTRL0_XFER_COUNT (0xffff)
|
||||
#define HW_SSP_CMD0 0x010
|
||||
#define BM_SSP_CMD0_DBL_DATA_RATE_EN (1 << 25)
|
||||
#define BM_SSP_CMD0_SLOW_CLKING_EN (1 << 22)
|
||||
#define BM_SSP_CMD0_CONT_CLKING_EN (1 << 21)
|
||||
#define BM_SSP_CMD0_APPEND_8CYC (1 << 20)
|
||||
#define BP_SSP_CMD0_BLOCK_SIZE (16)
|
||||
#define BM_SSP_CMD0_BLOCK_SIZE (0xf << 16)
|
||||
#define BP_SSP_CMD0_BLOCK_COUNT (8)
|
||||
#define BM_SSP_CMD0_BLOCK_COUNT (0xff << 8)
|
||||
#define BP_SSP_CMD0_CMD (0)
|
||||
#define BM_SSP_CMD0_CMD (0xff)
|
||||
#define HW_SSP_CMD1 0x020
|
||||
#define HW_SSP_XFER_SIZE 0x030
|
||||
#define HW_SSP_BLOCK_SIZE 0x040
|
||||
#define BP_SSP_BLOCK_SIZE_BLOCK_COUNT (4)
|
||||
#define BM_SSP_BLOCK_SIZE_BLOCK_COUNT (0xffffff << 4)
|
||||
#define BP_SSP_BLOCK_SIZE_BLOCK_SIZE (0)
|
||||
#define BM_SSP_BLOCK_SIZE_BLOCK_SIZE (0xf)
|
||||
#define HW_SSP_TIMING(h) (ssp_is_old(h) ? 0x050 : 0x070)
|
||||
#define BP_SSP_TIMING_TIMEOUT (16)
|
||||
#define BM_SSP_TIMING_TIMEOUT (0xffff << 16)
|
||||
#define BP_SSP_TIMING_CLOCK_DIVIDE (8)
|
||||
#define BM_SSP_TIMING_CLOCK_DIVIDE (0xff << 8)
|
||||
#define BP_SSP_TIMING_CLOCK_RATE (0)
|
||||
#define BM_SSP_TIMING_CLOCK_RATE (0xff)
|
||||
#define HW_SSP_CTRL1(h) (ssp_is_old(h) ? 0x060 : 0x080)
|
||||
#define BM_SSP_CTRL1_SDIO_IRQ (1 << 31)
|
||||
#define BM_SSP_CTRL1_SDIO_IRQ_EN (1 << 30)
|
||||
#define BM_SSP_CTRL1_RESP_ERR_IRQ (1 << 29)
|
||||
#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN (1 << 28)
|
||||
#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ (1 << 27)
|
||||
#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN (1 << 26)
|
||||
#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ (1 << 25)
|
||||
#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN (1 << 24)
|
||||
#define BM_SSP_CTRL1_DATA_CRC_IRQ (1 << 23)
|
||||
#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN (1 << 22)
|
||||
#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ (1 << 21)
|
||||
#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ_EN (1 << 20)
|
||||
#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ (1 << 17)
|
||||
#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN (1 << 16)
|
||||
#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ (1 << 15)
|
||||
#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN (1 << 14)
|
||||
#define BM_SSP_CTRL1_DMA_ENABLE (1 << 13)
|
||||
#define BM_SSP_CTRL1_POLARITY (1 << 9)
|
||||
#define BP_SSP_CTRL1_WORD_LENGTH (4)
|
||||
#define BM_SSP_CTRL1_WORD_LENGTH (0xf << 4)
|
||||
#define BP_SSP_CTRL1_SSP_MODE (0)
|
||||
#define BM_SSP_CTRL1_SSP_MODE (0xf)
|
||||
#define HW_SSP_SDRESP0(h) (ssp_is_old(h) ? 0x080 : 0x0a0)
|
||||
#define HW_SSP_SDRESP1(h) (ssp_is_old(h) ? 0x090 : 0x0b0)
|
||||
#define HW_SSP_SDRESP2(h) (ssp_is_old(h) ? 0x0a0 : 0x0c0)
|
||||
#define HW_SSP_SDRESP3(h) (ssp_is_old(h) ? 0x0b0 : 0x0d0)
|
||||
#define HW_SSP_STATUS(h) (ssp_is_old(h) ? 0x0c0 : 0x100)
|
||||
#define BM_SSP_STATUS_CARD_DETECT (1 << 28)
|
||||
#define BM_SSP_STATUS_SDIO_IRQ (1 << 17)
|
||||
|
||||
#define BF_SSP(value, field) (((value) << BP_SSP_##field) & BM_SSP_##field)
|
||||
|
||||
#define MXS_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \
|
||||
BM_SSP_CTRL1_RESP_ERR_IRQ | \
|
||||
BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \
|
||||
|
|
@ -135,31 +57,17 @@
|
|||
BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \
|
||||
BM_SSP_CTRL1_FIFO_OVERRUN_IRQ)
|
||||
|
||||
#define SSP_PIO_NUM 3
|
||||
|
||||
enum mxs_mmc_id {
|
||||
IMX23_MMC,
|
||||
IMX28_MMC,
|
||||
};
|
||||
/* card detect polling timeout */
|
||||
#define MXS_MMC_DETECT_TIMEOUT (HZ/2)
|
||||
|
||||
struct mxs_mmc_host {
|
||||
struct mxs_ssp ssp;
|
||||
|
||||
struct mmc_host *mmc;
|
||||
struct mmc_request *mrq;
|
||||
struct mmc_command *cmd;
|
||||
struct mmc_data *data;
|
||||
|
||||
void __iomem *base;
|
||||
int dma_channel;
|
||||
struct clk *clk;
|
||||
unsigned int clk_rate;
|
||||
|
||||
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];
|
||||
|
||||
enum mxs_mmc_id devid;
|
||||
unsigned char bus_width;
|
||||
spinlock_t lock;
|
||||
int sdio_irq_en;
|
||||
|
|
@ -186,16 +94,18 @@ static int mxs_mmc_get_ro(struct mmc_host *mmc)
|
|||
static int mxs_mmc_get_cd(struct mmc_host *mmc)
|
||||
{
|
||||
struct mxs_mmc_host *host = mmc_priv(mmc);
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
|
||||
return !(readl(host->base + HW_SSP_STATUS(host)) &
|
||||
return !(readl(ssp->base + HW_SSP_STATUS(ssp)) &
|
||||
BM_SSP_STATUS_CARD_DETECT);
|
||||
}
|
||||
|
||||
static void mxs_mmc_reset(struct mxs_mmc_host *host)
|
||||
{
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
u32 ctrl0, ctrl1;
|
||||
|
||||
stmp_reset_block(host->base);
|
||||
stmp_reset_block(ssp->base);
|
||||
|
||||
ctrl0 = BM_SSP_CTRL0_IGNORE_CRC;
|
||||
ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) |
|
||||
|
|
@ -211,15 +121,15 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host)
|
|||
writel(BF_SSP(0xffff, TIMING_TIMEOUT) |
|
||||
BF_SSP(2, TIMING_CLOCK_DIVIDE) |
|
||||
BF_SSP(0, TIMING_CLOCK_RATE),
|
||||
host->base + HW_SSP_TIMING(host));
|
||||
ssp->base + HW_SSP_TIMING(ssp));
|
||||
|
||||
if (host->sdio_irq_en) {
|
||||
ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
|
||||
ctrl1 |= BM_SSP_CTRL1_SDIO_IRQ_EN;
|
||||
}
|
||||
|
||||
writel(ctrl0, host->base + HW_SSP_CTRL0);
|
||||
writel(ctrl1, host->base + HW_SSP_CTRL1(host));
|
||||
writel(ctrl0, ssp->base + HW_SSP_CTRL0);
|
||||
writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp));
|
||||
}
|
||||
|
||||
static void mxs_mmc_start_cmd(struct mxs_mmc_host *host,
|
||||
|
|
@ -230,21 +140,22 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host)
|
|||
struct mmc_command *cmd = host->cmd;
|
||||
struct mmc_data *data = host->data;
|
||||
struct mmc_request *mrq = host->mrq;
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
|
||||
if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) {
|
||||
if (mmc_resp_type(cmd) & MMC_RSP_136) {
|
||||
cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0(host));
|
||||
cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1(host));
|
||||
cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2(host));
|
||||
cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3(host));
|
||||
cmd->resp[3] = readl(ssp->base + HW_SSP_SDRESP0(ssp));
|
||||
cmd->resp[2] = readl(ssp->base + HW_SSP_SDRESP1(ssp));
|
||||
cmd->resp[1] = readl(ssp->base + HW_SSP_SDRESP2(ssp));
|
||||
cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP3(ssp));
|
||||
} else {
|
||||
cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0(host));
|
||||
cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP0(ssp));
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
@ -277,13 +188,14 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id)
|
|||
struct mxs_mmc_host *host = dev_id;
|
||||
struct mmc_command *cmd = host->cmd;
|
||||
struct mmc_data *data = host->data;
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
u32 stat;
|
||||
|
||||
spin_lock(&host->lock);
|
||||
|
||||
stat = readl(host->base + HW_SSP_CTRL1(host));
|
||||
stat = readl(ssp->base + HW_SSP_CTRL1(ssp));
|
||||
writel(stat & MXS_MMC_IRQ_BITS,
|
||||
host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_CLR);
|
||||
ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR);
|
||||
|
||||
spin_unlock(&host->lock);
|
||||
|
||||
|
|
@ -312,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;
|
||||
|
|
@ -320,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;
|
||||
|
|
@ -345,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;
|
||||
|
|
@ -358,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:
|
||||
|
|
@ -378,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;
|
||||
|
|
@ -399,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:
|
||||
|
|
@ -447,6 +362,8 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
|
|||
unsigned int data_size = 0, log2_blksz;
|
||||
unsigned int blocks = data->blocks;
|
||||
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
|
||||
u32 ignore_crc, get_resp, long_resp, read;
|
||||
u32 ctrl0, cmd0, cmd1, val;
|
||||
|
||||
|
|
@ -489,15 +406,15 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
|
|||
blocks = 1;
|
||||
|
||||
/* xfer count, block size and count need to be set differently */
|
||||
if (ssp_is_old(host)) {
|
||||
if (ssp_is_old(ssp)) {
|
||||
ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT);
|
||||
cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) |
|
||||
BF_SSP(blocks - 1, CMD0_BLOCK_COUNT);
|
||||
} else {
|
||||
writel(data_size, host->base + HW_SSP_XFER_SIZE);
|
||||
writel(data_size, ssp->base + HW_SSP_XFER_SIZE);
|
||||
writel(BF_SSP(log2_blksz, BLOCK_SIZE_BLOCK_SIZE) |
|
||||
BF_SSP(blocks - 1, BLOCK_SIZE_BLOCK_COUNT),
|
||||
host->base + HW_SSP_BLOCK_SIZE);
|
||||
ssp->base + HW_SSP_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if ((cmd->opcode == MMC_STOP_TRANSMISSION) ||
|
||||
|
|
@ -512,18 +429,18 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
|
|||
}
|
||||
|
||||
/* set the timeout count */
|
||||
timeout = mxs_ns_to_ssp_ticks(host->clk_rate, data->timeout_ns);
|
||||
val = readl(host->base + HW_SSP_TIMING(host));
|
||||
timeout = mxs_ns_to_ssp_ticks(ssp->clk_rate, data->timeout_ns);
|
||||
val = readl(ssp->base + HW_SSP_TIMING(ssp));
|
||||
val &= ~(BM_SSP_TIMING_TIMEOUT);
|
||||
val |= BF_SSP(timeout, TIMING_TIMEOUT);
|
||||
writel(val, host->base + HW_SSP_TIMING(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;
|
||||
|
|
@ -531,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),
|
||||
|
|
@ -579,42 +496,6 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
|||
mxs_mmc_start_cmd(host, mrq->cmd);
|
||||
}
|
||||
|
||||
static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate)
|
||||
{
|
||||
unsigned int ssp_clk, ssp_sck;
|
||||
u32 clock_divide, clock_rate;
|
||||
u32 val;
|
||||
|
||||
ssp_clk = clk_get_rate(host->clk);
|
||||
|
||||
for (clock_divide = 2; clock_divide <= 254; clock_divide += 2) {
|
||||
clock_rate = DIV_ROUND_UP(ssp_clk, rate * clock_divide);
|
||||
clock_rate = (clock_rate > 0) ? clock_rate - 1 : 0;
|
||||
if (clock_rate <= 255)
|
||||
break;
|
||||
}
|
||||
|
||||
if (clock_divide > 254) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"%s: cannot set clock to %d\n", __func__, rate);
|
||||
return;
|
||||
}
|
||||
|
||||
ssp_sck = ssp_clk / clock_divide / (1 + clock_rate);
|
||||
|
||||
val = readl(host->base + HW_SSP_TIMING(host));
|
||||
val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE);
|
||||
val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE);
|
||||
val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE);
|
||||
writel(val, host->base + HW_SSP_TIMING(host));
|
||||
|
||||
host->clk_rate = ssp_sck;
|
||||
|
||||
dev_dbg(mmc_dev(host->mmc),
|
||||
"%s: clock_divide %d, clock_rate %d, ssp_clk %d, rate_actual %d, rate_requested %d\n",
|
||||
__func__, clock_divide, clock_rate, ssp_clk, ssp_sck, rate);
|
||||
}
|
||||
|
||||
static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
struct mxs_mmc_host *host = mmc_priv(mmc);
|
||||
|
|
@ -627,12 +508,13 @@ static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
host->bus_width = 0;
|
||||
|
||||
if (ios->clock)
|
||||
mxs_mmc_set_clk_rate(host, ios->clock);
|
||||
mxs_ssp_set_clk_rate(&host->ssp, ios->clock);
|
||||
}
|
||||
|
||||
static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||||
{
|
||||
struct mxs_mmc_host *host = mmc_priv(mmc);
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
|
@ -641,19 +523,19 @@ static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
|||
|
||||
if (enable) {
|
||||
writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK,
|
||||
host->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
||||
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
|
||||
writel(BM_SSP_CTRL1_SDIO_IRQ_EN,
|
||||
host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_SET);
|
||||
} else {
|
||||
writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK,
|
||||
host->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
|
||||
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR);
|
||||
writel(BM_SSP_CTRL1_SDIO_IRQ_EN,
|
||||
host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_CLR);
|
||||
ssp->base + HW_SSP_CTRL1(ssp) + STMP_OFFSET_REG_CLR);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
if (enable && readl(host->base + HW_SSP_STATUS(host)) &
|
||||
if (enable && readl(ssp->base + HW_SSP_STATUS(ssp)) &
|
||||
BM_SSP_STATUS_SDIO_IRQ)
|
||||
mmc_signal_sdio_irq(host->mmc);
|
||||
|
||||
|
|
@ -670,34 +552,35 @@ 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;
|
||||
}
|
||||
|
||||
static struct platform_device_id mxs_mmc_ids[] = {
|
||||
static struct platform_device_id mxs_ssp_ids[] = {
|
||||
{
|
||||
.name = "imx23-mmc",
|
||||
.driver_data = IMX23_MMC,
|
||||
.driver_data = IMX23_SSP,
|
||||
}, {
|
||||
.name = "imx28-mmc",
|
||||
.driver_data = IMX28_MMC,
|
||||
.driver_data = IMX28_SSP,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mxs_mmc_ids);
|
||||
MODULE_DEVICE_TABLE(platform, mxs_ssp_ids);
|
||||
|
||||
static const struct of_device_id mxs_mmc_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_MMC, },
|
||||
{ .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_MMC, },
|
||||
{ .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_SSP, },
|
||||
{ .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_SSP, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids);
|
||||
|
|
@ -716,6 +599,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
dma_cap_mask_t mask;
|
||||
struct regulator *reg_vmmc;
|
||||
enum of_gpio_flags flags;
|
||||
struct mxs_ssp *ssp;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
|
|
@ -729,28 +613,30 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
host->base = devm_request_and_ioremap(&pdev->dev, iores);
|
||||
if (!host->base) {
|
||||
ssp = &host->ssp;
|
||||
ssp->dev = &pdev->dev;
|
||||
ssp->base = devm_request_and_ioremap(&pdev->dev, iores);
|
||||
if (!ssp->base) {
|
||||
ret = -EADDRNOTAVAIL;
|
||||
goto out_mmc_free;
|
||||
}
|
||||
|
||||
if (np) {
|
||||
host->devid = (enum mxs_mmc_id) of_id->data;
|
||||
ssp->devid = (enum mxs_ssp_id) of_id->data;
|
||||
/*
|
||||
* TODO: This is a temporary solution and should be changed
|
||||
* 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");
|
||||
goto out_mmc_free;
|
||||
}
|
||||
} else {
|
||||
host->devid = pdev->id_entry->driver_data;
|
||||
host->dma_channel = dmares->start;
|
||||
ssp->devid = pdev->id_entry->driver_data;
|
||||
ssp->dma_channel = dmares->start;
|
||||
}
|
||||
|
||||
host->mmc = mmc;
|
||||
|
|
@ -772,20 +658,20 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
goto out_mmc_free;
|
||||
}
|
||||
|
||||
host->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(host->clk)) {
|
||||
ret = PTR_ERR(host->clk);
|
||||
ssp->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(ssp->clk)) {
|
||||
ret = PTR_ERR(ssp->clk);
|
||||
goto out_mmc_free;
|
||||
}
|
||||
clk_prepare_enable(host->clk);
|
||||
clk_prepare_enable(ssp->clk);
|
||||
|
||||
mxs_mmc_reset(host);
|
||||
|
||||
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;
|
||||
|
|
@ -822,9 +708,9 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
|
||||
mmc->max_segs = 52;
|
||||
mmc->max_blk_size = 1 << 0xf;
|
||||
mmc->max_blk_count = (ssp_is_old(host)) ? 0xff : 0xffffff;
|
||||
mmc->max_req_size = (ssp_is_old(host)) ? 0xffff : 0xffffffff;
|
||||
mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev);
|
||||
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(ssp->dmach->device->dev);
|
||||
|
||||
platform_set_drvdata(pdev, mmc);
|
||||
|
||||
|
|
@ -844,11 +730,11 @@ 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(host->clk);
|
||||
clk_put(host->clk);
|
||||
clk_disable_unprepare(ssp->clk);
|
||||
clk_put(ssp->clk);
|
||||
out_mmc_free:
|
||||
mmc_free_host(mmc);
|
||||
return ret;
|
||||
|
|
@ -858,16 +744,17 @@ static int mxs_mmc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct mmc_host *mmc = platform_get_drvdata(pdev);
|
||||
struct mxs_mmc_host *host = mmc_priv(mmc);
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
|
||||
mmc_remove_host(mmc);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
if (host->dmach)
|
||||
dma_release_channel(host->dmach);
|
||||
if (ssp->dmach)
|
||||
dma_release_channel(ssp->dmach);
|
||||
|
||||
clk_disable_unprepare(host->clk);
|
||||
clk_put(host->clk);
|
||||
clk_disable_unprepare(ssp->clk);
|
||||
clk_put(ssp->clk);
|
||||
|
||||
mmc_free_host(mmc);
|
||||
|
||||
|
|
@ -879,11 +766,12 @@ static int mxs_mmc_suspend(struct device *dev)
|
|||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
struct mxs_mmc_host *host = mmc_priv(mmc);
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
int ret = 0;
|
||||
|
||||
ret = mmc_suspend_host(mmc);
|
||||
|
||||
clk_disable_unprepare(host->clk);
|
||||
clk_disable_unprepare(ssp->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -892,9 +780,10 @@ static int mxs_mmc_resume(struct device *dev)
|
|||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
struct mxs_mmc_host *host = mmc_priv(mmc);
|
||||
struct mxs_ssp *ssp = &host->ssp;
|
||||
int ret = 0;
|
||||
|
||||
clk_prepare_enable(host->clk);
|
||||
clk_prepare_enable(ssp->clk);
|
||||
|
||||
ret = mmc_resume_host(mmc);
|
||||
|
||||
|
|
@ -910,7 +799,7 @@ static const struct dev_pm_ops mxs_mmc_pm_ops = {
|
|||
static struct platform_driver mxs_mmc_driver = {
|
||||
.probe = mxs_mmc_probe,
|
||||
.remove = mxs_mmc_remove,
|
||||
.id_table = mxs_mmc_ids,
|
||||
.id_table = mxs_ssp_ids,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
|||
Loading…
Reference in a new issue