[PATCH] 4/7 AU1100 MMC support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Better probe/remove functions implementation.

Signed-off-by: Rodolfo Giometti <giometti@xxxxxxxx>

-- 

GNU/Linux Solutions                  e-mail:    giometti@xxxxxxxxxxxx
Linux Device Driver                             giometti@xxxxxxxxx
Embedded Systems                     		giometti@xxxxxxxx
UNIX programming                     phone:     +39 349 2432127
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c
index ec81d4b..a77be4f 100644
--- a/arch/mips/au1000/common/platform.c
+++ b/arch/mips/au1000/common/platform.c
@@ -13,6 +13,7 @@ #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/resource.h>
 
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/mach-au1x00/au1xxx.h>
 
 #if defined(CONFIG_MIPS_AU1X00_ENET) || defined(CONFIG_MIPS_AU1X00_ENET_MODULE)
@@ -212,24 +213,6 @@ static struct resource au1xxx_usb_gdt_re
 	},
 };
 
-static struct resource au1xxx_mmc_resources[] = {
-	[0] = {
-		.start          = SD0_PHYS_ADDR,
-		.end            = SD0_PHYS_ADDR + 0x40,
-		.flags          = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start		= SD1_PHYS_ADDR,
-		.end 		= SD1_PHYS_ADDR + 0x40,
-		.flags		= IORESOURCE_MEM,
-	},
-	[2] = {
-		.start          = AU1200_SD_INT,
-		.end            = AU1200_SD_INT,
-		.flags          = IORESOURCE_IRQ,
-	}
-};
-
 static u64 udc_dmamask = ~(u32)0;
 
 static struct platform_device au1xxx_usb_gdt_device = {
@@ -325,15 +308,68 @@ static struct platform_device au1200_ide
 
 static u64 au1xxx_mmc_dmamask =  ~(u32)0;
 
-static struct platform_device au1xxx_mmc_device = {
+static struct resource au1xxx_mmc0_resources[] = {
+	[0] = {
+		.name		= "mmc-base",
+		.start          = SD0_PHYS_ADDR,
+		.end            = SD0_PHYS_ADDR + 0x40,
+		.flags          = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name		= "mmc-irq",
+		.start          = AU1200_SD_INT,
+		.end            = AU1200_SD_INT,
+		.flags          = IORESOURCE_IRQ,
+	},
+	[2] = {
+		.name		= "mmc-dma",
+		.start          = DSCR_CMD0_SDMS_TX0,
+		.end            = DSCR_CMD0_SDMS_RX0,
+		.flags          = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device au1xxx_mmc0_device = {
 	.name = "au1xxx-mmc",
 	.id = 0,
 	.dev = {
 		.dma_mask               = &au1xxx_mmc_dmamask,
 		.coherent_dma_mask      = 0xffffffff,
 	},
-	.num_resources  = ARRAY_SIZE(au1xxx_mmc_resources),
-	.resource       = au1xxx_mmc_resources,
+	.num_resources  = ARRAY_SIZE(au1xxx_mmc0_resources),
+	.resource       = au1xxx_mmc0_resources,
+};
+
+static struct resource au1xxx_mmc1_resources[] = {
+	[0] = {
+		.name		= "mmc-base",
+		.start          = SD1_PHYS_ADDR,
+		.end            = SD1_PHYS_ADDR + 0x40,
+		.flags          = IORESOURCE_MEM,
+	},
+	[1] = {
+		.name		= "mmc-irq",
+		.start          = AU1200_SD_INT,
+		.end            = AU1200_SD_INT,
+		.flags          = IORESOURCE_IRQ,
+	},
+	[2] = {
+		.name		= "mmc-dma",
+		.start          = DSCR_CMD0_SDMS_TX1,
+		.end            = DSCR_CMD0_SDMS_RX1,
+		.flags          = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device au1xxx_mmc1_device = {
+	.name = "au1xxx-mmc",
+	.id = 1,
+	.dev = {
+		.dma_mask               = &au1xxx_mmc_dmamask,
+		.coherent_dma_mask      = 0xffffffff,
+	},
+	.num_resources  = ARRAY_SIZE(au1xxx_mmc1_resources),
+	.resource       = au1xxx_mmc1_resources,
 };
 #endif /* #ifdef CONFIG_SOC_AU1200 */
 
@@ -414,7 +450,8 @@ #ifdef CONFIG_SOC_AU1200
 	&au1xxx_usb_otg_device,
 	&au1200_lcd_device,
 	&au1200_ide0_device,
-	&au1xxx_mmc_device,
+	&au1xxx_mmc0_device,
+	&au1xxx_mmc1_device,
 #endif
 #ifdef CONFIG_MIPS_DB1200
 	&smc91x_device,
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index 560d6e3..10e8e06 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -44,12 +44,11 @@ #include <linux/dma-mapping.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/protocol.h>
 #include <asm/io.h>
-#include <asm/mach-au1x00/au1000.h>
+#include <au1xxx.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/mach-au1x00/au1100_mmc.h>
 #include <asm/scatterlist.h>
 
-#include <au1xxx.h>
 #include "au1xmmc.h"
 
 #define DRIVER_NAME "au1xxx-mmc"
@@ -66,25 +65,16 @@ #define info(fmt, idx, args...) printk(K
 					fmt, DRIVER_NAME, idx, ##args)
 
 const struct {
-	u32 iobase;
-	u32 tx_devid, rx_devid;
-	u16 power;
-	u16 status;
-	u16 wpstatus;
+	u32 power;
+	u32 status;
+	u32 wpstatus;
 } au1xmmc_card_table[] = {
-	{ SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0,
-	  BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP },
+	{ BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP },
 #ifndef CONFIG_MIPS_DB1200
-	{ SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1,
-	  BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP }
+	{ BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP }
 #endif
 };
 
-#define AU1XMMC_CONTROLLER_COUNT \
-	(sizeof(au1xmmc_card_table) / sizeof(au1xmmc_card_table[0]))
-
-/* This array stores pointers for the hosts (used by the IRQ handler) */
-struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT];
 static int dma = 1;
 
 #ifdef MODULE
@@ -780,67 +770,64 @@ #define STATUS_DATA_OUT (SD_STATUS_TH)
 
 static irqreturn_t au1xmmc_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
-
+	struct au1xmmc_host *host = dev_id;
 	u32 status;
 	int i, ret = 0;
 
 	disable_irq(AU1100_SD_IRQ);
 
-	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
-		struct au1xmmc_host * host = au1xmmc_hosts[i];
-		u32 handled = 1;
+	u32 handled = 1;
 
-		status = au_readl(HOST_STATUS(host));
+	status = au_readl(HOST_STATUS(host));
 
-		if (host->mrq && (status & STATUS_TIMEOUT)) {
-			if (status & SD_STATUS_RAT)
-				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+	if (host->mrq && (status & STATUS_TIMEOUT)) {
+		if (status & SD_STATUS_RAT)
+			host->mrq->cmd->error = MMC_ERR_TIMEOUT;
 
-			else if (status & SD_STATUS_DT)
-				host->mrq->data->error = MMC_ERR_TIMEOUT;
+		else if (status & SD_STATUS_DT)
+			host->mrq->data->error = MMC_ERR_TIMEOUT;
 
-			/* In PIO mode, interrupts might still be enabled */
-			IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
+		/* In PIO mode, interrupts might still be enabled */
+		IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
 
-			//IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
-			tasklet_schedule(&host->finish_task);
-		}
+		//IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF);
+		tasklet_schedule(&host->finish_task);
+	}
 #if 0
-		else if (status & SD_STATUS_DD) {
+	else if (status & SD_STATUS_DD) {
 
-			/* Sometimes we get a DD before a NE in PIO mode */
+		/* Sometimes we get a DD before a NE in PIO mode */
 
-			if (!(host->flags & HOST_F_DMA) &&
-					(status & SD_STATUS_NE))
-				au1xmmc_receive_pio(host);
-			else {
-				au1xmmc_data_complete(host, status);
-				//tasklet_schedule(&host->data_task);
-			}
+		if (!(host->flags & HOST_F_DMA) &&
+				(status & SD_STATUS_NE))
+			au1xmmc_receive_pio(host);
+		else {
+			au1xmmc_data_complete(host, status);
+			//tasklet_schedule(&host->data_task);
 		}
+	}
 #endif
-		else if (status & (SD_STATUS_CR)) {
-			if (host->status == HOST_S_CMD)
-				au1xmmc_cmd_complete(host,status);
-		}
-		else if (!(host->flags & HOST_F_DMA)) {
-			if ((host->flags & HOST_F_XMIT) &&
-			    (status & STATUS_DATA_OUT))
-				au1xmmc_send_pio(host);
-			else if ((host->flags & HOST_F_RECV) &&
-			    (status & STATUS_DATA_IN))
-				au1xmmc_receive_pio(host);
-		}
-		else if (status & 0x203FBC70) {
-			dbg("Unhandled status %8.8x\n", host->id, status);
-			handled = 0;
-		}
+	else if (status & (SD_STATUS_CR)) {
+		if (host->status == HOST_S_CMD)
+			au1xmmc_cmd_complete(host,status);
+	}
+	else if (!(host->flags & HOST_F_DMA)) {
+		if ((host->flags & HOST_F_XMIT) &&
+		    (status & STATUS_DATA_OUT))
+			au1xmmc_send_pio(host);
+		else if ((host->flags & HOST_F_RECV) &&
+		    (status & STATUS_DATA_IN))
+			au1xmmc_receive_pio(host);
+	}
+	else if (status & 0x203FBC70) {
+		dbg("Unhandled status %8.8x\n", host->id, status);
+		handled = 0;
+	}
 
-		au_writel(status, HOST_STATUS(host));
-		au_sync();
+	au_writel(status, HOST_STATUS(host));
+	au_sync();
 
-		ret |= handled;
-	}
+	ret |= handled;
 
 	enable_irq(AU1100_SD_IRQ);
 	return ret;
@@ -875,8 +862,8 @@ static void au1xmmc_init_dma(struct au1x
 
 	u32 rxchan, txchan;
 
-	int txid = au1xmmc_card_table[host->id].tx_devid;
-	int rxid = au1xmmc_card_table[host->id].rx_devid;
+	int txid = host->tx_devid;
+	int rxid = host->rx_devid;
 
 	/* 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
@@ -908,111 +895,152 @@ struct mmc_host_ops au1xmmc_ops = {
 
 static int __devinit au1xmmc_probe(struct platform_device *pdev)
 {
+	struct resource *res;
+	u32 base_addr_phys;
+	void *base_addr;
+	struct mmc_host *mmc;
+	struct au1xmmc_host *host = 0;
+	int irq, tx_devid = 0, rx_devid = 0, ret;
+
+	/* Get the resource info */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mmc-base");
+	if (!res)
+		return -ENODEV;
+	base_addr_phys = res->start;
+	base_addr = ioremap(res->start, res->end - res->start);
+	if (!base_addr) {
+		err("unable to remap phys addr %x\n", pdev->id, base_addr_phys);
+		return -EINVAL;
+	}
 
-	int i, ret = 0;
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "mmc-irq");
+	if (!res)
+		return -ENODEV;
+	irq = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "mmc-dma");
+	if (!res)
+		return -ENODEV;
+	tx_devid = res->start;
+	rx_devid = res->end;
+
+	mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
+	if (!mmc) {
+		err("no mem for host\n", pdev->id);
+		return -ENOMEM;
+	}
 
-	/* THe interrupt is shared among all controllers */
-	ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, IRQF_DISABLED, "MMC", 0);
+	mmc->ops = &au1xmmc_ops;
 
-	if (ret) {
-		err("ERROR: Couldn't get int %d: %d\n",
-				AU1100_SD_IRQ, ret);
-		return -ENXIO;
-	}
+	mmc->f_min =   450000;
+	mmc->f_max = 24000000;
 
-	disable_irq(AU1100_SD_IRQ);
+	mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
+	mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
 
-	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
-		struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
-		struct au1xmmc_host *host = 0;
+	mmc->ocr_avail = AU1XMMC_OCR;
 
-		if (!mmc) {
-			err("ERROR: no mem for host %d\n", i);
-			au1xmmc_hosts[i] = 0;
-			continue;
-		}
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
 
-		mmc->ops = &au1xmmc_ops;
+	host->id = pdev->id;
+	host->iobase = (u32) base_addr;
+	host->irq = irq;
+	host->tx_devid = tx_devid;
+	host->rx_devid = rx_devid;
+	host->clock = 0;
+	host->power_mode = MMC_POWER_OFF;
 
-		mmc->f_min =   450000;
-		mmc->f_max = 24000000;
+	host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;
+	host->status = HOST_S_IDLE;
 
-		mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
-		mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+	init_timer(&host->timer);
 
-		mmc->ocr_avail = AU1XMMC_OCR;
+	host->timer.function = au1xmmc_poll_event;
+	host->timer.data = (unsigned long) host;
+	host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
 
-		host = mmc_priv(mmc);
-		host->mmc = mmc;
+	tasklet_init(&host->data_task, au1xmmc_tasklet_data,
+			(unsigned long) host);
 
-		host->id = i;
-		host->iobase = au1xmmc_card_table[host->id].iobase;
-		host->clock = 0;
-		host->power_mode = MMC_POWER_OFF;
+	tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
+			(unsigned long) host);
 
-		host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0;
-		host->status = HOST_S_IDLE;
+	spin_lock_init(&host->lock);
 
-		init_timer(&host->timer);
+	if (dma != 0)
+		au1xmmc_init_dma(host);
 
-		host->timer.function = au1xmmc_poll_event;
-		host->timer.data = (unsigned long) host;
-		host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
+	au1xmmc_reset_controller(host);
 
-		tasklet_init(&host->data_task, au1xmmc_tasklet_data,
-				(unsigned long) host);
+	mmc_add_host(mmc);
 
-		tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
-				(unsigned long) host);
+	add_timer(&host->timer);
 
-		spin_lock_init(&host->lock);
+	ret = request_irq(irq, au1xmmc_irq, IRQF_SHARED, "MMC", host);
+	if (ret) {
+		err("couldn't get int %d: %d\n", host->id, irq, ret);
+		ret = -ENXIO;
+		goto exit;
+	}
 
-		if (dma != 0)
-			au1xmmc_init_dma(host);
+	info("MMC controller set up at %x irq %d (mode=%s)\n",
+		host->id, base_addr_phys, host->irq, dma ? "dma" : "pio");
 
-		au1xmmc_reset_controller(host);
+	enable_irq(AU1100_SD_IRQ);
+	platform_set_drvdata(pdev, host);
 
-		mmc_add_host(mmc);
-		au1xmmc_hosts[i] = host;
+	return 0;
 
-		add_timer(&host->timer);
+exit :
+	iounmap(base_addr);
 
-		info("MMC Controller %d set up at %x (mode=%s)\n",
-		       host->id, host->iobase, dma ? "dma" : "pio");
-	}
+	tasklet_kill(&host->data_task);
+	tasklet_kill(&host->finish_task);
 
