Merge branch 'tmio' into next
This commit is contained in:
commit
9cd0ef2b10
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue