Merge branch 'tmio' into next

This commit is contained in:
Ulf Hansson 2015-01-20 10:44:08 +01:00
commit 9cd0ef2b10
7 changed files with 166 additions and 151 deletions

View File

@ -35,10 +35,13 @@
#define EXT_ACC 0xe4 #define EXT_ACC 0xe4
#define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data)
struct sh_mobile_sdhi_of_data { struct sh_mobile_sdhi_of_data {
unsigned long tmio_flags; unsigned long tmio_flags;
unsigned long capabilities; unsigned long capabilities;
unsigned long capabilities2; unsigned long capabilities2;
enum dma_slave_buswidth dma_buswidth;
dma_addr_t dma_rx_offset; dma_addr_t dma_rx_offset;
}; };
@ -58,6 +61,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
TMIO_MMC_CLK_ACTUAL, TMIO_MMC_CLK_ACTUAL,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
.dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
.dma_rx_offset = 0x2000, .dma_rx_offset = 0x2000,
}; };
@ -84,16 +88,43 @@ struct sh_mobile_sdhi {
struct tmio_mmc_dma dma_priv; struct tmio_mmc_dma dma_priv;
}; };
static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
{
u32 val;
/*
* see also
* sh_mobile_sdhi_of_data :: dma_buswidth
*/
switch (sd_ctrl_read16(host, CTL_VERSION)) {
case 0x490C:
val = (width == 32) ? 0x0001 : 0x0000;
break;
case 0xCB0D:
val = (width == 32) ? 0x0000 : 0x0001;
break;
default:
/* nothing to do */
return;
}
sd_ctrl_write16(host, EXT_ACC, val);
}
static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f) static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
{ {
struct mmc_host *mmc = platform_get_drvdata(pdev); struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_host *host = mmc_priv(mmc);
struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); struct sh_mobile_sdhi *priv = host_to_priv(host);
int ret = clk_prepare_enable(priv->clk); int ret = clk_prepare_enable(priv->clk);
if (ret < 0) if (ret < 0)
return ret; return ret;
*f = clk_get_rate(priv->clk); *f = clk_get_rate(priv->clk);
/* enable 16bit data access on SDBUF as default */
sh_mobile_sdhi_sdbuf_width(host, 16);
return 0; return 0;
} }
@ -101,7 +132,7 @@ static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
{ {
struct mmc_host *mmc = platform_get_drvdata(pdev); struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_host *host = mmc_priv(mmc);
struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); struct sh_mobile_sdhi *priv = host_to_priv(host);
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
} }
@ -113,7 +144,7 @@ static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
udelay(1); udelay(1);
if (!timeout) { if (!timeout) {
dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n"); dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n");
return -EBUSY; return -EBUSY;
} }
@ -156,14 +187,13 @@ static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card,
return blk_size; return blk_size;
} }
static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev) static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
{ {
mmc_detect_change(platform_get_drvdata(pdev), msecs_to_jiffies(100)); sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
}
static const struct sh_mobile_sdhi_ops sdhi_ops = { /* enable 32bit access if DMA mode if possibile */
.cd_wakeup = sh_mobile_sdhi_cd_wakeup, sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16);
}; }
static int sh_mobile_sdhi_probe(struct platform_device *pdev) static int sh_mobile_sdhi_probe(struct platform_device *pdev)
{ {
@ -177,7 +207,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
int irq, ret, i = 0; int irq, ret, i = 0;
bool multiplexed_isr = true; bool multiplexed_isr = true;
struct tmio_mmc_dma *dma_priv; struct tmio_mmc_dma *dma_priv;
u16 ver;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
@ -192,26 +221,31 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
mmc_data = &priv->mmc_data; mmc_data = &priv->mmc_data;
dma_priv = &priv->dma_priv; dma_priv = &priv->dma_priv;
if (p) {
if (p->init) {
ret = p->init(pdev, &sdhi_ops);
if (ret)
return ret;
}
}
priv->clk = devm_clk_get(&pdev->dev, NULL); priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk); ret = PTR_ERR(priv->clk);
dev_err(&pdev->dev, "cannot get clock: %d\n", ret); dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
goto eclkget; goto eprobe;
} }
mmc_data->clk_enable = sh_mobile_sdhi_clk_enable; host = tmio_mmc_host_alloc(pdev);
mmc_data->clk_disable = sh_mobile_sdhi_clk_disable; if (!host) {
ret = -ENOMEM;
goto eprobe;
}
host->dma = dma_priv;
host->write16_hook = sh_mobile_sdhi_write16_hook;
host->clk_enable = sh_mobile_sdhi_clk_enable;
host->clk_disable = sh_mobile_sdhi_clk_disable;
host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
/* SD control register space size is 0x100, 0x200 for bus_shift=1 */
if (resource_size(res) > 0x100)
host->bus_shift = 1;
else
host->bus_shift = 0;
mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
if (p) { if (p) {
mmc_data->flags = p->tmio_flags; mmc_data->flags = p->tmio_flags;
mmc_data->ocr_mask = p->tmio_ocr_mask; mmc_data->ocr_mask = p->tmio_ocr_mask;
@ -231,11 +265,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
dma_priv->slave_id_rx = p->dma_slave_rx; dma_priv->slave_id_rx = p->dma_slave_rx;
} }
} }
dma_priv->alignment_shift = 1; /* 2-byte alignment */
dma_priv->filter = shdma_chan_filter; dma_priv->filter = shdma_chan_filter;
dma_priv->enable = sh_mobile_sdhi_enable_dma;
mmc_data->dma = dma_priv; mmc_data->alignment_shift = 1; /* 2-byte alignment */
/* /*
* All SDHI blocks support 2-byte and larger block sizes in 4-bit * All SDHI blocks support 2-byte and larger block sizes in 4-bit
@ -258,33 +291,18 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
*/ */
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK; mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK;
/*
* All SDHI have DMA control register
*/
mmc_data->flags |= TMIO_MMC_HAVE_CTL_DMA_REG;
if (of_id && of_id->data) { if (of_id && of_id->data) {
const struct sh_mobile_sdhi_of_data *of_data = of_id->data; const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
mmc_data->flags |= of_data->tmio_flags; mmc_data->flags |= of_data->tmio_flags;
mmc_data->capabilities |= of_data->capabilities; mmc_data->capabilities |= of_data->capabilities;
mmc_data->capabilities2 |= of_data->capabilities2; mmc_data->capabilities2 |= of_data->capabilities2;
dma_priv->dma_rx_offset = of_data->dma_rx_offset; mmc_data->dma_rx_offset = of_data->dma_rx_offset;
dma_priv->dma_buswidth = of_data->dma_buswidth;
} }
/* SD control register space size is 0x100, 0x200 for bus_shift=1 */ ret = tmio_mmc_host_probe(host, mmc_data);
mmc_data->bus_shift = resource_size(res) >> 9;
ret = tmio_mmc_host_probe(&host, pdev, mmc_data);
if (ret < 0) if (ret < 0)
goto eprobe; goto efree;
/*
* FIXME:
* this Workaround can be more clever method
*/
ver = sd_ctrl_read16(host, CTL_VERSION);
if (ver == 0xCB0D)
sd_ctrl_write16(host, EXT_ACC, 1);
/* /*
* Allow one or more specific (named) ISRs or * Allow one or more specific (named) ISRs or
@ -351,10 +369,9 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
eirq: eirq:
tmio_mmc_host_remove(host); tmio_mmc_host_remove(host);
efree:
tmio_mmc_host_free(host);
eprobe: eprobe:
eclkget:
if (p && p->cleanup)
p->cleanup(pdev);
return ret; return ret;
} }
@ -362,13 +379,9 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
{ {
struct mmc_host *mmc = platform_get_drvdata(pdev); struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_host *host = mmc_priv(mmc);
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
tmio_mmc_host_remove(host); tmio_mmc_host_remove(host);
if (p && p->cleanup)
p->cleanup(pdev);
return 0; return 0;
} }

View File

@ -88,14 +88,19 @@ static int tmio_mmc_probe(struct platform_device *pdev)
if (!res) if (!res)
return -EINVAL; return -EINVAL;
/* SD control register space size is 0x200, 0x400 for bus_shift=1 */
pdata->bus_shift = resource_size(res) >> 10;
pdata->flags |= TMIO_MMC_HAVE_HIGH_REG; pdata->flags |= TMIO_MMC_HAVE_HIGH_REG;
ret = tmio_mmc_host_probe(&host, pdev, pdata); host = tmio_mmc_host_alloc(pdev);
if (ret) if (!host)
goto cell_disable; goto cell_disable;
/* SD control register space size is 0x200, 0x400 for bus_shift=1 */
host->bus_shift = resource_size(res) >> 10;
ret = tmio_mmc_host_probe(host, pdata);
if (ret)
goto host_free;
ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING,
dev_name(&pdev->dev), host); dev_name(&pdev->dev), host);
if (ret) if (ret)
@ -108,6 +113,8 @@ static int tmio_mmc_probe(struct platform_device *pdev)
host_remove: host_remove:
tmio_mmc_host_remove(host); tmio_mmc_host_remove(host);
host_free:
tmio_mmc_host_free(host);
cell_disable: cell_disable:
if (cell->disable) if (cell->disable)
cell->disable(pdev); cell->disable(pdev);