-	enable_irq(AU1100_SD_IRQ);
+	del_timer_sync(&host->timer);
+	au1xmmc_set_power(host, 0);
 
-	return 0;
+	mmc_remove_host(mmc);
+
+	au1xxx_dbdma_chan_free(host->tx_chan);
+	au1xxx_dbdma_chan_free(host->rx_chan);
+
+	au_writel(0x0, HOST_ENABLE(host));
+	au_sync();
+
+	return ret;
 }
 
 static int __devexit au1xmmc_remove(struct platform_device *pdev)
 {
+	struct au1xmmc_host *host = platform_get_drvdata(pdev);
+	struct mmc_host *mmc = host->mmc;
+	void *base_addr = (void *) host->iobase;
 
-	int i;
+	if (!host)
+		return 0;
 
 	disable_irq(AU1100_SD_IRQ);
 
-	for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) {
-		struct au1xmmc_host *host = au1xmmc_hosts[i];
-		if (!host) continue;
+	tasklet_kill(&host->data_task);
+	tasklet_kill(&host->finish_task);
 
-		tasklet_kill(&host->data_task);
-		tasklet_kill(&host->finish_task);
+	del_timer_sync(&host->timer);
+	au1xmmc_set_power(host, 0);
 
-		del_timer_sync(&host->timer);
-		au1xmmc_set_power(host, 0);
+	mmc_remove_host(mmc);
 
-		mmc_remove_host(host->mmc);
+	au1xxx_dbdma_chan_free(host->tx_chan);
+	au1xxx_dbdma_chan_free(host->rx_chan);
 
-		au1xxx_dbdma_chan_free(host->tx_chan);
-		au1xxx_dbdma_chan_free(host->rx_chan);
+	au_writel(0x0, HOST_ENABLE(host));
+	au_sync();
 
-		au_writel(0x0, HOST_ENABLE(host));
-		au_sync();
-	}
+	free_irq(host->irq, host);
+
+	iounmap(base_addr);
 
-	free_irq(AU1100_SD_IRQ, 0);
 	return 0;
 }
 
diff --git a/drivers/mmc/au1xmmc.h b/drivers/mmc/au1xmmc.h
index 341cbdf..8f7fec1 100644
--- a/drivers/mmc/au1xmmc.h
+++ b/drivers/mmc/au1xmmc.h
@@ -53,6 +53,9 @@ struct au1xmmc_host {
 
   u32 flags;
   u32 iobase;
+  int irq;
+  int tx_devid;
+  int rx_devid;
   u32 clock;
   u32 bus_width;
   u32 power_mode;

[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux