All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lars-Peter Clausen <lars@metafoo.de>
To: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org, linux-kernel@vger.kernel.org,
	Lars-Peter Clausen <lars@metafoo.de>,
	Andrew Morton <akpm@linux-foundation.org>,
	Matt Fleming <matt@console-pimps.org>,
	linux-mmc@vger.kernel.org
Subject: [PATCH v3] MMC: Add JZ4740 mmc driver
Date: Mon, 28 Jun 2010 03:20:41 +0200	[thread overview]
Message-ID: <1277688041-23522-1-git-send-email-lars@metafoo.de> (raw)
In-Reply-To: <1276924111-11158-19-git-send-email-lars@metafoo.de>

This patch adds support for the mmc controller on JZ4740 SoCs.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Matt Fleming <matt@console-pimps.org>
Cc: linux-mmc@vger.kernel.org

---
Changes since v1
- Do not request IRQ with IRQF_DISABLED since it is a noop now
- Use a generous slack for the timeout timer. It does not need to be accurate.
Changes since v2
- Use sg_mapping_to iterate over sg elements in mmc read and write functions
- Use bitops instead of a spinlock and a variable for testing whether a request
  has been finished.
- Rework irq and timeout handling in order to get rid of locking in hot paths
---
 drivers/mmc/host/Kconfig       |    8 +
 drivers/mmc/host/Makefile      |    1 +
 drivers/mmc/host/jz4740_mmc.c  |  969 ++++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/jz4740_mmc.h |   15 +
 4 files changed, 993 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mmc/host/jz4740_mmc.c
 create mode 100644 include/linux/mmc/jz4740_mmc.h

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index f06d06e..546fc49 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -81,6 +81,14 @@ config MMC_RICOH_MMC
 
 	  If unsure, say Y.
 
+config MMC_JZ4740
+	tristate "JZ4740 SD/Multimedia Card Interface support"
+	depends on MACH_JZ4740
+	help
+	  This selects the Ingenic Z4740 SD/Multimedia card Interface.
+	  If you have an ngenic platform with a Multimedia Card slot,
+	  say Y or M here.
+
 config MMC_SDHCI_OF
 	tristate "SDHCI support on OpenFirmware platforms"
 	depends on MMC_SDHCI && PPC_OF
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e30c2ee..f4e53c9 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_MMC_CB710)	+= cb710-mmc.o
 obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
 obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o
+obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o
 
 obj-$(CONFIG_MMC_SDHCI_OF)	+= sdhci-of.o
 sdhci-of-y				:= sdhci-of-core.o
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
new file mode 100644
index 0000000..b34f25b
--- /dev/null
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -0,0 +1,969 @@
+/*
+ *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  JZ4740 SD/MMC controller driver
+ *
+ *  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.
+ *
+ *  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/mmc/host.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/clk.h>
+#include <linux/mmc/jz4740_mmc.h>
+
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <asm/mach-jz4740/gpio.h>
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+
+
+#define JZ_REG_MMC_STRPCL	0x00
+#define JZ_REG_MMC_STATUS	0x04
+#define JZ_REG_MMC_CLKRT	0x08
+#define JZ_REG_MMC_CMDAT	0x0C
+#define JZ_REG_MMC_RESTO	0x10
+#define JZ_REG_MMC_RDTO		0x14
+#define JZ_REG_MMC_BLKLEN	0x18
+#define JZ_REG_MMC_NOB		0x1C
+#define JZ_REG_MMC_SNOB		0x20
+#define JZ_REG_MMC_IMASK	0x24
+#define JZ_REG_MMC_IREG		0x28
+#define JZ_REG_MMC_CMD		0x2C
+#define JZ_REG_MMC_ARG		0x30
+#define JZ_REG_MMC_RESP_FIFO	0x34
+#define JZ_REG_MMC_RXFIFO	0x38
+#define JZ_REG_MMC_TXFIFO	0x3C
+
+#define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7)
+#define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6)
+#define JZ_MMC_STRPCL_START_READWAIT BIT(5)
+#define JZ_MMC_STRPCL_STOP_READWAIT BIT(4)
+#define JZ_MMC_STRPCL_RESET BIT(3)
+#define JZ_MMC_STRPCL_START_OP BIT(2)
+#define JZ_MMC_STRPCL_CLOCK_CONTROL (BIT(1) | BIT(0))
+#define JZ_MMC_STRPCL_CLOCK_STOP BIT(0)
+#define JZ_MMC_STRPCL_CLOCK_START BIT(1)
+
+
+#define JZ_MMC_STATUS_IS_RESETTING BIT(15)
+#define JZ_MMC_STATUS_SDIO_INT_ACTIVE BIT(14)
+#define JZ_MMC_STATUS_PRG_DONE BIT(13)
+#define JZ_MMC_STATUS_DATA_TRAN_DONE BIT(12)
+#define JZ_MMC_STATUS_END_CMD_RES BIT(11)
+#define JZ_MMC_STATUS_DATA_FIFO_AFULL BIT(10)
+#define JZ_MMC_STATUS_IS_READWAIT BIT(9)
+#define JZ_MMC_STATUS_CLK_EN BIT(8)
+#define JZ_MMC_STATUS_DATA_FIFO_FULL BIT(7)
+#define JZ_MMC_STATUS_DATA_FIFO_EMPTY BIT(6)
+#define JZ_MMC_STATUS_CRC_RES_ERR BIT(5)
+#define JZ_MMC_STATUS_CRC_READ_ERROR BIT(4)
+#define JZ_MMC_STATUS_TIMEOUT_WRITE BIT(3)
+#define JZ_MMC_STATUS_CRC_WRITE_ERROR BIT(2)
+#define JZ_MMC_STATUS_TIMEOUT_RES BIT(1)
+#define JZ_MMC_STATUS_TIMEOUT_READ BIT(0)
+
+#define JZ_MMC_STATUS_READ_ERROR_MASK (BIT(4) | BIT(0))
+#define JZ_MMC_STATUS_WRITE_ERROR_MASK (BIT(3) | BIT(2))
+
+
+#define JZ_MMC_CMDAT_IO_ABORT BIT(11)
+#define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10)
+#define JZ_MMC_CMDAT_DMA_EN BIT(8)
+#define JZ_MMC_CMDAT_INIT BIT(7)
+#define JZ_MMC_CMDAT_BUSY BIT(6)
+#define JZ_MMC_CMDAT_STREAM BIT(5)
+#define JZ_MMC_CMDAT_WRITE BIT(4)
+#define JZ_MMC_CMDAT_DATA_EN BIT(3)
+#define JZ_MMC_CMDAT_RESPONSE_FORMAT (BIT(2) | BIT(1) | BIT(0))
+#define JZ_MMC_CMDAT_RSP_R1 1
+#define JZ_MMC_CMDAT_RSP_R2 2
+#define JZ_MMC_CMDAT_RSP_R3 3
+
+#define JZ_MMC_IRQ_SDIO BIT(7)
+#define JZ_MMC_IRQ_TXFIFO_WR_REQ BIT(6)
+#define JZ_MMC_IRQ_RXFIFO_RD_REQ BIT(5)
+#define JZ_MMC_IRQ_END_CMD_RES BIT(2)
+#define JZ_MMC_IRQ_PRG_DONE BIT(1)
+#define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0)
+
+
+#define JZ_MMC_CLK_RATE 24000000
+
+#define JZ4740_MMC_MAX_TIMEOUT 10000000
+
+struct jz4740_mmc_host {
+	struct mmc_host *mmc;
+	struct platform_device *pdev;
+	struct jz4740_mmc_platform_data *pdata;
+	struct clk *clk;
+
+	int irq;
+	int card_detect_irq;
+
+	struct resource *mem;
+	void __iomem *base;
+	struct mmc_request *req;
+	struct mmc_command *cmd;
+
+	unsigned long waiting;
+
+	int max_clock;
+	uint32_t cmdat;
+
+	uint16_t irq_mask;
+
+	spinlock_t lock;
+
+	struct timer_list timeout_timer;
+};
+
+static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host,
+	unsigned int irq, bool enabled)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (enabled)
+		host->irq_mask &= ~irq;
+	else
+		host->irq_mask |= irq;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK);
+}
+
+static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host,
+	bool start_transfer)
+{
+	uint16_t val = JZ_MMC_STRPCL_CLOCK_START;
+
+	if (start_transfer)
+		val |= JZ_MMC_STRPCL_START_OP;
+
+	writew(val, host->base + JZ_REG_MMC_STRPCL);
+}
+
+static void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host)
+{
+	uint32_t status;
+
+	writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL);
+	do {
+		status = readl(host->base + JZ_REG_MMC_STATUS);
+	} while (status & JZ_MMC_STATUS_CLK_EN);
+}
+
+static void jz4740_mmc_reset(struct jz4740_mmc_host *host)
+{
+	uint32_t status;
+
+	writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL);
+	udelay(10);
+	do {
+		status = readl(host->base + JZ_REG_MMC_STATUS);
+	} while (status & JZ_MMC_STATUS_IS_RESETTING);
+}
+
+static void jz4740_mmc_request_done(struct jz4740_mmc_host *host)
+{
+	struct mmc_request *req;
+
+	req = host->req;
+	host->req = NULL;
+
+	mmc_request_done(host->mmc, req);
+}
+
+static inline unsigned int jz4740_mmc_wait_irq(struct jz4740_mmc_host *host,
+	unsigned int irq)
+{
+	unsigned int timeout = JZ4740_MMC_MAX_TIMEOUT;
+	uint16_t status;
+
+	do {
+		status = readw(host->base + JZ_REG_MMC_IREG);
+	} while (!(status & irq) && --timeout);
+
+	return timeout;
+}
+
+static void jz4740_mmc_write_data(struct jz4740_mmc_host *host,
+	struct mmc_data *data)
+{
+	struct sg_mapping_iter miter;
+	uint32_t *buf;
+	int status;
+	unsigned int timeout;
+	size_t i, j;
+
+	sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG);
+	while (sg_miter_next(&miter)) {
+		buf = miter.addr;
+		i = miter.length / 4;
+		j = i >> 3;
+		i = i & 0x7;
+		while (j) {
+			timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
+			if (unlikely(timeout == 0)) {
+				sg_miter_stop(&miter);
+				goto err_timeout;
+			}
+
+			writel(buf[0], host->base + JZ_REG_MMC_TXFIFO);
+			writel(buf[1], host->base + JZ_REG_MMC_TXFIFO);
+			writel(buf[2], host->base + JZ_REG_MMC_TXFIFO);
+			writel(buf[3], host->base + JZ_REG_MMC_TXFIFO);
+			writel(buf[4], host->base + JZ_REG_MMC_TXFIFO);
+			writel(buf[5], host->base + JZ_REG_MMC_TXFIFO);
+			writel(buf[6], host->base + JZ_REG_MMC_TXFIFO);
+			writel(buf[7], host->base + JZ_REG_MMC_TXFIFO);
+			buf += 8;
+			--j;
+		}
+		if (unlikely(i)) {
+			timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
+			if (unlikely(timeout == 0)) {
+				sg_miter_stop(&miter);
+				goto err_timeout;
+			}
+
+			while (i) {
+				writel(*buf, host->base + JZ_REG_MMC_TXFIFO);
+				++buf;
+				--i;
+			}
+		}
+		data->bytes_xfered += miter.length;
+	}
+	sg_miter_stop(&miter);
+
+	status = readl(host->base + JZ_REG_MMC_STATUS);
+	if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) {
+		if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) {
+			host->req->cmd->error = -ETIMEDOUT;
+			data->error = -ETIMEDOUT;
+		} else {
+			host->req->cmd->error = -EIO;
+			data->error = -EIO;
+		}
+		return;
+	}
+
+	timeout = JZ4740_MMC_MAX_TIMEOUT;
+	do {
+		status = readl(host->base + JZ_REG_MMC_STATUS);
+	} while ((status & JZ_MMC_STATUS_DATA_TRAN_DONE) == 0 && --timeout);
+
+	if (unlikely(timeout == 0))
+		goto err_timeout;
+	writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG);
+
+	return;
+
+err_timeout:
+	host->req->cmd->error = -ETIMEDOUT;
+	data->error = -ETIMEDOUT;
+}
+
+static void jz4740_mmc_read_data(struct jz4740_mmc_host *host,
+				struct mmc_data *data)
+{
+	struct sg_mapping_iter miter;
+	uint32_t *buf;
+	uint32_t d;
+	uint16_t status = 0;
+	size_t i, j;
+	unsigned int timeout;
+
+	sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_TO_SG);
+	while (sg_miter_next(&miter)) {
+		buf = miter.addr;
+		i = miter.length;
+		j = i >> 5;
+		i = i & 0x1f;
+		while (j) {
+			timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
+			if (unlikely(timeout == 0)) {
+				sg_miter_stop(&miter);
+				goto err_timeout;
+			}
+
+			buf[0] = readl(host->base + JZ_REG_MMC_RXFIFO);
+			buf[1] = readl(host->base + JZ_REG_MMC_RXFIFO);
+			buf[2] = readl(host->base + JZ_REG_MMC_RXFIFO);
+			buf[3] = readl(host->base + JZ_REG_MMC_RXFIFO);
+			buf[4] = readl(host->base + JZ_REG_MMC_RXFIFO);
+			buf[5] = readl(host->base + JZ_REG_MMC_RXFIFO);
+			buf[6] = readl(host->base + JZ_REG_MMC_RXFIFO);
+			buf[7] = readl(host->base + JZ_REG_MMC_RXFIFO);
+
+			buf += 8;
+			--j;
+		}
+
+		while (i >= 4) {
+			timeout = jz4740_mmc_wait_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
+			if (unlikely(timeout == 0)) {
+				sg_miter_stop(&miter);
+				goto err_timeout;
+			}
+
+			*buf++ = readl(host->base + JZ_REG_MMC_RXFIFO);
+			i -= 4;
+		}
+		if (unlikely(i > 0)) {
+			d = readl(host->base + JZ_REG_MMC_RXFIFO);
+			memcpy(buf, &d, i);
+		}
+		data->bytes_xfered += miter.length;
+
+		/* This can go away once MIPS implements flush_kernel_dcache_page */
+		flush_dcache_page(miter.page);
+	}
+	sg_miter_stop(&miter);
+
+	status = readl(host->base + JZ_REG_MMC_STATUS);
+	if (status & JZ_MMC_STATUS_READ_ERROR_MASK) {
+		if (status & JZ_MMC_STATUS_TIMEOUT_READ) {
+			host->req->cmd->error = -ETIMEDOUT;
+			data->error = -ETIMEDOUT;
+		} else {
+			host->req->cmd->error = -EIO;
+			data->error = -EIO;
+		}
+		return;
+	}
+
+	/* For whatever reason there is sometime one word more in the fifo then
+	 * requested */
+	while ((status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) == 0 && --timeout) {
+		d = readl(host->base + JZ_REG_MMC_RXFIFO);
+		status = readl(host->base + JZ_REG_MMC_STATUS);
+	}
+	return;
+
+err_timeout:
+	host->req->cmd->error = -ETIMEDOUT;
+	data->error = -ETIMEDOUT;
+}
+
+static void jz4740_mmc_timeout(unsigned long data)
+{
+	struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data;
+
+	if (!test_and_clear_bit(0, &host->waiting))
+		return;
+
+	jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false);
+
+	host->req->cmd->error = -ETIMEDOUT;
+	jz4740_mmc_request_done(host);
+}
+
+static void jz4740_mmc_read_response(struct jz4740_mmc_host *host,
+	struct mmc_command *cmd)
+{
+	int i;
+	uint16_t tmp;
+
+	if (cmd->flags & MMC_RSP_136) {
+		tmp = readw(host->base + JZ_REG_MMC_RESP_FIFO);
+		for (i = 0; i < 4; ++i) {
+			cmd->resp[i] = tmp << 24;
+			cmd->resp[i] |= readw(host->base + JZ_REG_MMC_RESP_FIFO) << 8;
+			tmp = readw(host->base + JZ_REG_MMC_RESP_FIFO);
+			cmd->resp[i] |= tmp >> 8;
+		}
+	} else {
+		cmd->resp[0] = readw(host->base + JZ_REG_MMC_RESP_FIFO) << 24;
+		cmd->resp[0] |= readw(host->base + JZ_REG_MMC_RESP_FIFO) << 8;
+		cmd->resp[0] |= readw(host->base + JZ_REG_MMC_RESP_FIFO) & 0xff;
+	}
+}
+
+static void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
+	struct mmc_command *cmd)
+{
+	uint32_t cmdat = host->cmdat;
+
+	host->cmdat &= ~JZ_MMC_CMDAT_INIT;
+	jz4740_mmc_clock_disable(host);
+
+	host->cmd = cmd;
+
+	if (cmd->flags & MMC_RSP_BUSY)
+		cmdat |= JZ_MMC_CMDAT_BUSY;
+
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_R1B:
+	case MMC_RSP_R1:
+		cmdat |= JZ_MMC_CMDAT_RSP_R1;
+		break;
+	case MMC_RSP_R2:
+		cmdat |= JZ_MMC_CMDAT_RSP_R2;
+		break;
+	case MMC_RSP_R3:
+		cmdat |= JZ_MMC_CMDAT_RSP_R3;
+		break;
+	default:
+		break;
+	}
+
+	if (cmd->data) {
+		cmdat |= JZ_MMC_CMDAT_DATA_EN;
+		if (cmd->data->flags & MMC_DATA_WRITE)
+			cmdat |= JZ_MMC_CMDAT_WRITE;
+		if (cmd->data->flags & MMC_DATA_STREAM)
+			cmdat |= JZ_MMC_CMDAT_STREAM;
+
+		writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN);
+		writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB);
+	}
+
+	writeb(cmd->opcode, host->base + JZ_REG_MMC_CMD);
+	writel(cmd->arg, host->base + JZ_REG_MMC_ARG);
+	writel(cmdat, host->base + JZ_REG_MMC_CMDAT);
+
+	jz4740_mmc_clock_enable(host, 1);
+}
+
+
+static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
+{
+	struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid;
+	struct mmc_command *cmd = host->req->cmd;
+	struct mmc_request *req = host->req;
+	unsigned int timeout = JZ4740_MMC_MAX_TIMEOUT;
+	uint32_t status;
+
+	if (cmd->error)
+		goto done;
+
+	if (cmd->flags & MMC_RSP_PRESENT)
+		jz4740_mmc_read_response(host, cmd);
+
+	if (cmd->data) {
+		if (cmd->data->flags & MMC_DATA_READ)
+			jz4740_mmc_read_data(host, cmd->data);
+		else
+			jz4740_mmc_write_data(host, cmd->data);
+	}
+
+	if (req->stop) {
+		jz4740_mmc_send_command(host, req->stop);
+		do {
+			status = readw(host->base + JZ_REG_MMC_IREG);
+		} while ((status & JZ_MMC_IRQ_PRG_DONE) == 0 && --timeout);
+		writew(JZ_MMC_IRQ_PRG_DONE, host->base + JZ_REG_MMC_IREG);
+	}
+
+	if (unlikely(timeout == 0))
+		req->stop->error = -ETIMEDOUT;
+
+done:
+	jz4740_mmc_request_done(host);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t jz_mmc_irq(int irq, void *devid)
+{
+	struct jz4740_mmc_host *host = devid;
+	uint16_t irq_reg, status, tmp;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	irq_reg = readw(host->base + JZ_REG_MMC_IREG);
+
+	tmp = irq_reg;
+	irq_reg &= ~host->irq_mask;
+
+	tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ |
+		    JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE);
+
+	if (tmp != irq_reg)
+		writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG);
+
+	if (irq_reg & JZ_MMC_IRQ_SDIO) {
+		writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG);
+		mmc_signal_sdio_irq(host->mmc);
+	}
+
+	if (!host->req || !host->cmd)
+		goto handled;
+
+	if (!(irq_reg & JZ_MMC_IRQ_END_CMD_RES))
+		goto handled;
+
+	if (test_and_clear_bit(0, &host->waiting)) {
+	    del_timer(&host->timeout_timer);
+
+	    status = readl(host->base + JZ_REG_MMC_STATUS);
+
+	    if (status & JZ_MMC_STATUS_TIMEOUT_RES) {
+			host->cmd->error = -ETIMEDOUT;
+		} else if (status & JZ_MMC_STATUS_CRC_RES_ERR) {
+			host->cmd->error = -EIO;
+		} else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
+			    JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
+			host->cmd->data->error = -EIO;
+		} else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
+				JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
+			host->cmd->data->error = -EIO;
+		}
+
+		ret = IRQ_WAKE_THREAD;
+	}
+
+	jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false);
+	writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
+
+handled:
+	return ret;
+}
+
+static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)
+{
+	int div = 0;
+	int real_rate;
+
+	jz4740_mmc_clock_disable(host);
+	clk_set_rate(host->clk, JZ_MMC_CLK_RATE);
+
+	real_rate = clk_get_rate(host->clk);
+
+	while (real_rate > rate && div < 7) {
+		++div;
+		real_rate >>= 1;
+	}
+
+	writew(div, host->base + JZ_REG_MMC_CLKRT);
+	return real_rate;
+}
+
+static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+	struct jz4740_mmc_host *host = mmc_priv(mmc);
+
+	host->req = req;
+
+	writew(0xffff, host->base + JZ_REG_MMC_IREG);
+
+	writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
+	jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true);
+
+	set_bit(0, &host->waiting);
+	mod_timer(&host->timeout_timer, jiffies + 5*HZ);
+	jz4740_mmc_send_command(host, req->cmd);
+}
+
+static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct jz4740_mmc_host *host = mmc_priv(mmc);
+	if (ios->clock)
+		jz4740_mmc_set_clock_rate(host, ios->clock);
+
+	switch (ios->power_mode) {
+	case MMC_POWER_UP:
+		jz4740_mmc_reset(host);
+		if (gpio_is_valid(host->pdata->gpio_power))
+			gpio_set_value(host->pdata->gpio_power,
+					!host->pdata->power_active_low);
+		host->cmdat |= JZ_MMC_CMDAT_INIT;
+		clk_enable(host->clk);
+		break;
+	case MMC_POWER_ON:
+		break;
+	default:
+		if (gpio_is_valid(host->pdata->gpio_power))
+			gpio_set_value(host->pdata->gpio_power,
+					host->pdata->power_active_low);
+		clk_disable(host->clk);
+		break;
+	}
+
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_1:
+		host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
+		break;
+	case MMC_BUS_WIDTH_4:
+		host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
+		break;
+	default:
+		break;
+	}
+}
+
+static int jz4740_mmc_get_ro(struct mmc_host *mmc)
+{
+	struct jz4740_mmc_host *host = mmc_priv(mmc);
+	if (!gpio_is_valid(host->pdata->gpio_read_only))
+		return -ENOSYS;
+
+	return gpio_get_value(host->pdata->gpio_read_only) ^
+		host->pdata->read_only_active_low;
+}
+
+static int jz4740_mmc_get_cd(struct mmc_host *mmc)
+{
+	struct jz4740_mmc_host *host = mmc_priv(mmc);
+	if (!gpio_is_valid(host->pdata->gpio_card_detect))
+		return -ENOSYS;
+
+	return gpio_get_value(host->pdata->gpio_card_detect) ^
+			host->pdata->card_detect_active_low;
+}
+
+static irqreturn_t jz4740_mmc_card_detect_irq(int irq, void *devid)
+{
+	struct jz4740_mmc_host *host = devid;
+
+	mmc_detect_change(host->mmc, HZ / 3);
+
+	return IRQ_HANDLED;
+}
+
+static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct jz4740_mmc_host *host = mmc_priv(mmc);
+	jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable);
+}
+
+static const struct mmc_host_ops jz4740_mmc_ops = {
+	.request	= jz4740_mmc_request,
+	.set_ios	= jz4740_mmc_set_ios,
+	.get_ro		= jz4740_mmc_get_ro,
+	.get_cd		= jz4740_mmc_get_cd,
+	.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
+};
+
+static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
+	JZ_GPIO_BULK_PIN(MSC_CMD),
+	JZ_GPIO_BULK_PIN(MSC_CLK),
+	JZ_GPIO_BULK_PIN(MSC_DATA0),
+	JZ_GPIO_BULK_PIN(MSC_DATA1),
+	JZ_GPIO_BULK_PIN(MSC_DATA2),
+	JZ_GPIO_BULK_PIN(MSC_DATA3),
+};
+
+static int __devinit jz4740_mmc_request_gpios(struct platform_device *pdev)
+{
+	int ret;
+	struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata)
+		return 0;
+
+	if (gpio_is_valid(pdata->gpio_card_detect)) {
+		ret = gpio_request(pdata->gpio_card_detect, "MMC detect change");
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request detect change gpio\n");
+			goto err;
+		}
+		gpio_direction_input(pdata->gpio_card_detect);
+	}
+
+	if (gpio_is_valid(pdata->gpio_read_only)) {
+		ret = gpio_request(pdata->gpio_read_only, "MMC read only");
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request read only gpio: %d\n", ret);
+			goto err_free_gpio_card_detect;
+		}
+		gpio_direction_input(pdata->gpio_read_only);
+	}
+
+	if (gpio_is_valid(pdata->gpio_power)) {
+		ret = gpio_request(pdata->gpio_power, "MMC power");
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request power gpio: %d\n", ret);
+			goto err_free_gpio_read_only;
+		}
+		gpio_direction_output(pdata->gpio_power, pdata->power_active_low);
+	}
+
+	return 0;
+
+err_free_gpio_read_only:
+	if (gpio_is_valid(pdata->gpio_read_only))
+		gpio_free(pdata->gpio_read_only);
+err_free_gpio_card_detect:
+	if (gpio_is_valid(pdata->gpio_card_detect))
+		gpio_free(pdata->gpio_card_detect);
+err:
+	return ret;
+}
+
+static void jz4740_mmc_free_gpios(struct platform_device *pdev)
+{
+	struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata)
+		return;
+
+	if (gpio_is_valid(pdata->gpio_power))
+		gpio_free(pdata->gpio_power);
+	if (gpio_is_valid(pdata->gpio_read_only))
+		gpio_free(pdata->gpio_read_only);
+	if (gpio_is_valid(pdata->gpio_card_detect))
+		gpio_free(pdata->gpio_card_detect);
+}
+
+static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
+{
+	size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
+	if (host->pdata && host->pdata->data_1bit)
+		num_pins -= 3;
+
+	return num_pins;
+}
+
+static int __devinit jz4740_mmc_probe(struct platform_device* pdev)
+{
+	int ret;
+	struct mmc_host *mmc;
+	struct jz4740_mmc_host *host;
+	struct jz4740_mmc_platform_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+
+	mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev);
+	if (!mmc) {
+		dev_err(&pdev->dev, "Failed to alloc mmc host structure\n");
+		return -ENOMEM;
+	}
+
+	host = mmc_priv(mmc);
+	host->pdata = pdata;
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq < 0) {
+		ret = host->irq;
+		dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
+		goto err_free_host;
+	}
+
+	host->clk = clk_get(&pdev->dev, "mmc");
+	if (!host->clk) {
+		ret = -ENOENT;
+		dev_err(&pdev->dev, "Failed to get mmc clock\n");
+		goto err_free_host;
+	}
+
+	host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!host->mem) {
+		ret = -ENOENT;
+		dev_err(&pdev->dev, "Failed to get base platform memory\n");
+		goto err_clk_put;
+	}
+
+	host->mem = request_mem_region(host->mem->start,
+					resource_size(host->mem), pdev->name);
+	if (!host->mem) {
+		ret = -EBUSY;
+		dev_err(&pdev->dev, "Failed to request base memory region\n");
+		goto err_clk_put;
+	}
+
+	host->base = ioremap_nocache(host->mem->start, resource_size(host->mem));
+	if (!host->base) {
+		ret = -EBUSY;
+		dev_err(&pdev->dev, "Failed to ioremap base memory\n");
+		goto err_release_mem_region;
+	}
+
+	ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
+		goto err_iounmap;
+	}
+
+	ret = jz4740_mmc_request_gpios(pdev);
+	if (ret)
+		goto err_gpio_bulk_free;
+
+	mmc->ops = &jz4740_mmc_ops;
+	mmc->f_min = JZ_MMC_CLK_RATE / 128;
+	mmc->f_max = JZ_MMC_CLK_RATE;
+	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA;
+	mmc->caps |= MMC_CAP_SDIO_IRQ;
+
+	mmc->max_blk_size = (1 << 10) - 1;
+	mmc->max_blk_count = (1 << 15) - 1;
+	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+
+	mmc->max_phys_segs = 128;
+	mmc->max_hw_segs = 128;
+	mmc->max_seg_size = mmc->max_req_size;
+
+	host->mmc = mmc;
+	host->pdev = pdev;
+	host->max_clock = JZ_MMC_CLK_RATE;
+	spin_lock_init(&host->lock);
+	host->irq_mask = 0xffff;
+
+	host->card_detect_irq = gpio_to_irq(pdata->gpio_card_detect);
+
+	if (host->card_detect_irq < 0) {
+		dev_warn(&pdev->dev, "Failed to get irq for card detect gpio\n");
+	} else {
+		ret = request_irq(host->card_detect_irq,
+			jz4740_mmc_card_detect_irq,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			"MMC card detect", host);
+
+		if (ret) {
+			dev_err(&pdev->dev, "Failed to request card detect irq");
+			goto err_free_gpios;
+		}
+	}
+
+	ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0,
+			dev_name(&pdev->dev), host);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
+		goto err_free_card_detect_irq;
+	}
+
+	jz4740_mmc_reset(host);
+	jz4740_mmc_clock_disable(host);
+	setup_timer(&host->timeout_timer, jz4740_mmc_timeout,
+			(unsigned long)host);
+	/* It is not that important when it times out, it just needs to timeout. */
+	set_timer_slack(&host->timeout_timer, HZ);
+
+	platform_set_drvdata(pdev, host);
+	ret = mmc_add_host(mmc);
+
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret);
+		goto err_free_irq;
+	}
+	dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n");
+
+	return 0;
+
+err_free_irq:
+	free_irq(host->irq, host);
+err_free_card_detect_irq:
+	if (host->card_detect_irq >= 0)
+		free_irq(host->card_detect_irq, host);
+err_free_gpios:
+	jz4740_mmc_free_gpios(pdev);
+err_gpio_bulk_free:
+	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+err_iounmap:
+	iounmap(host->base);
+err_release_mem_region:
+	release_mem_region(host->mem->start, resource_size(host->mem));
+err_clk_put:
+	clk_put(host->clk);
+err_free_host:
+	platform_set_drvdata(pdev, NULL);
+	mmc_free_host(mmc);
+
+	return ret;
+}
+
+static int __devexit jz4740_mmc_remove(struct platform_device *pdev)
+{
+	struct jz4740_mmc_host *host = platform_get_drvdata(pdev);
+
+	del_timer_sync(&host->timeout_timer);
+	jz4740_mmc_set_irq_enabled(host, 0xff, false);
+	jz4740_mmc_reset(host);
+
+	mmc_remove_host(host->mmc);
+
+	free_irq(host->irq, host);
+	if (host->card_detect_irq >= 0)
+		free_irq(host->card_detect_irq, host);
+
+	jz4740_mmc_free_gpios(pdev);
+	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+
+	iounmap(host->base);
+	release_mem_region(host->mem->start, resource_size(host->mem));
+
+	clk_put(host->clk);
+
+	platform_set_drvdata(pdev, NULL);
+	mmc_free_host(host->mmc);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int jz4740_mmc_suspend(struct device *dev)
+{
+	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
+
+	mmc_suspend_host(host->mmc);
+
+	jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+
+	return 0;
+}
+
+static int jz4740_mmc_resume(struct device *dev)
+{
+	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
+
+	jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
+
+	mmc_resume_host(host->mmc);
+
+	return 0;
+}
+
+const struct dev_pm_ops jz4740_mmc_pm_ops = {
+	.suspend	= jz4740_mmc_suspend,
+	.resume		= jz4740_mmc_resume,
+	.poweroff	= jz4740_mmc_suspend,
+	.restore	= jz4740_mmc_resume,
+};
+
+#define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops)
+#else
+#define JZ4740_MMC_PM_OPS NULL
+#endif
+
+static struct platform_driver jz4740_mmc_driver = {
+	.probe = jz4740_mmc_probe,
+	.remove = __devexit_p(jz4740_mmc_remove),
+	.driver = {
+		.name = "jz4740-mmc",
+		.owner = THIS_MODULE,
+		.pm = JZ4740_MMC_PM_OPS,
+	},
+};
+
+static int __init jz4740_mmc_init(void)
+{
+	return platform_driver_register(&jz4740_mmc_driver);
+}
+module_init(jz4740_mmc_init);
+
+static void __exit jz4740_mmc_exit(void)
+{
+	platform_driver_unregister(&jz4740_mmc_driver);
+}
+module_exit(jz4740_mmc_exit);
+
+MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
diff --git a/include/linux/mmc/jz4740_mmc.h b/include/linux/mmc/jz4740_mmc.h
new file mode 100644
index 0000000..8543f43
--- /dev/null
+++ b/include/linux/mmc/jz4740_mmc.h
@@ -0,0 +1,15 @@
+#ifndef __LINUX_MMC_JZ4740_MMC
+#define __LINUX_MMC_JZ4740_MMC
+
+struct jz4740_mmc_platform_data {
+	int gpio_power;
+	int gpio_card_detect;
+	int gpio_read_only;
+	unsigned card_detect_active_low:1;
+	unsigned read_only_active_low:1;
+	unsigned power_active_low:1;
+
+	unsigned data_1bit:1;
+};
+
+#endif
-- 
1.5.6.5


  parent reply	other threads:[~2010-06-28  1:21 UTC|newest]

Thread overview: 163+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-19  5:08 [PATCH v2 00/26] Add support for the Ingenic JZ4740 System-on-a-Chip Lars-Peter Clausen
2010-06-19  5:08 ` [lm-sensors] [PATCH v2 00/26] Add support for the Ingenic JZ4740 Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 00/26] Add support for the Ingenic JZ4740 System-on-a-Chip Lars-Peter Clausen
2010-06-19  5:08 ` Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 01/26] MIPS: Add base support for " Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 02/26] MIPS: jz4740: Add IRQ handler code Lars-Peter Clausen
2010-07-17 12:08   ` [PATCH v3] " Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 03/26] MIPS: JZ4740: Add clock API support Lars-Peter Clausen
2010-06-28  1:24   ` [PATCH v3 " Lars-Peter Clausen
2010-07-17 12:10     ` [PATCH v4] " Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 04/26] MIPS: JZ4740: Add timer support Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 05/26] MIPS: JZ4740: Add clocksource/clockevent support Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 06/26] MIPS: JZ4740: Add power-management and system reset support Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 07/26] MIPS: JZ4740: Add setup code Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 08/26] MIPS: JZ4740: Add gpio support Lars-Peter Clausen
2010-07-17 12:11   ` [PATCH v3] " Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 09/26] MIPS: JZ4740: Add DMA support Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 10/26] MIPS: JZ4740: Add PWM support Lars-Peter Clausen
2010-06-28  1:23   ` [PATCH v3 " Lars-Peter Clausen
2010-07-17 12:12     ` [PATCH v4] " Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 11/26] MIPS: JZ4740: Add serial support Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 12/26] MIPS: JZ4740: Add prom support Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 13/26] MIPS: JZ4740: Add platform devices Lars-Peter Clausen
2010-07-17 12:13   ` [PATCH v3] " Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 14/26] MIPS: JZ4740: Add Kbuild files Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 15/26] RTC: Add JZ4740 RTC driver Lars-Peter Clausen
2010-06-19 10:43   ` Marek Vasut
2010-06-19 13:05     ` Lars-Peter Clausen
2010-06-19 13:37       ` Wan ZongShun
2010-06-19 13:53         ` Lars-Peter Clausen
2010-06-19 14:36           ` Wan ZongShun
2010-06-19 14:04       ` Marek Vasut
2010-06-19 17:42         ` Lars-Peter Clausen
2010-06-19 17:53           ` Geert Uytterhoeven
2010-06-19 19:29   ` [PATCH v3] " Lars-Peter Clausen
2010-06-20  1:13     ` [rtc-linux] " Wan ZongShun
2010-06-20  1:23       ` Lars-Peter Clausen
2010-06-20  1:30         ` Wan ZongShun
2010-06-22  5:53     ` Alessandro Zummo
2010-06-19  5:08 ` [PATCH v2 16/26] fbdev: Add JZ4740 framebuffer driver Lars-Peter Clausen
2010-06-19  5:08   ` Lars-Peter Clausen
2010-07-04 22:27   ` Lars-Peter Clausen
2010-07-04 22:27     ` Lars-Peter Clausen
2010-07-07 23:41     ` Andrew Morton
2010-07-07 23:41       ` Andrew Morton
2010-07-08 13:28       ` Lars-Peter Clausen
2010-07-08 13:28         ` Lars-Peter Clausen
2010-07-08 16:46         ` Andrew Morton
2010-07-08 16:46           ` Andrew Morton
2010-07-09  1:26     ` Jaya Kumar
2010-07-09  1:26       ` Jaya Kumar
2010-07-09 15:31       ` Lars-Peter Clausen
2010-07-09 15:31         ` Lars-Peter Clausen
2010-07-17 12:14   ` [PATCH v3] " Lars-Peter Clausen
2010-07-17 12:14     ` Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 17/26] MTD: Nand: Add JZ4740 NAND driver Lars-Peter Clausen
2010-06-19  5:08   ` Lars-Peter Clausen
2010-07-04 22:35   ` [PATCH v2 17/26] MTD: Nand: Add JZ4740 NAND Lars-Peter Clausen
2010-07-08  6:06   ` [PATCH v2 17/26] MTD: Nand: Add JZ4740 NAND driver Artem Bityutskiy
2010-07-08  6:06     ` Artem Bityutskiy
2010-07-08 13:20     ` Lars-Peter Clausen
2010-07-08 13:20       ` Lars-Peter Clausen
2010-07-08 13:19       ` Artem Bityutskiy
2010-07-08 13:19         ` Artem Bityutskiy
2010-07-08 14:02         ` Lars-Peter Clausen
2010-07-08 14:02           ` Lars-Peter Clausen
2010-07-08 14:14           ` Artem Bityutskiy
2010-07-08 14:14             ` Artem Bityutskiy
2010-07-17 12:15   ` [PATCH v3] " Lars-Peter Clausen
2010-07-17 12:15     ` Lars-Peter Clausen
2010-07-18 16:54     ` Artem Bityutskiy
2010-07-18 16:54       ` Artem Bityutskiy
2010-07-18 17:02       ` Lars-Peter Clausen
2010-07-18 17:02         ` Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 18/26] MMC: Add JZ4740 mmc driver Lars-Peter Clausen
2010-06-19 14:46   ` Matt Fleming
2010-06-19 14:46     ` Matt Fleming
2010-06-19 14:46     ` Matt Fleming
2010-06-19 15:29     ` Lars-Peter Clausen
2010-06-28  1:20   ` Lars-Peter Clausen [this message]
2010-06-29 20:17     ` [PATCH v3] " Matt Fleming
2010-06-29 20:17       ` Matt Fleming
2010-06-29 20:17       ` Matt Fleming
2010-07-01 15:47       ` Lars-Peter Clausen
2010-06-30 20:55     ` Andrew Morton
2010-07-01 15:45       ` Lars-Peter Clausen
2010-07-12 21:33     ` [PATCH v4] " Lars-Peter Clausen
2010-07-12 21:41       ` Randy Dunlap
2010-07-12 22:07         ` Lars-Peter Clausen
2010-07-12 22:20       ` [PATCH v5] " Lars-Peter Clausen
2010-07-12 22:45         ` Joe Perches
2010-07-12 23:45           ` Lars-Peter Clausen
2010-07-15 21:06         ` [PATCH v6] " Lars-Peter Clausen
2010-07-15 21:16           ` Andrew Morton
2010-07-15 21:37             ` Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 19/26] USB: Add JZ4740 ohci support Lars-Peter Clausen
2010-06-19 17:17   ` Greg KH
2010-06-19  5:08 ` [PATCH v2 20/26] alsa: ASoC: Add JZ4740 codec driver Lars-Peter Clausen
2010-06-19  5:08   ` Lars-Peter Clausen
2010-06-19 14:49   ` [PATCH v3] " Lars-Peter Clausen
2010-06-19 14:49     ` Lars-Peter Clausen
2010-06-20 13:11     ` Mark Brown
2010-06-20 13:11       ` Mark Brown
2010-06-21 22:46     ` [PATCH v4] " Lars-Peter Clausen
2010-06-21 22:46       ` Lars-Peter Clausen
2010-06-22 10:12       ` Liam Girdwood
2010-06-22 10:12         ` Liam Girdwood
2010-06-22 23:12       ` Mark Brown
2010-06-22 23:12         ` Mark Brown
2010-06-19  5:08 ` [PATCH v2 21/26] alsa: ASoC: Add JZ4740 ASoC support Lars-Peter Clausen
2010-06-19  5:08   ` Lars-Peter Clausen
2010-06-19 14:50   ` [PATCH v3] " Lars-Peter Clausen
2010-06-19 14:50     ` Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 22/26] MFD: Add JZ4740 ADC driver Lars-Peter Clausen
2010-07-04 22:47   ` Lars-Peter Clausen
2010-07-05 14:53   ` Samuel Ortiz
2010-07-05 15:43     ` Lars-Peter Clausen
2010-07-05 15:53       ` Samuel Ortiz
2010-07-12  1:48   ` [PATCH v3] " Lars-Peter Clausen
2010-07-14  9:19     ` Samuel Ortiz
2010-06-19  5:08 ` [PATCH v2 23/26] hwmon: " Lars-Peter Clausen
2010-06-19  5:08   ` [lm-sensors] " Lars-Peter Clausen
2010-06-19  8:36   ` Jean Delvare
2010-06-19  8:36     ` Jean Delvare
2010-06-19  8:36     ` Jean Delvare
2010-06-19 12:58     ` Lars-Peter Clausen
2010-06-19 12:58       ` Lars-Peter Clausen
2010-06-19 14:47   ` [PATCH v3] " Lars-Peter Clausen
2010-06-19 14:47     ` [lm-sensors] " Lars-Peter Clausen
2010-06-19 16:24     ` Jean Delvare
2010-06-19 16:24       ` Jean Delvare
2010-06-19 17:59       ` Lars-Peter Clausen
2010-06-19 17:59         ` Lars-Peter Clausen
2010-06-19 19:32     ` [PATCH v4] " Lars-Peter Clausen
2010-06-19 19:32       ` [lm-sensors] " Lars-Peter Clausen
2010-06-20  6:32       ` Jean Delvare
2010-06-20  6:32         ` Jean Delvare
2010-06-20  6:32         ` Jean Delvare
2010-06-19  5:08 ` [PATCH v2 24/26] power: Add JZ4740 battery driver Lars-Peter Clausen
2010-06-27  1:58   ` Lars-Peter Clausen
2010-06-28 11:43     ` Anton Vorontsov
2010-06-19  5:08 ` [PATCH v2 25/26] MIPS: JZ4740: Add qi_lb60 board support Lars-Peter Clausen
2010-07-17 12:16   ` [PATCH v3] " Lars-Peter Clausen
2010-06-19  5:08 ` [PATCH v2 26/26] alsa: ASoC: JZ4740: Add qi_lb60 board driver Lars-Peter Clausen
2010-06-19  5:08   ` Lars-Peter Clausen
2010-06-19 14:52   ` [PATCH v3] " Lars-Peter Clausen
2010-06-19 14:52     ` Lars-Peter Clausen
2010-06-20  9:26 ` [PATCH v2 00/26] Add support for the Ingenic JZ4740 System-on-a-Chip Thomas Bogendoerfer
2010-06-20  9:26   ` [lm-sensors] [PATCH v2 00/26] Add support for the Ingenic Thomas Bogendoerfer
2010-06-20  9:26   ` [PATCH v2 00/26] Add support for the Ingenic JZ4740 System-on-a-Chip Thomas Bogendoerfer
2010-06-20  9:26   ` Thomas Bogendoerfer
2010-06-20  9:26   ` [PATCH v2 00/26] Add support for the Ingenic JZ4740 Thomas Bogendoerfer
2010-06-20 14:31   ` [PATCH v2 00/26] Add support for the Ingenic JZ4740 System-on-a-Chip Lars-Peter Clausen
2010-06-20 14:31     ` Lars-Peter Clausen
2010-06-20 16:34     ` Thomas Bogendoerfer
2010-06-20 16:49       ` Lars-Peter Clausen
2010-06-20 17:01         ` Thomas Bogendoerfer
2010-06-20 17:57           ` Florian Fainelli
2010-06-20 18:30             ` Lars-Peter Clausen
2010-06-21  2:56   ` Xiangfu Liu
2010-06-21  2:56     ` [lm-sensors] [PATCH v2 00/26] Add support for the Ingenic Xiangfu Liu
2010-06-21  2:56     ` [PATCH v2 00/26] Add support for the Ingenic JZ4740 System-on-a-Chip Xiangfu Liu
2010-06-21  2:56     ` Xiangfu Liu

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=1277688041-23522-1-git-send-email-lars@metafoo.de \
    --to=lars@metafoo.de \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mips@linux-mips.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=matt@console-pimps.org \
    --cc=ralf@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.