Supports the MMC/SD controller on Au1300 and the single slot on the DB1300 board. Signed-off-by: Kevin Hickey <khickey@xxxxxxxxxxx> --- arch/mips/alchemy/devboards/db1300/mmc.c | 154 ++++++++++++++++++++++++++++++ drivers/mmc/host/Kconfig | 2 +- drivers/mmc/host/au1xmmc.c | 18 ++-- 3 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 arch/mips/alchemy/devboards/db1300/mmc.c diff --git a/arch/mips/alchemy/devboards/db1300/mmc.c b/arch/mips/alchemy/devboards/db1300/mmc.c new file mode 100644 index 0000000..821658c --- /dev/null +++ b/arch/mips/alchemy/devboards/db1300/mmc.c @@ -0,0 +1,154 @@ +/* + * Copyright 2003-2008 RMI Corporation. All rights reserved. + * Author: Kevin Hickey <khickey@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED BY RMI Corporation 'AS IS' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL RMI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/leds.h> +#include <linux/platform_device.h> +#include <asm/mips-boards/db1300.h> +#include <asm/mach-au1x00/au1100_mmc.h> +#include <asm/mach-au1x00/au1xxx_dbdma.h> +#include <linux/dma-mapping.h> + +static volatile struct bcsr_regs *const bcsr = + (struct bcsr_regs *)(DB1300_BCSR_REGS_PHYS_ADDR + KSEG1_OFFSET); + +static int mmc_activity; +static u64 au1xxx_mmc_dmamask = DMA_32BIT_MASK; + + +static void db1300_mmcled_set(struct led_classdev *led, + enum led_brightness brightness) +{ + if (brightness != LED_OFF) { + if (++mmc_activity == 1) + bcsr->disk_leds &= ~(1 << 8); + } else { + if (--mmc_activity == 0) + bcsr->disk_leds |= (1 << 8); + } +} + +static struct led_classdev db1300mmc_led = { + .brightness_set = db1300_mmcled_set, +}; + + +static int db1300mmc1_card_readonly(void *mmc_host) +{ + return (bcsr->status & BCSR_STATUS_SD1_WP) ? 1 : 0; +} + +static int db1300mmc1_card_inserted(void *mmc_host) +{ + int retval; + retval = (bcsr->sig_status & BCSR_INT_SD1_INSERT) ? 1 : 0; + return retval; +} + +struct au1xmmc_platform_data au1xmmc_platdata[2] = { + [0] = { + .set_power = NULL, + .card_inserted = NULL, + .card_readonly = NULL, + .cd_setup = NULL, /* use poll-timer in driver */ + .led = &db1300mmc_led, + }, + [1] = { + .set_power = NULL, + .card_inserted = db1300mmc1_card_inserted, + .card_readonly = db1300mmc1_card_readonly, + .cd_setup = NULL, /* use poll-timer in driver */ + .led = &db1300mmc_led, + }, +}; + +static struct resource au13xx_mmc0_resources[] = { + [0] = { + .start = SD0_PHYS_ADDR, + .end = SD0_PHYS_ADDR + 0x7ffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1300_IRQ_SD0 + GPINT_LINUX_IRQ_OFFSET, + .end = AU1300_IRQ_SD0 + GPINT_LINUX_IRQ_OFFSET, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = DSCR_CMD0_SDMS_TX0, + .end = DSCR_CMD0_SDMS_TX0, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = DSCR_CMD0_SDMS_RX0, + .end = DSCR_CMD0_SDMS_RX0, + .flags = IORESOURCE_DMA, + } +}; + +struct platform_device au13xx_mmc0_device = { + .name = "au1xxx-mmc", + .id = 0, + .dev = { + .dma_mask = &au1xxx_mmc_dmamask, + .coherent_dma_mask = DMA_32BIT_MASK, + .platform_data = &au1xmmc_platdata[0], + }, + .num_resources = ARRAY_SIZE(au13xx_mmc0_resources), + .resource = au13xx_mmc0_resources, +}; + +static struct resource au13xx_mmc1_resources[] = { + [0] = { + .start = SD1_PHYS_ADDR, + .end = SD1_PHYS_ADDR + 0x7ffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1300_IRQ_SD1 + GPINT_LINUX_IRQ_OFFSET, + .end = AU1300_IRQ_SD1 + GPINT_LINUX_IRQ_OFFSET, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = DSCR_CMD0_SDMS_TX1, + .end = DSCR_CMD0_SDMS_TX1, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = DSCR_CMD0_SDMS_RX1, + .end = DSCR_CMD0_SDMS_RX1, + .flags = IORESOURCE_DMA, + } +}; + +struct platform_device au13xx_mmc1_device = { + .name = "au1xxx-mmc", + .id = 1, + .dev = { + .dma_mask = &au1xxx_mmc_dmamask, + .coherent_dma_mask = DMA_32BIT_MASK, + .platform_data = &au1xmmc_platdata[1], + }, + .num_resources = ARRAY_SIZE(au13xx_mmc1_resources), + .resource = au13xx_mmc1_resources, +}; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 99d4b28..a37bfee 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -99,7 +99,7 @@ config MMC_WBSD config MMC_AU1X tristate "Alchemy AU1XX0 MMC Card Interface support" - depends on SOC_AU1200 + depends on (SOC_AU1200 || SOC_AU13XX) help This selects the AMD Alchemy(R) Multimedia card interface. If you have a Alchemy platform with a MMC slot, say Y or M here. diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index d3f5561..a3b8ac7 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -353,7 +353,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) if (!data->error) { if (host->flags & HOST_F_DMA) { -#ifdef CONFIG_SOC_AU1200 /* DBDMA */ +#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) /* DBDMA */ u32 chan = DMA_CHANNEL(host); chan_tab_t *c = *((chan_tab_t **)chan); @@ -570,7 +570,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) host->status = HOST_S_DATA; if (host->flags & HOST_F_DMA) { -#ifdef CONFIG_SOC_AU1200 /* DBDMA */ +#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) /* DBDMA */ u32 channel = DMA_CHANNEL(host); /* Start the DMA as soon as the buffer gets something in it */ @@ -633,7 +633,7 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host, au_writel(data->blksz - 1, HOST_BLKSIZE(host)); if (host->flags & HOST_F_DMA) { -#ifdef CONFIG_SOC_AU1200 /* DBDMA */ +#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) /* DBDMA */ int i; u32 channel = DMA_CHANNEL(host); @@ -837,7 +837,7 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_SOC_AU1200 +#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) /* 8bit memory DMA device */ static dbdev_tab_t au1xmmc_mem_dbdev = { .dev_id = DSCR_CMD0_ALWAYS, @@ -1023,7 +1023,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) tasklet_init(&host->finish_task, au1xmmc_tasklet_finish, (unsigned long)host); -#ifdef CONFIG_SOC_AU1200 +#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) ret = au1xmmc_dbdma_init(host); if (ret) printk(KERN_INFO DRIVER_NAME ": DBDMA init failed; using PIO\n"); @@ -1068,7 +1068,7 @@ out5: au_writel(0, HOST_CONFIG2(host)); au_sync(); -#ifdef CONFIG_SOC_AU1200 +#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) au1xmmc_dbdma_shutdown(host); #endif @@ -1115,7 +1115,7 @@ static int __devexit au1xmmc_remove(struct platform_device *pdev) tasklet_kill(&host->data_task); tasklet_kill(&host->finish_task); -#ifdef CONFIG_SOC_AU1200 +#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) au1xmmc_dbdma_shutdown(host); #endif au1xmmc_set_power(host, 0); @@ -1176,7 +1176,7 @@ static struct platform_driver au1xmmc_driver = { static int __init au1xmmc_init(void) { -#ifdef CONFIG_SOC_AU1200 +#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride * of 8 bits. And since devices are shared, we need to create * our own to avoid freaking out other devices. @@ -1190,7 +1190,7 @@ static int __init au1xmmc_init(void) static void __exit au1xmmc_exit(void) { -#ifdef CONFIG_SOC_AU1200 +#if defined(CONFIG_SOC_AU1200) || defined(CONFIG_SOC_AU13XX) if (memid) au1xxx_ddma_del_device(memid); #endif -- 1.5.4.3