All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rodolfo Giometti <giometti@linux.it>
To: linux-mips@linux-mips.org
Subject: [PATCH] 4/7 AU1100 MMC support
Date: Wed, 9 Aug 2006 23:10:14 +0200	[thread overview]
Message-ID: <20060809211014.GE13145@enneenne.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 363 bytes --]

Better probe/remove functions implementation.

Signed-off-by: Rodolfo Giometti <giometti@linux.it>

-- 

GNU/Linux Solutions                  e-mail:    giometti@enneenne.com
Linux Device Driver                             giometti@gnudd.com
Embedded Systems                     		giometti@linux.it
UNIX programming                     phone:     +39 349 2432127

[-- Attachment #2: patch-mmc-probe_remove --]
[-- Type: text/plain, Size: 14156 bytes --]

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;

                 reply	other threads:[~2006-08-09 21:09 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060809211014.GE13145@enneenne.com \
    --to=giometti@linux.it \
    --cc=linux-mips@linux-mips.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.