View File

@ -16,6 +16,7 @@
#ifndef TMIO_MMC_H #ifndef TMIO_MMC_H
#define TMIO_MMC_H #define TMIO_MMC_H
#include <linux/dmaengine.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/mmc/tmio.h> #include <linux/mmc/tmio.h>
#include <linux/mutex.h> #include <linux/mutex.h>
@ -39,6 +40,17 @@
#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
struct tmio_mmc_data; struct tmio_mmc_data;
struct tmio_mmc_host;
struct tmio_mmc_dma {
void *chan_priv_tx;
void *chan_priv_rx;
int slave_id_tx;
int slave_id_rx;
enum dma_slave_buswidth dma_buswidth;
bool (*filter)(struct dma_chan *chan, void *arg);
void (*enable)(struct tmio_mmc_host *host, bool enable);
};
struct tmio_mmc_host { struct tmio_mmc_host {
void __iomem *ctl; void __iomem *ctl;
@ -56,9 +68,11 @@ struct tmio_mmc_host {
struct scatterlist *sg_orig; struct scatterlist *sg_orig;
unsigned int sg_len; unsigned int sg_len;
unsigned int sg_off; unsigned int sg_off;
unsigned long bus_shift;
struct platform_device *pdev; struct platform_device *pdev;
struct tmio_mmc_data *pdata; struct tmio_mmc_data *pdata;
struct tmio_mmc_dma *dma;
/* DMA support */ /* DMA support */
bool force_pio; bool force_pio;
@ -83,10 +97,17 @@ struct tmio_mmc_host {
struct mutex ios_lock; /* protect set_ios() context */ struct mutex ios_lock; /* protect set_ios() context */
bool native_hotplug; bool native_hotplug;
bool sdio_irq_enabled; bool sdio_irq_enabled;
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
void (*clk_disable)(struct platform_device *pdev);
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
}; };
int tmio_mmc_host_probe(struct tmio_mmc_host **host, struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev);
struct platform_device *pdev, void tmio_mmc_host_free(struct tmio_mmc_host *host);
int tmio_mmc_host_probe(struct tmio_mmc_host *host,
struct tmio_mmc_data *pdata); struct tmio_mmc_data *pdata);
void tmio_mmc_host_remove(struct tmio_mmc_host *host); void tmio_mmc_host_remove(struct tmio_mmc_host *host);
void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
@ -151,19 +172,19 @@ int tmio_mmc_host_runtime_resume(struct device *dev);
static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
{ {
return readw(host->ctl + (addr << host->pdata->bus_shift)); return readw(host->ctl + (addr << host->bus_shift));
} }
static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
u16 *buf, int count) u16 *buf, int count)
{ {
readsw(host->ctl + (addr << host->pdata->bus_shift), buf, count); readsw(host->ctl + (addr << host->bus_shift), buf, count);
} }
static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
{ {
return readw(host->ctl + (addr << host->pdata->bus_shift)) | return readw(host->ctl + (addr << host->bus_shift)) |
readw(host->ctl + ((addr + 2) << host->pdata->bus_shift)) << 16; readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
} }
static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val)
@ -171,21 +192,21 @@ static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val
/* If there is a hook and it returns non-zero then there /* If there is a hook and it returns non-zero then there
* is an error and the write should be skipped * is an error and the write should be skipped
*/ */
if (host->pdata->write16_hook && host->pdata->write16_hook(host, addr)) if (host->write16_hook && host->write16_hook(host, addr))
return; return;
writew(val, host->ctl + (addr << host->pdata->bus_shift)); writew(val, host->ctl + (addr << host->bus_shift));
} }
static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
u16 *buf, int count) u16 *buf, int count)
{ {
writesw(host->ctl + (addr << host->pdata->bus_shift), buf, count); writesw(host->ctl + (addr << host->bus_shift), buf, count);
} }
static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val)
{ {
writew(val, host->ctl + (addr << host->pdata->bus_shift)); writew(val, host->ctl + (addr << host->bus_shift));
writew(val >> 16, host->ctl + ((addr + 2) << host->pdata->bus_shift)); writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
} }

View File

@ -28,8 +28,8 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
if (!host->chan_tx || !host->chan_rx) if (!host->chan_tx || !host->chan_rx)
return; return;
if (host->pdata->flags & TMIO_MMC_HAVE_CTL_DMA_REG) if (host->dma->enable)
sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); host->dma->enable(host, enable);
} }
void tmio_mmc_abort_dma(struct tmio_mmc_host *host) void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
@ -49,11 +49,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL; struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_rx; struct dma_chan *chan = host->chan_rx;
struct tmio_mmc_data *pdata = host->pdata;
dma_cookie_t cookie; dma_cookie_t cookie;
int ret, i; int ret, i;
bool aligned = true, multiple = true; bool aligned = true, multiple = true;
unsigned int align = (1 << pdata->dma->alignment_shift) - 1; unsigned int align = (1 << host->pdata->alignment_shift) - 1;
for_each_sg(sg, sg_tmp, host->sg_len, i) { for_each_sg(sg, sg_tmp, host->sg_len, i) {
if (sg_tmp->offset & align) if (sg_tmp->offset & align)
@ -126,11 +125,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL; struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_tx; struct dma_chan *chan = host->chan_tx;
struct tmio_mmc_data *pdata = host->pdata;
dma_cookie_t cookie; dma_cookie_t cookie;
int ret, i; int ret, i;
bool aligned = true, multiple = true; bool aligned = true, multiple = true;
unsigned int align = (1 << pdata->dma->alignment_shift) - 1; unsigned int align = (1 << host->pdata->alignment_shift) - 1;
for_each_sg(sg, sg_tmp, host->sg_len, i) { for_each_sg(sg, sg_tmp, host->sg_len, i) {
if (sg_tmp->offset & align) if (sg_tmp->offset & align)
@ -262,8 +260,8 @@ out:
void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
{ {
/* We can only either use DMA for both Tx and Rx or not use it at all */ /* We can only either use DMA for both Tx and Rx or not use it at all */
if (!pdata->dma || (!host->pdev->dev.of_node && if (!host->dma || (!host->pdev->dev.of_node &&
(!pdata->dma->chan_priv_tx || !pdata->dma->chan_priv_rx))) (!host->dma->chan_priv_tx || !host->dma->chan_priv_rx)))
return; return;
if (!host->chan_tx && !host->chan_rx) { if (!host->chan_tx && !host->chan_rx) {
@ -280,7 +278,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
host->chan_tx = dma_request_slave_channel_compat(mask, host->chan_tx = dma_request_slave_channel_compat(mask,
pdata->dma->filter, pdata->dma->chan_priv_tx, host->dma->filter, host->dma->chan_priv_tx,
&host->pdev->dev, "tx"); &host->pdev->dev, "tx");
dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
host->chan_tx); host->chan_tx);
@ -288,18 +286,20 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
if (!host->chan_tx) if (!host->chan_tx)
return; return;
if (pdata->dma->chan_priv_tx) if (host->dma->chan_priv_tx)
cfg.slave_id = pdata->dma->slave_id_tx; cfg.slave_id = host->dma->slave_id_tx;
cfg.direction = DMA_MEM_TO_DEV; cfg.direction = DMA_MEM_TO_DEV;
cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->pdata->bus_shift); cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift);
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.dst_addr_width = host->dma->dma_buswidth;
if (!cfg.dst_addr_width)
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
cfg.src_addr = 0; cfg.src_addr = 0;
ret = dmaengine_slave_config(host->chan_tx, &cfg); ret = dmaengine_slave_config(host->chan_tx, &cfg);
if (ret < 0) if (ret < 0)
goto ecfgtx; goto ecfgtx;
host->chan_rx = dma_request_slave_channel_compat(mask, host->chan_rx = dma_request_slave_channel_compat(mask,
pdata->dma->filter, pdata->dma->chan_priv_rx, host->dma->filter, host->dma->chan_priv_rx,
&host->pdev->dev, "rx"); &host->pdev->dev, "rx");
dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
host->chan_rx); host->chan_rx);
@ -307,11 +307,13 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
if (!host->chan_rx) if (!host->chan_rx)
goto ereqrx; goto ereqrx;
if (pdata->dma->chan_priv_rx) if (host->dma->chan_priv_rx)
cfg.slave_id = pdata->dma->slave_id_rx; cfg.slave_id = host->dma->slave_id_rx;
cfg.direction = DMA_DEV_TO_MEM; cfg.direction = DMA_DEV_TO_MEM;
cfg.src_addr = cfg.dst_addr + pdata->dma->dma_rx_offset; cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset;
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.src_addr_width = host->dma->dma_buswidth;
if (!cfg.src_addr_width)
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
cfg.dst_addr = 0; cfg.dst_addr = 0;
ret = dmaengine_slave_config(host->chan_rx, &cfg); ret = dmaengine_slave_config(host->chan_rx, &cfg);
if (ret < 0) if (ret < 0)

View File

@ -835,13 +835,12 @@ fail:
static int tmio_mmc_clk_update(struct tmio_mmc_host *host) static int tmio_mmc_clk_update(struct tmio_mmc_host *host)
{ {
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
struct tmio_mmc_data *pdata = host->pdata;
int ret; int ret;
if (!pdata->clk_enable) if (!host->clk_enable)
return -ENOTSUPP; return -ENOTSUPP;
ret = pdata->clk_enable(host->pdev, &mmc->f_max); ret = host->clk_enable(host->pdev, &mmc->f_max);
if (!ret) if (!ret)
mmc->f_min = mmc->f_max / 512; mmc->f_min = mmc->f_max / 512;
@ -1005,10 +1004,9 @@ static int tmio_multi_io_quirk(struct mmc_card *card,
unsigned int direction, int blk_size) unsigned int direction, int blk_size)
{ {
struct tmio_mmc_host *host = mmc_priv(card->host); struct tmio_mmc_host *host = mmc_priv(card->host);
struct tmio_mmc_data *pdata = host->pdata;
if (pdata->multi_io_quirk) if (host->multi_io_quirk)
return pdata->multi_io_quirk(card, direction, blk_size); return host->multi_io_quirk(card, direction, blk_size);
return blk_size; return blk_size;
} }
@ -1054,12 +1052,37 @@ static void tmio_mmc_of_parse(struct platform_device *pdev,
pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE; pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE;
} }
int tmio_mmc_host_probe(struct tmio_mmc_host **host, struct tmio_mmc_host*
struct platform_device *pdev, tmio_mmc_host_alloc(struct platform_device *pdev)
struct tmio_mmc_data *pdata)
{ {
struct tmio_mmc_host *_host; struct tmio_mmc_host *host;
struct mmc_host *mmc; struct mmc_host *mmc;
mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev);
if (!mmc)
return NULL;
host = mmc_priv(mmc);
host->mmc = mmc;
host->pdev = pdev;
return host;
}
EXPORT_SYMBOL(tmio_mmc_host_alloc);
void tmio_mmc_host_free(struct tmio_mmc_host *host)
{
mmc_free_host(host->mmc);
host->mmc = NULL;
}
EXPORT_SYMBOL(tmio_mmc_host_free);
int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
struct tmio_mmc_data *pdata)
{
struct platform_device *pdev = _host->pdev;
struct mmc_host *mmc = _host->mmc;
struct resource *res_ctl; struct resource *res_ctl;
int ret; int ret;
u32 irq_mask = TMIO_MASK_CMD; u32 irq_mask = TMIO_MASK_CMD;
@ -1067,25 +1090,17 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
tmio_mmc_of_parse(pdev, pdata); tmio_mmc_of_parse(pdev, pdata);
if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT)) if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT))
pdata->write16_hook = NULL; _host->write16_hook = NULL;
res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0); res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res_ctl) if (!res_ctl)
return -EINVAL; return -EINVAL;
mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev);
if (!mmc)
return -ENOMEM;
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret < 0) if (ret < 0)
goto host_free; goto host_free;
pdata->dev = &pdev->dev;
_host = mmc_priv(mmc);
_host->pdata = pdata; _host->pdata = pdata;
_host->mmc = mmc;
_host->pdev = pdev;
platform_set_drvdata(pdev, mmc); platform_set_drvdata(pdev, mmc);
_host->set_pwr = pdata->set_pwr; _host->set_pwr = pdata->set_pwr;
@ -1192,12 +1207,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
mmc_gpiod_request_cd_irq(mmc); mmc_gpiod_request_cd_irq(mmc);
} }
*host = _host;
return 0; return 0;
host_free: host_free:
mmc_free_host(mmc);
return ret; return ret;
} }
@ -1222,7 +1234,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
iounmap(host->ctl); iounmap(host->ctl);
mmc_free_host(mmc);
} }
EXPORT_SYMBOL(tmio_mmc_host_remove); EXPORT_SYMBOL(tmio_mmc_host_remove);
@ -1237,8 +1248,8 @@ int tmio_mmc_host_runtime_suspend(struct device *dev)
if (host->clk_cache) if (host->clk_cache)
tmio_mmc_clk_stop(host); tmio_mmc_clk_stop(host);
if (host->pdata->clk_disable) if (host->clk_disable)
host->pdata->clk_disable(host->pdev); host->clk_disable(host->pdev);
return 0; return 0;
} }

View File

@ -95,11 +95,6 @@
*/ */
#define TMIO_MMC_SDIO_STATUS_QUIRK (1 << 8) #define TMIO_MMC_SDIO_STATUS_QUIRK (1 << 8)
/*
* Some controllers have DMA enable/disable register
*/
#define TMIO_MMC_HAVE_CTL_DMA_REG (1 << 9)
/* /*
* Some controllers allows to set SDx actual clock * Some controllers allows to set SDx actual clock
*/ */
@ -112,18 +107,6 @@ void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state);
struct dma_chan; struct dma_chan;
struct tmio_mmc_dma {
void *chan_priv_tx;
void *chan_priv_rx;
int slave_id_tx;
int slave_id_rx;
int alignment_shift;
dma_addr_t dma_rx_offset;
bool (*filter)(struct dma_chan *chan, void *arg);
};
struct tmio_mmc_host;
/* /*
* data for the MMC controller * data for the MMC controller
*/ */
@ -132,19 +115,12 @@ struct tmio_mmc_data {
unsigned long capabilities; unsigned long capabilities;
unsigned long capabilities2; unsigned long capabilities2;
unsigned long flags; unsigned long flags;
unsigned long bus_shift;
u32 ocr_mask; /* available voltages */ u32 ocr_mask; /* available voltages */
struct tmio_mmc_dma *dma;
struct device *dev;
unsigned int cd_gpio; unsigned int cd_gpio;
int alignment_shift;
dma_addr_t dma_rx_offset;
void (*set_pwr)(struct platform_device *host, int state); void (*set_pwr)(struct platform_device *host, int state);
void (*set_clk_div)(struct platform_device *host, int state); void (*set_clk_div)(struct platform_device *host, int state);
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
/* clock management callbacks */
int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
void (*clk_disable)(struct platform_device *pdev);
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
}; };
/* /*

View File

@ -3,20 +3,10 @@
#include <linux/types.h> #include <linux/types.h>
struct platform_device;
#define SH_MOBILE_SDHI_IRQ_CARD_DETECT "card_detect" #define SH_MOBILE_SDHI_IRQ_CARD_DETECT "card_detect"
#define SH_MOBILE_SDHI_IRQ_SDCARD "sdcard" #define SH_MOBILE_SDHI_IRQ_SDCARD "sdcard"
#define SH_MOBILE_SDHI_IRQ_SDIO "sdio" #define SH_MOBILE_SDHI_IRQ_SDIO "sdio"
/**
* struct sh_mobile_sdhi_ops - SDHI driver callbacks
* @cd_wakeup: trigger a card-detection run
*/
struct sh_mobile_sdhi_ops {
void (*cd_wakeup)(const struct platform_device *pdev);
};
struct sh_mobile_sdhi_info { struct sh_mobile_sdhi_info {
int dma_slave_tx; int dma_slave_tx;
int dma_slave_rx; int dma_slave_rx;
@ -25,11 +15,6 @@ struct sh_mobile_sdhi_info {
unsigned long tmio_caps2; unsigned long tmio_caps2;
u32 tmio_ocr_mask; /* available MMC voltages */ u32 tmio_ocr_mask; /* available MMC voltages */
unsigned int cd_gpio; unsigned int cd_gpio;
/* callbacks for board specific setup code */
int (*init)(struct platform_device *pdev,
const struct sh_mobile_sdhi_ops *ops);
void (*cleanup)(struct platform_device *pdev);
}; };
#endif /* LINUX_MMC_SH_MOBILE_SDHI_H */ #endif /* LINUX_MMC_SH_MOBILE_SDHI_H */