Re: [PATCH 1/32] mmc: add 'enable' and 'disable' methods to mmc host

2009-07-10 Thread Adrian Hunter

Madhusudhan wrote:

The patch numbers 7 and 28 in the series seems to be missing?


I can see them in mailing list archives - lkml.org or gmane.org

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1:2] [MTD][NAND]omap: Adding support for nand prefetch-read and post-write, in MPU mode.

2009-07-10 Thread David Brownell
On Friday 10 July 2009, vimal singh wrote:
> +static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
> +{
> +   struct nand_chip *nand = mtd->priv;
> +   u_char *p = (u_char *)buf;
> +
> +   while (len--)
> +   *p++ = __raw_readb(nand->IO_ADDR_R);
> +}

Better as __raw_readsb() yes?  Or maybe ioread8_rep().

... speaking of which, maybe the MTD layer can finally
default to using the accelerated block PIO calls, now
that ioreadX_rep() is supposed to work on all arches...

Last time I measured, that change alone was worth
something like a 10% speedup.  Maybe more.
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 1/32] mmc: add 'enable' and 'disable' methods to mmc host

2009-07-10 Thread Madhusudhan
Hi Adrian,

The patch numbers 7 and 28 in the series seems to be missing?

Regards,
Madhu

> -Original Message-
> From: linux-omap-ow...@vger.kernel.org [mailto:linux-omap-
> ow...@vger.kernel.org] On Behalf Of Adrian Hunter
> Sent: Friday, July 10, 2009 7:40 AM
> To: Pierre Ossman
> Cc: Jarkko Lavinen; Denis Karpov; Adrian Hunter; linux-omap Mailing List;
> lkml
> Subject: [PATCH 1/32] mmc: add 'enable' and 'disable' methods to mmc host
> 
> From a0164897276e4d1f972fd90b1e9499e1ab8d221e Mon Sep 17 00:00:00 2001
> From: Adrian Hunter 
> Date: Wed, 22 Apr 2009 12:50:45 +0300
> Subject: [PATCH] mmc: add 'enable' and 'disable' methods to mmc host
> 
> MMC hosts that support power saving can use the 'enable' and
> 'disable' methods to exit and enter power saving states.
> An explanation of their use is provided in the comments
> added to include/linux/mmc/host.h.
> 
> Signed-off-by: Adrian Hunter 
> ---
>  drivers/mmc/core/core.c  |  174
> --
>  drivers/mmc/core/host.c  |1 +
>  drivers/mmc/core/host.h  |2 +
>  include/linux/mmc/host.h |   47 
>  4 files changed, 218 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index d84c880..41fd127 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -344,6 +344,98 @@ unsigned int mmc_align_data_size(struct mmc_card
> *card, unsigned int sz)
>  EXPORT_SYMBOL(mmc_align_data_size);
> 
>  /**
> + *   mmc_host_enable - enable a host.
> + *   @host: mmc host to enable
> + *
> + *   Hosts that support power saving can use the 'enable' and 'disable'
> + *   methods to exit and enter power saving states. For more information
> + *   see comments for struct mmc_host_ops.
> + */
> +int mmc_host_enable(struct mmc_host *host)
> +{
> + if (!(host->caps & MMC_CAP_DISABLE))
> + return 0;
> +
> + if (host->en_dis_recurs)
> + return 0;
> +
> + if (host->nesting_cnt++)
> + return 0;
> +
> + cancel_delayed_work_sync(&host->disable);
> +
> + if (host->enabled)
> + return 0;
> +
> + if (host->ops->enable) {
> + int err;
> +
> + host->en_dis_recurs = 1;
> + err = host->ops->enable(host);
> + host->en_dis_recurs = 0;
> +
> + if (err) {
> + pr_debug("%s: enable error %d\n",
> +  mmc_hostname(host), err);
> + return err;
> + }
> + }
> + host->enabled = 1;
> + return 0;
> +}
> +EXPORT_SYMBOL(mmc_host_enable);
> +
> +static int mmc_host_do_disable(struct mmc_host *host, int lazy)
> +{
> + if (host->ops->disable) {
> + int err;
> +
> + host->en_dis_recurs = 1;
> + err = host->ops->disable(host, lazy);
> + host->en_dis_recurs = 0;
> +
> + if (err < 0) {
> + pr_debug("%s: disable error %d\n",
> +  mmc_hostname(host), err);
> + return err;
> + }
> + if (err > 0)
> + mmc_schedule_delayed_work(&host->disable, err);
> + }
> + host->enabled = 0;
> + return 0;
> +}
> +
> +/**
> + *   mmc_host_disable - disable a host.
> + *   @host: mmc host to disable
> + *
> + *   Hosts that support power saving can use the 'enable' and 'disable'
> + *   methods to exit and enter power saving states. For more information
> + *   see comments for struct mmc_host_ops.
> + */
> +int mmc_host_disable(struct mmc_host *host)
> +{
> + int err;
> +
> + if (!(host->caps & MMC_CAP_DISABLE))
> + return 0;
> +
> + if (host->en_dis_recurs)
> + return 0;
> +
> + if (--host->nesting_cnt)
> + return 0;
> +
> + if (!host->enabled)
> + return 0;
> +
> + err = mmc_host_do_disable(host, 0);
> + return err;
> +}
> +EXPORT_SYMBOL(mmc_host_disable);
> +
> +/**
>   *   __mmc_claim_host - exclusively claim a host
>   *   @host: mmc host to claim
>   *   @abort: whether or not the operation should be aborted
> @@ -379,11 +471,81 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t
> *abort)
>   wake_up(&host->wq);
>   spin_unlock_irqrestore(&host->lock, flags);
>   remove_wait_queue(&host->wq, &wait);
> + if (!stop)
> + mmc_host_enable(host);
>   return stop;
>  }
> 
>  EXPORT_SYMBOL(__mmc_claim_host);
> 
> +static int mmc_try_claim_host(struct mmc_host *host)
> +{
> + int claimed_host = 0;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&host->lock, flags);
> + if (!host->claimed) {
> + host->claimed = 1;
> + claimed_host = 1;
> + }
> + spin_unlock_irqrestore(&host->lock, flags);
> + return claimed_host;
> +}
> +
> +static void mmc_do_release_host(struct mmc_host *host)
> +{
> + unsigned long flags;
> +
> + spin_lock_irq

[PATCH] ehci: update driver with generic change

2009-07-10 Thread Ajay Kumar Gupta
Update the OMAP EHCI driver in accordance with below patch
introduced in generic EHCI driver.

commit: b18ffd49e86102a9ed0a1cc83fdafe3891e844e5
USB: EHCI: update toggle state for linked QHs

Signed-off-by: Ajay Kumar Gupta 
---
 drivers/usb/host/ehci-omap.c |1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index c0f9a19..858bf11 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -762,6 +762,7 @@ static const struct hc_driver ehci_omap_hc_driver = {
.urb_enqueue= ehci_urb_enqueue,
.urb_dequeue= ehci_urb_dequeue,
.endpoint_disable   = ehci_endpoint_disable,
+   .endpoint_reset = ehci_endpoint_reset,
 
/*
 * scheduling support
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH-v2 2:2][MTD][NAND]omap : Adding DMA mode support in nand prefetch/post-write

2009-07-10 Thread vimal singh
This patch also got updated due to changes in 1st patch.
Also made 'len/64' to 'len >> 6', as per Artem's comment.

-vimal

This patch adds DMA mode support for nand prefetch/post-write engine.

Signed-off-by: Vimal Singh 
---

 drivers/mtd/nand/Kconfig |9 ++
 drivers/mtd/nand/omap2.c |  186 ++-
 2 files changed, 193 insertions(+), 2 deletions(-)

Index: mtd-2.6/drivers/mtd/nand/Kconfig
===
--- mtd-2.6.orig/drivers/mtd/nand/Kconfig
+++ mtd-2.6/drivers/mtd/nand/Kconfig
@@ -88,6 +88,15 @@ config MTD_NAND_OMAP_PREFETCH
 The NAND device can be accessed for Read/Write using GPMC PREFETCH 
engine
 to improve the performance.

+config MTD_NAND_OMAP_PREFETCH_DMA
+   depends on MTD_NAND_OMAP_PREFETCH
+   bool "DMA mode"
+   default n
+   help
+The GPMC PREFETCH engine can be configured eigther in MPU interrupt 
mode
+or in DMA interrupt mode.
+Say y for DMA mode or MPU mode will be used
+
 config MTD_NAND_TS7250
tristate "NAND Flash device on TS-7250 board"
depends on MACH_TS72XX
Index: mtd-2.6/drivers/mtd/nand/omap2.c
===
--- mtd-2.6.orig/drivers/mtd/nand/omap2.c
+++ mtd-2.6/drivers/mtd/nand/omap2.c
@@ -18,8 +18,7 @@
 #include 
 #include 

-#include 
-
+#include 
 #include 
 #include 

@@ -118,8 +117,19 @@ static int use_prefetch = 1;
 /* "modprobe ... use_prefetch=0" etc */
 module_param(use_prefetch, bool, 0);
 MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH");
+
+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
+static int use_dma = 1;
+
+/* "modprobe ... use_dma=0" etc */
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
+#else
+const int use_dma;
+#endif
 #else
 const int use_prefetch;
+const int use_dma;
 #endif

 struct omap_nand_info {
@@ -135,6 +145,8 @@ struct omap_nand_info {
void __iomem*gpmc_cs_baseaddr;
void __iomem*gpmc_baseaddr;
void __iomem*nand_pref_fifo_add;
+   struct completion   comp;
+   int dma_ch;
 };

 /**
@@ -357,6 +369,147 @@ static void omap_write_buf_pref(struct m
}
 }

+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
+/*
+ * omap_nand_dma_cb: callback on the completion of dma transfer
+ * @lch: logical channel
+ * @ch_satuts: channel status
+ * @data: pointer to completion data structure
+ */
+static void omap_nand_dma_cb(int lch, u16 ch_status, void *data)
+{
+   complete((struct completion *) data);
+}
+
+/*
+ * omap_nand_dma_transfer: configure and start dma transfer
+ * @mtd: MTD device structure
+ * @addr: virtual address in RAM of source/destination
+ * @len: number of data bytes to be transferred
+ * @is_write: flag for read/write operation
+ */
+static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+   unsigned int len, int is_write)
+{
+   struct omap_nand_info *info = container_of(mtd,
+   struct omap_nand_info, mtd);
+   uint32_t prefetch_status = 0;
+   enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
+   DMA_FROM_DEVICE;
+   dma_addr_t dma_addr;
+   int ret;
+
+   /* The fifo depth is 64 bytes. We have a sync at each frame and frame
+* length is 64 bytes.
+*/
+   int buf_len = len >> 6;
+
+   if (addr >= high_memory) {
+   struct page *p1;
+
+   if (((size_t)addr & PAGE_MASK) !=
+   ((size_t)(addr + len - 1) & PAGE_MASK))
+   goto out_copy;
+   p1 = vmalloc_to_page(addr);
+   if (!p1)
+   goto out_copy;
+   addr = page_address(p1) + ((size_t)addr & ~PAGE_MASK);
+   }
+
+   dma_addr = dma_map_single(&info->pdev->dev, addr, len, dir);
+   if (dma_mapping_error(&info->pdev->dev, dma_addr)) {
+   dev_err(&info->pdev->dev,
+   "Couldn't DMA map a %d byte buffer\n", len);
+   goto out_copy;
+   }
+
+   if (is_write) {
+   omap_set_dma_dest_params(info->dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
+   info->phys_base, 0, 0);
+   omap_set_dma_src_params(info->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
+   dma_addr, 0, 0);
+   omap_set_dma_transfer_params(info->dma_ch, OMAP_DMA_DATA_TYPE_S32,
+   0x10, buf_len, OMAP_DMA_SYNC_FRAME,
+   OMAP24XX_DMA_GPMC, OMAP_DMA_DST_SYNC);
+   } else {
+   omap_set_dma_src_params(info->dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
+  

[PATCH-v2 1:2] [MTD][NAND]omap: Adding support for nand prefetch-read and post-write, in MPU mode.

2009-07-10 Thread vimal singh
Please ignore previous patch, it had some problem.
Fixing and re-submitting the patch this time.

-vimal

This patch adds prefetch support to access nand flash in mpu mode.
This patch also adds 8-bit nand support (omap_read/write_buf8).
Prefetch can be used for both 8- and 16-bit devices.

Signed-off-by: Vimal Singh 
---

 arch/arm/mach-omap2/gpmc.c |   63 -
 arch/arm/plat-omap/include/mach/gpmc.h |4
 drivers/mtd/nand/Kconfig   |8 +
 drivers/mtd/nand/omap2.c   |  159 +++--
 4 files changed, 226 insertions(+), 8 deletions(-)

Index: mtd-2.6/arch/arm/mach-omap2/gpmc.c
===
--- mtd-2.6.orig/arch/arm/mach-omap2/gpmc.c
+++ mtd-2.6/arch/arm/mach-omap2/gpmc.c
@@ -57,6 +57,11 @@
 #define GPMC_CHUNK_SHIFT   24  /* 16 MB */
 #define GPMC_SECTION_SHIFT 28  /* 128 MB */

+#define PREFETCH_FIFOTHRESHOLD (0x40 << 8)
+#define CS_NUM_SHIFT   24
+#define ENABLE_PREFETCH(0x1 << 7)
+#define DMA_MPU_MODE   2
+
 static struct resource gpmc_mem_root;
 static struct resource gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -386,6 +391,63 @@ void gpmc_cs_free(int cs)
 }
 EXPORT_SYMBOL(gpmc_cs_free);

+/**
+ * gpmc_prefetch_enable - configures and starts prefetch transfer
+ * @cs: nand cs (chip select) number
+ * @dma_mode: dma mode enable (1) or disable (0)
+ * @u32_count: number of bytes to be transferred
+ * @is_write: prefetch read(0) or write post(1) mode
+ */
+int gpmc_prefetch_enable(int cs, int dma_mode,
+   unsigned int u32_count, int is_write)
+{
+   uint32_t prefetch_config1;
+
+   if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
+   /* Set the amount of bytes to be prefetched */
+   gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
+
+   /* Set dma/mpu mode, the prefetch read / post write and
+* enable the engine. Set which cs is has requested for.
+*/
+   prefetch_config1 = ((cs << CS_NUM_SHIFT) |
+   PREFETCH_FIFOTHRESHOLD |
+   ENABLE_PREFETCH |
+   (dma_mode << DMA_MPU_MODE) |
+   (0x1 & is_write));
+   gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1);
+   } else {
+   return -EBUSY;
+   }
+   /*  Start the prefetch engine */
+   gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1);
+
+   return 0;
+}
+EXPORT_SYMBOL(gpmc_prefetch_enable);
+
+/**
+ * gpmc_prefetch_reset - disables and stops the prefetch engine
+ */
+void gpmc_prefetch_reset(void)
+{
+   /* Stop the PFPW engine */
+   gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
+
+   /* Reset/disable the PFPW engine */
+   gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
+}
+EXPORT_SYMBOL(gpmc_prefetch_reset);
+
+/**
+ * gpmc_prefetch_status - reads prefetch status of engine
+ */
+int  gpmc_prefetch_status(void)
+{
+   return gpmc_read_reg(GPMC_PREFETCH_STATUS);
+}
+EXPORT_SYMBOL(gpmc_prefetch_status);
+
 static void __init gpmc_mem_init(void)
 {
int cs;
@@ -452,6 +514,5 @@ void __init gpmc_init(void)
l &= 0x03 << 3;
l |= (0x02 << 3) | (1 << 0);
gpmc_write_reg(GPMC_SYSCONFIG, l);
-
gpmc_mem_init();
 }
Index: mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h
===
--- mtd-2.6.orig/arch/arm/plat-omap/include/mach/gpmc.h
+++ mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h
@@ -103,6 +103,10 @@ extern int gpmc_cs_request(int cs, unsig
 extern void gpmc_cs_free(int cs);
 extern int gpmc_cs_set_reserved(int cs, int reserved);
 extern int gpmc_cs_reserved(int cs);
+extern int gpmc_prefetch_enable(int cs, int dma_mode,
+   unsigned int u32_count, int is_write);
+extern void gpmc_prefetch_reset(void);
+extern int gpmc_prefetch_status(void);
 extern void __init gpmc_init(void);

 #endif
Index: mtd-2.6/drivers/mtd/nand/Kconfig
===
--- mtd-2.6.orig/drivers/mtd/nand/Kconfig
+++ mtd-2.6/drivers/mtd/nand/Kconfig
@@ -80,6 +80,14 @@ config MTD_NAND_OMAP2
help
   Support for NAND flash on Texas Instruments OMAP2 and OMAP3 
platforms.

+config MTD_NAND_OMAP_PREFETCH
+   bool "GPMC prefetch support for NAND Flash device"
+   depends on MTD_NAND && MTD_NAND_OMAP2
+   default y
+   help
+The NAND device can be accessed for Read/Write using GPMC PREFETCH 
engine
+to improve the performance.
+
 config MTD_NAND_TS7250
tristate "NAND Flash device on TS-7250 board"
depends on MACH_TS72XX
Index: mtd-2.6/drivers/mtd/nand/omap2.c
===
--- mtd-2

Re: [PATCH 2:2][MTD][NAND]omap : Adding DMA mode support in nand prefetch/post-write

2009-07-10 Thread Artem Bityutskiy

David Woodhouse wrote:

On Fri, 2009-07-10 at 15:02 +0300, Artem Bityutskiy wrote:

On Fri, 2009-07-10 at 17:25 +0530, vimal singh wrote:

+   /* The fifo depth is 64 bytes. We have a sync at each frame and frame
+* length is 64 bytes.
+*/
+   int buf_len = len/64;

To optimize performance it is better not to rely on gcc and use <<


If you ever see gcc screwing up division of an 'int' by a constant 64,
file a GCC bug.


I did see gcc generated division instruction instead of shift
instruction on x86 when the kernel is compiles with size optimization.
I think this is because it division instruction is shorter.

The exact place I we saw was the UBIFS binary search function, and
division by 2 was not compiled into a shift instruction.

So what I suggested is to use shift explicitly if this is wanted.

--
Best Regards,
Artem Bityutskiy (Артём Битюцкий)
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 31/32] omap_hsmmc: set a large data timeout for commands with busy signal

2009-07-10 Thread Adrian Hunter
>From 54996066acb35e82f89715c6c59b28bc81e12239 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Fri, 26 Jun 2009 11:29:20 +0300
Subject: [PATCH] omap_hsmmc: set a large data timeout for commands with busy 
signal

Commands like SWITCH (CMD6) send a response and then signal busy
while the operation is completed.  These commands are expected
to always succeed (otherwise the response would have indicated an
error).

Set an arbitrarily large data timeout value (100ms) for these commands
to ensure that premature timeouts do not occur.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   15 +++
 1 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 427bd49..ae8d33b 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -982,7 +982,8 @@ static int omap_hsmmc_start_dma_transfer(struct 
omap_hsmmc_host *host,
 }
 
 static void set_data_timeout(struct omap_hsmmc_host *host,
-struct mmc_request *req)
+unsigned int timeout_ns,
+unsigned int timeout_clks)
 {
unsigned int timeout, cycle_ns;
uint32_t reg, clkd, dto = 0;
@@ -993,8 +994,8 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
clkd = 1;
 
cycle_ns = 10 / (clk_get_rate(host->fclk) / clkd);
-   timeout = req->data->timeout_ns / cycle_ns;
-   timeout += req->data->timeout_clks;
+   timeout = timeout_ns / cycle_ns;
+   timeout += timeout_clks;
if (timeout) {
while ((timeout & 0x8000) == 0) {
dto += 1;
@@ -1028,12 +1029,18 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, 
struct mmc_request *req)
 
if (req->data == NULL) {
OMAP_HSMMC_WRITE(host->base, BLK, 0);
+   /*
+* Set an arbitrary 100ms data timeout for commands with
+* busy signal.
+*/
+   if (req->cmd->flags & MMC_RSP_BUSY)
+   set_data_timeout(host, 1U, 0);
return 0;
}
 
OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
| (req->data->blocks << 16));
-   set_data_timeout(host, req);
+   set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks);
 
if (host->use_dma) {
ret = omap_hsmmc_start_dma_transfer(host, req);
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2:2][MTD][NAND]omap : Adding DMA mode support in nand prefetch/post-write

2009-07-10 Thread David Woodhouse
On Fri, 2009-07-10 at 15:02 +0300, Artem Bityutskiy wrote:
> On Fri, 2009-07-10 at 17:25 +0530, vimal singh wrote:
> > +   /* The fifo depth is 64 bytes. We have a sync at each frame and frame
> > +* length is 64 bytes.
> > +*/
> > +   int buf_len = len/64;
> 
> To optimize performance it is better not to rely on gcc and use <<

If you ever see gcc screwing up division of an 'int' by a constant 64,
file a GCC bug.

-- 
David WoodhouseOpen Source Technology Centre
david.woodho...@intel.com  Intel Corporation

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 32/32] ARM: OMAP: RX51: set MMC capabilities and power-saving flag

2009-07-10 Thread Adrian Hunter
>From 3865867159f25cf706480236f6d4f0e4adde5dac Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Fri, 10 Jul 2009 10:32:44 +0300
Subject: [PATCH] ARM: OMAP: RX51: set MMC capabilities and power-saving flag

Specify MMC capabilities and set the power-saving flag
for RX51.

Signed-off-by: Adrian Hunter 
---
 arch/arm/mach-omap2/board-rx51-peripherals.c |5 +
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c 
b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 9a0bf67..5cc815b 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -102,6 +103,8 @@ static struct twl4030_hsmmc_info mmc[] = {
.cover_only = true,
.gpio_cd= 160,
.gpio_wp= -EINVAL,
+   .power_saving   = true,
+   .caps   = MMC_CAP_SD_ONLY,
},
{
.name   = "internal",
@@ -109,6 +112,8 @@ static struct twl4030_hsmmc_info mmc[] = {
.wires  = 8,
.gpio_cd= -EINVAL,
.gpio_wp= -EINVAL,
+   .power_saving   = true,
+   .caps   = MMC_CAP_MMC_ONLY | MMC_CAP_NONREMOVABLE,
},
{}  /* Terminator */
 };
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 28/32] omap_hsmmc: code refactoring

2009-07-10 Thread Adrian Hunter
>From 10908c5264a19de415af6406ee19ef2bd68928c6 Mon Sep 17 00:00:00 2001
From: Denis Karpov 
Date: Mon, 18 May 2009 13:29:18 +0300
Subject: [PATCH] omap_hsmmc: code refactoring

Functions', structures', variables' names are changed to start
with omap_hsmmc_ prefix.

Signed-off-by: Denis Karpov 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |  322 +
 1 files changed, 162 insertions(+), 160 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index fa5f401..5055d52 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -133,7 +133,7 @@
 #define OMAP_HSMMC_WRITE(base, reg, val) \
__raw_writel((val), (base) + OMAP_HSMMC_##reg)
 
-struct mmc_omap_host {
+struct omap_hsmmc_host {
struct  device  *dev;
struct  mmc_host*mmc;
struct  mmc_request *mrq;
@@ -170,7 +170,7 @@ struct mmc_omap_host {
 /*
  * Stop clock to the card
  */
-static void omap_mmc_stop_clock(struct mmc_omap_host *host)
+static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
 {
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
@@ -184,7 +184,7 @@ static void omap_mmc_stop_clock(struct mmc_omap_host *host)
  * Restore the MMC host context, if it was lost as result of a
  * power state change.
  */
-static int omap_mmc_restore_ctx(struct mmc_omap_host *host)
+static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
 {
struct mmc_ios *ios = &host->mmc->ios;
struct omap_mmc_platform_data *pdata = host->pdata;
@@ -312,7 +312,7 @@ out:
 /*
  * Save the MMC host context (store the number of power state changes so far).
  */
-static void omap_mmc_save_ctx(struct mmc_omap_host *host)
+static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
 {
struct omap_mmc_platform_data *pdata = host->pdata;
int context_loss;
@@ -327,12 +327,12 @@ static void omap_mmc_save_ctx(struct mmc_omap_host *host)
 
 #else
 
-static int omap_mmc_restore_ctx(struct mmc_omap_host *host)
+static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
 {
return 0;
 }
 
-static void omap_mmc_save_ctx(struct mmc_omap_host *host)
+static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
 {
 }
 
@@ -342,7 +342,7 @@ static void omap_mmc_save_ctx(struct mmc_omap_host *host)
  * Send init stream sequence to card
  * before sending IDLE command
  */
-static void send_init_stream(struct mmc_omap_host *host)
+static void send_init_stream(struct omap_hsmmc_host *host)
 {
int reg = 0;
unsigned long timeout;
@@ -366,7 +366,7 @@ static void send_init_stream(struct mmc_omap_host *host)
 }
 
 static inline
-int mmc_omap_cover_is_closed(struct mmc_omap_host *host)
+int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
 {
int r = 1;
 
@@ -376,35 +376,35 @@ int mmc_omap_cover_is_closed(struct mmc_omap_host *host)
 }
 
 static ssize_t
-mmc_omap_show_cover_switch(struct device *dev, struct device_attribute *attr,
+omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr,
   char *buf)
 {
struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
-   struct mmc_omap_host *host = mmc_priv(mmc);
+   struct omap_hsmmc_host *host = mmc_priv(mmc);
 
-   return sprintf(buf, "%s\n", mmc_omap_cover_is_closed(host) ? "closed" :
-  "open");
+   return sprintf(buf, "%s\n",
+   omap_hsmmc_cover_is_closed(host) ? "closed" : "open");
 }
 
-static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
+static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL);
 
 static ssize_t
-mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr,
+omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
char *buf)
 {
struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
-   struct mmc_omap_host *host = mmc_priv(mmc);
+   struct omap_hsmmc_host *host = mmc_priv(mmc);
 
return sprintf(buf, "%s\n", mmc_slot(host).name);
 }
 
-static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL);
+static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL);
 
 /*
  * Configure the response type and send the cmd.
  */
 static void
-mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd,
+omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
struct mmc_data *data)
 {
int cmdreg = 0, resptype = 0, cmdtype = 0;
@@ -464,7 +464,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct 
mmc_command *cmd,
 }
 
 static int
-mmc_omap_get_dma_dir(struct mmc_omap_host *host, struct mmc_data *data)
+omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
 {
   

[PATCH 30/32] omap_hsmmc: ensure all clock enables and disables are paired

2009-07-10 Thread Adrian Hunter
>From 92159741642af71828cb664f716b098152b7a1c1 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Sun, 31 May 2009 19:27:36 +0300
Subject: [PATCH] omap_hsmmc: ensure all clock enables and disables are paired

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   26 ++
 1 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 2570bfe..427bd49 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -727,22 +727,24 @@ static int omap_hsmmc_switch_opcond(struct 
omap_hsmmc_host *host, int vdd)
/* Disable the clocks */
clk_disable(host->fclk);
clk_disable(host->iclk);
-   clk_disable(host->dbclk);
+   if (host->dbclk_enabled)
+   clk_disable(host->dbclk);
 
/* Turn the power off */
ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
-   if (ret != 0)
-   goto err;
 
/* Turn the power ON with given VDD 1.8 or 3.0v */
-   ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd);
+   if (!ret)
+   ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1,
+  vdd);
+   clk_enable(host->iclk);
+   if (host->dbclk_enabled)
+   clk_enable(host->dbclk);
+   clk_enable(host->fclk);
+
if (ret != 0)
goto err;
 
-   clk_enable(host->fclk);
-   clk_enable(host->iclk);
-   clk_enable(host->dbclk);
-
OMAP_HSMMC_WRITE(host->base, HCTL,
OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
reg_val = OMAP_HSMMC_READ(host->base, HCTL);
@@ -1888,7 +1890,8 @@ static int omap_hsmmc_suspend(struct platform_device 
*pdev, pm_message_t state)
OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
mmc_host_disable(host->mmc);
clk_disable(host->iclk);
-   clk_disable(host->dbclk);
+   if (host->dbclk_enabled)
+   clk_disable(host->dbclk);
} else {
host->suspended = 0;
if (host->pdata->resume) {
@@ -1919,9 +1922,8 @@ static int omap_hsmmc_resume(struct platform_device *pdev)
if (ret)
goto clk_en_err;
 
-   if (clk_enable(host->dbclk) != 0)
-   dev_dbg(mmc_dev(host->mmc),
-   "Enabling debounce clk failed\n");
+   if (host->dbclk_enabled)
+   clk_enable(host->dbclk);
 
if (mmc_host_enable(host->mmc) != 0) {
clk_disable(host->iclk);
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 26/32] omap_hsmmc: prevent races with irq handler

2009-07-10 Thread Adrian Hunter
>From 242fae6293adec671b14354f215217354f5076a0 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Sat, 16 May 2009 10:32:34 +0300
Subject: [PATCH] omap_hsmmc: prevent races with irq handler

If an unexpected interrupt occurs while preparing the
next request, an oops can occur.

For example, a new request is setting up DMA for data
transfer so host->data is not NULL.  An unexpected
transfer complete (TC) interrupt comes along and
the interrupt handler sets host->data to NULL.  Oops!

Prevent that by disabling interrupts while setting up
a new request.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   16 
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 28563d6..38e1410 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -452,6 +452,13 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct 
mmc_command *cmd,
if (host->use_dma)
cmdreg |= DMA_EN;
 
+   /*
+* In an interrupt context (i.e. STOP command), the interrupt is already
+* enabled, otherwise it is not (i.e. new request).
+*/
+   if (!in_interrupt())
+   enable_irq(host->irq);
+
OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
 }
@@ -1011,6 +1018,13 @@ static void omap_mmc_request(struct mmc_host *mmc, 
struct mmc_request *req)
struct mmc_omap_host *host = mmc_priv(mmc);
int err;
 
+   /*
+* Prevent races with the interrupt handler because of unexpected
+* interrupts, but not if we are already in interrupt context i.e.
+* retries.
+*/
+   if (!in_interrupt())
+   disable_irq(host->irq);
WARN_ON(host->mrq != NULL);
host->mrq = req;
err = mmc_omap_prepare_data(host, req);
@@ -1019,6 +1033,8 @@ static void omap_mmc_request(struct mmc_host *mmc, struct 
mmc_request *req)
if (req->data)
req->data->error = err;
host->mrq = NULL;
+   if (!in_interrupt())
+   enable_irq(host->irq);
mmc_request_done(mmc, req);
return;
}
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 29/32] omap_hsmmc: protect the card when the cover is open

2009-07-10 Thread Adrian Hunter
>From 9b524a70c3d8f3d138646630bb2144c9895af47a Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Fri, 22 May 2009 16:53:49 +0300
Subject: [PATCH] omap_hsmmc: protect the card when the cover is open

Depending on the manufacturer, there is a small possibility that
removing a card while it is being written to, can render the
card permanently unusable.  To prevent that, the card is made
inaccessible when the cover is open.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   63 +++-
 1 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 5055d52..2570bfe 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -163,6 +163,8 @@ struct omap_hsmmc_host {
int context_loss;
int dpm_state;
int vdd;
+   int protect_card;
+   int reqs_blocked;
 
struct  omap_mmc_platform_data  *pdata;
 };
@@ -347,6 +349,9 @@ static void send_init_stream(struct omap_hsmmc_host *host)
int reg = 0;
unsigned long timeout;
 
+   if (host->protect_card)
+   return;
+
disable_irq(host->irq);
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
@@ -771,6 +776,30 @@ err:
return ret;
 }
 
+/* Protect the card while the cover is open */
+static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
+{
+   if (!mmc_slot(host).get_cover_state)
+   return;
+
+   host->reqs_blocked = 0;
+   if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
+   if (host->protect_card) {
+   printk(KERN_INFO "%s: cover is closed, "
+"card is now accessible\n",
+mmc_hostname(host->mmc));
+   host->protect_card = 0;
+   }
+   } else {
+   if (!host->protect_card) {
+   printk(KERN_INFO "%s: cover is open, "
+"card is now inaccessible\n",
+mmc_hostname(host->mmc));
+   host->protect_card = 1;
+   }
+   }
+}
+
 /*
  * Work Item to notify the core about card insertion/removal
  */
@@ -788,8 +817,10 @@ static void omap_hsmmc_detect(struct work_struct *work)
 
if (slot->card_detect)
carddetect = slot->card_detect(slot->card_detect_irq);
-   else
+   else {
+   omap_hsmmc_protect_card(host);
carddetect = -ENOSYS;
+   }
 
if (carddetect) {
mmc_detect_change(host->mmc, (HZ * 200) / 1000);
@@ -1025,8 +1056,32 @@ static void omap_hsmmc_request(struct mmc_host *mmc, 
struct mmc_request *req)
 * interrupts, but not if we are already in interrupt context i.e.
 * retries.
 */
-   if (!in_interrupt())
+   if (!in_interrupt()) {
disable_irq(host->irq);
+   /*
+* Protect the card from I/O if there is a possibility
+* it can be removed.
+*/
+   if (host->protect_card) {
+   if (host->reqs_blocked < 3) {
+   /*
+* Ensure the controller is left in a consistent
+* state by resetting the command and data state
+* machines.
+*/
+   omap_hsmmc_reset_controller_fsm(host, SRD);
+   omap_hsmmc_reset_controller_fsm(host, SRC);
+   host->reqs_blocked += 1;
+   }
+   req->cmd->error = -EBADF;
+   if (req->data)
+   req->data->error = -EBADF;
+   enable_irq(host->irq);
+   mmc_request_done(mmc, req);
+   return;
+   } else if (host->reqs_blocked)
+   host->reqs_blocked = 0;
+   }
WARN_ON(host->mrq != NULL);
host->mrq = req;
err = omap_hsmmc_prepare_data(host, req);
@@ -1715,6 +1770,8 @@ static int __init omap_hsmmc_probe(struct platform_device 
*pdev)
 
mmc_host_lazy_disable(host->mmc);
 
+   omap_hsmmc_protect_card(host);
+
mmc_add_host(mmc);
 
if (mmc_slot(host).name != NULL) {
@@ -1880,6 +1937,8 @@ static int omap_hsmmc_resume(struct platform_device *pdev)
"Unmask interrupt failed\n");
}
 
+   omap_hsmmc_protect_card(host);
+
/* Notify the core to resume the host */
ret = mmc_resume_ho

[PATCH 27/32] omap_hsmmc: pass host capabilities for SD only and MMC only

2009-07-10 Thread Adrian Hunter
>From 2c975c1612a3ef5f641881b69491265038f0c0b2 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Mon, 18 May 2009 11:33:26 +0300
Subject: [PATCH] omap_hsmmc: pass host capabilities for SD only and MMC only

Some hosts can accept only certain types of cards.
For example, an eMMC is MMC only and a uSD slot may
be SD only.  Pass host capabilities from the board
through to the driver.

Signed-off-by: Adrian Hunter 
---
 arch/arm/mach-omap2/mmc-twl4030.c |5 ++---
 arch/arm/mach-omap2/mmc-twl4030.h |2 +-
 arch/arm/plat-omap/include/mach/mmc.h |6 +++---
 drivers/mmc/host/omap_hsmmc.c |3 +--
 4 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mach-omap2/mmc-twl4030.c 
b/arch/arm/mach-omap2/mmc-twl4030.c
index f95c702..48765bf 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -464,12 +464,11 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info 
*controllers)
} else
mmc->slots[0].gpio_wp = -EINVAL;
 
-   if (c->nonremovable)
-   mmc->slots[0].nonremovable = 1;
-
if (c->power_saving)
mmc->slots[0].power_saving = 1;
 
+   mmc->slots[0].caps = c->caps;
+
/* NOTE:  MMC slots should have a Vcc regulator set up.
 * This may be from a TWL4030-family chip, another
 * controllable regulator, or a fixed supply.
diff --git a/arch/arm/mach-omap2/mmc-twl4030.h 
b/arch/arm/mach-omap2/mmc-twl4030.h
index a47e685..cb43f52 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.h
+++ b/arch/arm/mach-omap2/mmc-twl4030.h
@@ -12,8 +12,8 @@ struct twl4030_hsmmc_info {
booltransceiver;/* MMC-2 option */
boolext_clock;  /* use external pin for input clock */
boolcover_only; /* No card detect - just cover switch */
-   boolnonremovable;   /* Nonremovable e.g. eMMC */
boolpower_saving;   /* Try to sleep or power off when possible */
+   unsigned long caps; /* MMC host capabilities */
int gpio_cd;/* or -EINVAL */
int gpio_wp;/* or -EINVAL */
char*name;  /* or NULL for default */
diff --git a/arch/arm/plat-omap/include/mach/mmc.h 
b/arch/arm/plat-omap/include/mach/mmc.h
index 9390297..48cf2de 100644
--- a/arch/arm/plat-omap/include/mach/mmc.h
+++ b/arch/arm/plat-omap/include/mach/mmc.h
@@ -83,12 +83,12 @@ struct omap_mmc_platform_data {
/* use the internal clock */
unsigned internal_clock:1;
 
-   /* nonremovable e.g. eMMC */
-   unsigned nonremovable:1;
-
/* Try to sleep or power off when possible */
unsigned power_saving:1;
 
+   /* MMC host capabilities */
+   unsigned long caps;
+
int switch_pin; /* gpio (card detect) */
int gpio_wp;/* gpio (write protect) */
 
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 38e1410..fa5f401 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1655,8 +1655,7 @@ static int __init omap_mmc_probe(struct platform_device 
*pdev)
else if (mmc_slot(host).wires >= 4)
mmc->caps |= MMC_CAP_4_BIT_DATA;
 
-   if (mmc_slot(host).nonremovable)
-   mmc->caps |= MMC_CAP_NONREMOVABLE;
+   mmc->caps |= mmc_slot(host).caps;
 
omap_hsmmc_init(host);
 
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 25/32] omap_hsmmc: cater for weird CMD6 behaviour

2009-07-10 Thread Adrian Hunter
>From 4ad1f699fad1f7132e5a6a7ad1a2a433accb88d4 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Sat, 16 May 2009 10:05:40 +0300
Subject: [PATCH] omap_hsmmc: cater for weird CMD6 behaviour

Sometimes the controller unexpectedly produces a TC (transfer
complete) interrupt before the CC (command complete) interrupt for
command 6 (SWITCH).  This is a problem because the CC interrupt
can get mixed up with the next request.  Add a hack for CMD6.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |7 +++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 315d1df..28563d6 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -474,6 +474,13 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct 
mmc_data *data)
if (!data) {
struct mmc_request *mrq = host->mrq;
 
+   /* TC before CC from CMD6 - don't know why, but it happens */
+   if (host->cmd && host->cmd->opcode == 6 &&
+   host->response_busy) {
+   host->response_busy = 0;
+   return;
+   }
+
host->mrq = NULL;
mmc_request_done(host->mmc, mrq);
return;
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 24/32] omap_hsmmc: clear interrupt status after init sequence

2009-07-10 Thread Adrian Hunter
>From 5fffc71c4b754453a286bec4c461ca6897941ad1 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Sat, 16 May 2009 09:35:17 +0300
Subject: [PATCH] omap_hsmmc: clear interrupt status after init sequence

Clear the interrupt status after sending the initialization sequence,
as specified in the TRM.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 743c07a..315d1df 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -358,6 +358,10 @@ static void send_init_stream(struct mmc_omap_host *host)
 
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
+
+   OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+   OMAP_HSMMC_READ(host->base, STAT);
+
enable_irq(host->irq);
 }
 
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 17/32] omap_hsmmc: make use of new MMC_CAP_NONREMOVABLE host capability

2009-07-10 Thread Adrian Hunter
>From 913b1f23036a578427626e5b0a154cd7547c0609 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Mon, 11 May 2009 10:06:38 +0300
Subject: [PATCH] omap_hsmmc: make use of new MMC_CAP_NONREMOVABLE host 
capability

Let the board specify that a card is nonremovable e.g. eMMC

Signed-off-by: Adrian Hunter 
---
 arch/arm/mach-omap2/mmc-twl4030.c |3 +++
 arch/arm/mach-omap2/mmc-twl4030.h |1 +
 arch/arm/plat-omap/include/mach/mmc.h |3 +++
 drivers/mmc/host/omap_hsmmc.c |3 +++
 4 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/mmc-twl4030.c 
b/arch/arm/mach-omap2/mmc-twl4030.c
index 5be3111..67c22c6 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -409,6 +409,9 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info 
*controllers)
} else
mmc->slots[0].gpio_wp = -EINVAL;
 
+   if (c->nonremovable)
+   mmc->slots[0].nonremovable = 1;
+
/* NOTE:  MMC slots should have a Vcc regulator set up.
 * This may be from a TWL4030-family chip, another
 * controllable regulator, or a fixed supply.
diff --git a/arch/arm/mach-omap2/mmc-twl4030.h 
b/arch/arm/mach-omap2/mmc-twl4030.h
index 3807c45..75b0c64 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.h
+++ b/arch/arm/mach-omap2/mmc-twl4030.h
@@ -12,6 +12,7 @@ struct twl4030_hsmmc_info {
booltransceiver;/* MMC-2 option */
boolext_clock;  /* use external pin for input clock */
boolcover_only; /* No card detect - just cover switch */
+   boolnonremovable;   /* Nonremovable e.g. eMMC */
int gpio_cd;/* or -EINVAL */
int gpio_wp;/* or -EINVAL */
char*name;  /* or NULL for default */
diff --git a/arch/arm/plat-omap/include/mach/mmc.h 
b/arch/arm/plat-omap/include/mach/mmc.h
index 2f7cf31..bab486c 100644
--- a/arch/arm/plat-omap/include/mach/mmc.h
+++ b/arch/arm/plat-omap/include/mach/mmc.h
@@ -83,6 +83,9 @@ struct omap_mmc_platform_data {
/* use the internal clock */
unsigned internal_clock:1;
 
+   /* nonremovable e.g. eMMC */
+   unsigned nonremovable:1;
+
int switch_pin; /* gpio (card detect) */
int gpio_wp;/* gpio (write protect) */
 
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 15f1a9a..7b56988 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1383,6 +1383,9 @@ static int __init omap_mmc_probe(struct platform_device 
*pdev)
else if (pdata->slots[host->slot_id].wires >= 4)
mmc->caps |= MMC_CAP_4_BIT_DATA;
 
+   if (pdata->slots[host->slot_id].nonremovable)
+   mmc->caps |= MMC_CAP_NONREMOVABLE;
+
omap_hsmmc_init(host);
 
/* Select DMA lines */
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 23/32] omap_hsmmc: cleanup macro usage

2009-07-10 Thread Adrian Hunter
>From ecb91d032ea4e68f61317a0e5b880277cd02117b Mon Sep 17 00:00:00 2001
From: Denis Karpov 
Date: Thu, 14 May 2009 09:11:38 +0200
Subject: [PATCH] omap_hsmmc: cleanup macro usage

Use macro mmc_slot() in omap_hsmmc.

Signed-off-by: Denis Karpov 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   42 ++--
 1 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index fe46234..743c07a 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -366,9 +366,8 @@ int mmc_omap_cover_is_closed(struct mmc_omap_host *host)
 {
int r = 1;
 
-   if (host->pdata->slots[host->slot_id].get_cover_state)
-   r = host->pdata->slots[host->slot_id].get_cover_state(host->dev,
-   host->slot_id);
+   if (mmc_slot(host).get_cover_state)
+   r = mmc_slot(host).get_cover_state(host->dev, host->slot_id);
return r;
 }
 
@@ -391,9 +390,8 @@ mmc_omap_show_slot_name(struct device *dev, struct 
device_attribute *attr,
 {
struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
struct mmc_omap_host *host = mmc_priv(mmc);
-   struct omap_mmc_slot_data slot = host->pdata->slots[host->slot_id];
 
-   return sprintf(buf, "%s\n", slot.name);
+   return sprintf(buf, "%s\n", mmc_slot(host).name);
 }
 
 static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL);
@@ -625,7 +623,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
(status & CMD_CRC)) {
if (host->cmd) {
if (status & CMD_TIMEOUT) {
-   mmc_omap_reset_controller_fsm(host, 
SRC);
+   mmc_omap_reset_controller_fsm(host,
+ SRC);
host->cmd->error = -ETIMEDOUT;
} else {
host->cmd->error = -EILSEQ;
@@ -768,7 +767,7 @@ static void mmc_omap_detect(struct work_struct *work)
 
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
 
-   if (mmc_slot(host).card_detect)
+   if (slot->card_detect)
carddetect = slot->card_detect(slot->card_detect_irq);
else
carddetect = -ENOSYS;
@@ -823,7 +822,7 @@ static void mmc_omap_config_dma_params(struct mmc_omap_host 
*host,
sg_dma_address(sgl), 0, 0);
} else {
omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
-   (host->mapbase + OMAP_HSMMC_DATA), 0, 
0);
+   (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
sg_dma_address(sgl), 0, 0);
}
@@ -911,7 +910,7 @@ mmc_omap_start_dma_transfer(struct mmc_omap_host *host, 
struct mmc_request *req)
}
 
ret = omap_request_dma(mmc_omap_get_dma_sync_dev(host, data), "MMC/SD",
-  mmc_omap_dma_cb,host, &dma_ch);
+  mmc_omap_dma_cb, host, &dma_ch);
if (ret != 0) {
dev_err(mmc_dev(host->mmc),
"%s: omap_request_dma() failed with %d\n",
@@ -1131,21 +1130,19 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, 
struct mmc_ios *ios)
 static int omap_hsmmc_get_cd(struct mmc_host *mmc)
 {
struct mmc_omap_host *host = mmc_priv(mmc);
-   struct omap_mmc_platform_data *pdata = host->pdata;
 
-   if (!pdata->slots[0].card_detect)
+   if (!mmc_slot(host).card_detect)
return -ENOSYS;
-   return pdata->slots[0].card_detect(pdata->slots[0].card_detect_irq);
+   return mmc_slot(host).card_detect(mmc_slot(host).card_detect_irq);
 }
 
 static int omap_hsmmc_get_ro(struct mmc_host *mmc)
 {
struct mmc_omap_host *host = mmc_priv(mmc);
-   struct omap_mmc_platform_data *pdata = host->pdata;
 
-   if (!pdata->slots[0].get_ro)
+   if (!mmc_slot(host).get_ro)
return -ENOSYS;
-   return pdata->slots[0].get_ro(host->dev, 0);
+   return mmc_slot(host).get_ro(host->dev, 0);
 }
 
 static void omap_hsmmc_init(struct mmc_omap_host *host)
@@ -1556,7 +1553,7 @@ static int __init omap_mmc_probe(struct platform_device 
*pdev)
platform_set_drvdata(pdev, host);
INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
 
-   if (pdata->slots[host->slot_id].power_saving)
+   if (mmc_slot(host).power_saving)
mmc->ops= &mmc_omap_ps_ops;
else
mmc->ops= &mmc_omap_ops;
@@ -1626,12 +1623,12 @@ static int __init omap_mmc_probe(struct platform_device 
*pdev)
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPE

[PATCH 15/32] omap_hsmmc: ensure workqueues are empty before suspend

2009-07-10 Thread Adrian Hunter
>From 697301e98721b32335caa2dc83b654c81866a97e Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Fri, 24 Apr 2009 13:13:20 +0300
Subject: [PATCH] omap_hsmmc: ensure workqueues are empty before suspend

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   50 +++-
 1 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 2e2a81c..41500ac 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -149,7 +149,6 @@ struct mmc_omap_host {
u32 bytesleft;
int suspended;
int irq;
-   int carddetect;
int use_dma, dma_ch;
int dma_line_tx, dma_line_rx;
int slot_id;
@@ -754,14 +753,19 @@ static void mmc_omap_detect(struct work_struct *work)
struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
mmc_carddetect_work);
struct omap_mmc_slot_data *slot = &mmc_slot(host);
+   int carddetect;
+
+   if (host->suspended)
+   return;
+
+   sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
 
if (mmc_slot(host).card_detect)
-   host->carddetect = slot->card_detect(slot->card_detect_irq);
+   carddetect = slot->card_detect(slot->card_detect_irq);
else
-   host->carddetect = -ENOSYS;
+   carddetect = -ENOSYS;
 
-   sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
-   if (host->carddetect) {
+   if (carddetect) {
mmc_detect_change(host->mmc, (HZ * 200) / 1000);
} else {
mmc_host_enable(host->mmc);
@@ -778,6 +782,8 @@ static irqreturn_t omap_mmc_cd_handler(int irq, void 
*dev_id)
 {
struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
 
+   if (host->suspended)
+   return IRQ_HANDLED;
schedule_work(&host->mmc_carddetect_work);
 
return IRQ_HANDLED;
@@ -1517,30 +1523,42 @@ static int omap_mmc_suspend(struct platform_device 
*pdev, pm_message_t state)
return 0;
 
if (host) {
+   host->suspended = 1;
+   if (host->pdata->suspend) {
+   ret = host->pdata->suspend(&pdev->dev,
+   host->slot_id);
+   if (ret) {
+   dev_dbg(mmc_dev(host->mmc),
+   "Unable to handle MMC board"
+   " level suspend\n");
+   host->suspended = 0;
+   return ret;
+   }
+   }
+   cancel_work_sync(&host->mmc_carddetect_work);
mmc_host_enable(host->mmc);
ret = mmc_suspend_host(host->mmc, state);
if (ret == 0) {
-   host->suspended = 1;
-
OMAP_HSMMC_WRITE(host->base, ISE, 0);
OMAP_HSMMC_WRITE(host->base, IE, 0);
 
-   if (host->pdata->suspend) {
-   ret = host->pdata->suspend(&pdev->dev,
-   host->slot_id);
-   if (ret)
-   dev_dbg(mmc_dev(host->mmc),
-   "Unable to handle MMC board"
-   " level suspend\n");
-   }
 
OMAP_HSMMC_WRITE(host->base, HCTL,
 OMAP_HSMMC_READ(host->base, HCTL) & 
~SDBP);
mmc_host_disable(host->mmc);
clk_disable(host->iclk);
clk_disable(host->dbclk);
-   } else
+   } else {
+   host->suspended = 0;
+   if (host->pdata->resume) {
+   ret = host->pdata->resume(&pdev->dev,
+ host->slot_id);
+   if (ret)
+   dev_dbg(mmc_dev(host->mmc),
+   "Unmask interrupt failed\n");
+   }
mmc_host_disable(host->mmc);
+   }
 
}
return ret;
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 22/32] omap_hsmmc: fix NULL pointer dereference

2009-07-10 Thread Adrian Hunter
>From ece776be05f73787dad93802000f2d04218197d0 Mon Sep 17 00:00:00 2001
From: Jarkko Lavinen 
Date: Tue, 12 May 2009 19:46:14 +0300
Subject: [PATCH] omap_hsmmc: fix NULL pointer dereference

Do not call 'mmc_omap_xfer_done()' if the request is
already done.

Signed-off-by: Jarkko Lavinen 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 41c330d..fe46234 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -670,7 +670,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
 
if (end_cmd || ((status & CC) && host->cmd))
mmc_omap_cmd_done(host, host->cmd);
-   if (end_trans || (status & TC))
+   if ((end_trans || (status & TC)) && host->mrq)
mmc_omap_xfer_done(host, data);
 
return IRQ_HANDLED;
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 21/32] omap_hsmmc: add mmc card sleep and awake support

2009-07-10 Thread Adrian Hunter
>From 8bf0af61703bd4a1d397f565104bee69c77ff586 Mon Sep 17 00:00:00 2001
From: Jarkko Lavinen 
Date: Tue, 12 May 2009 19:46:14 +0300
Subject: [PATCH] omap_hsmmc: add mmc card sleep and awake support

After 1 second of inactivity, put card and/or regulator
to sleep.  After 8 seconds of inactivity, turn off the
power.

Signed-off-by: Jarkko Lavinen 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |  162 ++---
 1 files changed, 88 insertions(+), 74 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index eb301c1..41c330d 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -27,6 +27,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -113,7 +114,8 @@
 
 /* Timeouts for entering power saving states on inactivity, msec */
 #define OMAP_MMC_DISABLED_TIMEOUT  100
-#define OMAP_MMC_OFF_TIMEOUT   1000
+#define OMAP_MMC_SLEEP_TIMEOUT 1000
+#define OMAP_MMC_OFF_TIMEOUT   8000
 
 /*
  * One controller can have multiple slots, like on some omap boards using
@@ -1175,20 +1177,21 @@ static void omap_hsmmc_init(struct mmc_omap_host *host)
 
 /*
  * Dynamic power saving handling, FSM:
- *   ENABLED -> DISABLED -> OFF / REGSLEEP
- * ^___|  |
- * |__|
+ *   ENABLED -> DISABLED -> CARDSLEEP / REGSLEEP -> OFF
+ * ^___|  |  |
+ * |__|__|
  *
  * ENABLED:   mmc host is fully functional
  * DISABLED:  fclk is off
- * OFF:   fclk is off,voltage regulator is off
- * REGSLEEP:  fclk is off,voltage regulator is asleep
+ * CARDSLEEP: fclk is off, card is asleep, voltage regulator is asleep
+ * REGSLEEP:  fclk is off, voltage regulator is asleep
+ * OFF:   fclk is off, voltage regulator is off
  *
  * Transition handlers return the timeout for the next state transition
  * or negative error.
  */
 
-enum {ENABLED = 0, DISABLED, REGSLEEP, OFF};
+enum {ENABLED = 0, DISABLED, CARDSLEEP, REGSLEEP, OFF};
 
 /* Handler for [ENABLED -> DISABLED] transition */
 static int omap_mmc_enabled_to_disabled(struct mmc_omap_host *host)
@@ -1202,46 +1205,72 @@ static int omap_mmc_enabled_to_disabled(struct 
mmc_omap_host *host)
if (host->power_mode == MMC_POWER_OFF)
return 0;
 
-   return msecs_to_jiffies(OMAP_MMC_OFF_TIMEOUT);
+   return msecs_to_jiffies(OMAP_MMC_SLEEP_TIMEOUT);
 }
 
-/* Handler for [DISABLED -> OFF] transition */
-static int omap_mmc_disabled_to_off(struct mmc_omap_host *host)
+/* Handler for [DISABLED -> REGSLEEP / CARDSLEEP] transition */
+static int omap_mmc_disabled_to_sleep(struct mmc_omap_host *host)
 {
-   int new_state;
-
-   dev_dbg(mmc_dev(host->mmc), "DISABLED -> OFF\n");
+   int err, new_state;
 
if (!mmc_try_claim_host(host->mmc))
return 0;
 
clk_enable(host->fclk);
-
omap_mmc_restore_ctx(host);
+   if (mmc_card_can_sleep(host->mmc)) {
+   err = mmc_card_sleep(host->mmc);
+   if (err < 0) {
+   clk_disable(host->fclk);
+   mmc_release_host(host->mmc);
+   return err;
+   }
+   new_state = CARDSLEEP;
+   } else
+   new_state = REGSLEEP;
+   if (mmc_slot(host).set_sleep)
+   mmc_slot(host).set_sleep(host->dev, host->slot_id, 1, 0,
+new_state == CARDSLEEP);
+   /* FIXME: turn off bus power and perhaps interrupts too */
+   clk_disable(host->fclk);
+   host->dpm_state = new_state;
+
+   mmc_release_host(host->mmc);
+
+   dev_dbg(mmc_dev(host->mmc), "DISABLED -> %s\n",
+   host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP");
 
if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
mmc_slot(host).card_detect ||
(mmc_slot(host).get_cover_state &&
-mmc_slot(host).get_cover_state(host->dev, host->slot_id))) {
-   mmc_power_save_host(host->mmc);
-   new_state = OFF;
-   } else {
-   if (mmc_slot(host).set_sleep)
-   mmc_slot(host).set_sleep(host->dev, host->slot_id,
-1, 0, 0);
-   new_state = REGSLEEP;
+mmc_slot(host).get_cover_state(host->dev, host->slot_id)))
+   return msecs_to_jiffies(OMAP_MMC_OFF_TIMEOUT);
+
+   return 0;
+}
+
+/* Handler for [REGSLEEP / CARDSLEEP -> OFF] transition */
+static int omap_mmc_sleep_to_off(struct mmc_omap_host *host)
+{
+   if (!mmc_try_claim_host(host->mmc))
+   return 0;
+
+   if (!((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
+ mmc_slot(host).card_detect ||
+ (mmc_slot(host).get_cover_state &&
+  mmc_slot(host).get_cover_state(host->dev, host->slot_

[PATCH 20/32] omap_hsmmc: put MMC regulator to sleep

2009-07-10 Thread Adrian Hunter
>From 66c91dd04118c2e2111dade9d5a327c442912046 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Tue, 12 May 2009 20:54:51 +0300
Subject: [PATCH] omap_hsmmc: put MMC regulator to sleep

When a card is not in use, the voltage regulator can be put
to sleep.  This is an alternative to powering the card off,
when powering off is not safe because the card might be
replaced without the driver being aware of it.

That situation happens if:
- the card is removable i.e. not eMMC
- and there is no card detect
- and there is a cover switch but the cover is open

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   59 +---
 1 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index c69ab89..eb301c1 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -160,6 +160,7 @@ struct mmc_omap_host {
int response_busy;
int context_loss;
int dpm_state;
+   int vdd;
 
struct  omap_mmc_platform_data  *pdata;
 };
@@ -1031,10 +1032,12 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, 
struct mmc_ios *ios)
case MMC_POWER_OFF:
mmc_slot(host).set_power(host->dev, host->slot_id,
 0, 0);
+   host->vdd = 0;
break;
case MMC_POWER_UP:
mmc_slot(host).set_power(host->dev, host->slot_id,
 1, ios->vdd);
+   host->vdd = ios->vdd;
break;
case MMC_POWER_ON:
do_send_init_stream = 1;
@@ -1172,19 +1175,20 @@ static void omap_hsmmc_init(struct mmc_omap_host *host)
 
 /*
  * Dynamic power saving handling, FSM:
- *   ENABLED -> DISABLED -> OFF
+ *   ENABLED -> DISABLED -> OFF / REGSLEEP
  * ^___|  |
  * |__|
  *
  * ENABLED:   mmc host is fully functional
  * DISABLED:  fclk is off
  * OFF:   fclk is off,voltage regulator is off
+ * REGSLEEP:  fclk is off,voltage regulator is asleep
  *
  * Transition handlers return the timeout for the next state transition
  * or negative error.
  */
 
-enum {ENABLED = 0, DISABLED, OFF};
+enum {ENABLED = 0, DISABLED, REGSLEEP, OFF};
 
 /* Handler for [ENABLED -> DISABLED] transition */
 static int omap_mmc_enabled_to_disabled(struct mmc_omap_host *host)
@@ -1221,8 +1225,12 @@ static int omap_mmc_disabled_to_off(struct mmc_omap_host 
*host)
 mmc_slot(host).get_cover_state(host->dev, host->slot_id))) {
mmc_power_save_host(host->mmc);
new_state = OFF;
-   } else
-   new_state = DISABLED;
+   } else {
+   if (mmc_slot(host).set_sleep)
+   mmc_slot(host).set_sleep(host->dev, host->slot_id,
+1, 0, 0);
+   new_state = REGSLEEP;
+   }
 
OMAP_HSMMC_WRITE(host->base, ISE, 0);
OMAP_HSMMC_WRITE(host->base, IE, 0);
@@ -1279,6 +1287,44 @@ static int omap_mmc_off_to_enabled(struct mmc_omap_host 
*host)
return 0;
 }
 
+/* Handler for [REGSLEEP -> ENABLED] transition */
+static int omap_mmc_regsleep_to_enabled(struct mmc_omap_host *host)
+{
+   unsigned long timeout;
+
+   dev_dbg(mmc_dev(host->mmc), "REGSLEEP -> ENABLED\n");
+
+   clk_enable(host->fclk);
+   clk_enable(host->iclk);
+
+   if (clk_enable(host->dbclk))
+   dev_dbg(mmc_dev(host->mmc),
+   "Enabling debounce clk failed\n");
+
+   omap_mmc_restore_ctx(host);
+
+   /*
+* We turned off interrupts and bus power.  Interrupts
+* are turned on by 'mmc_omap_start_command()' so we
+* just need to turn on the bus power here.
+*/
+   OMAP_HSMMC_WRITE(host->base, HCTL,
+OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+
+   timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+   while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP &&
+  time_before(jiffies, timeout))
+   ;
+
+   if (mmc_slot(host).set_sleep)
+   mmc_slot(host).set_sleep(host->dev, host->slot_id,
+0, host->vdd, 0);
+
+   host->dpm_state = ENABLED;
+
+   return 0;
+}
+
 /*
  * Bring MMC host to ENABLED from any other PM state.
  */
@@ -1289,6 +1335,8 @@ static int omap_mmc_enable(struct mmc_host *mmc)
switch (host->dpm_state) {
case DISABLED:
return omap_mmc_disabled_to_enabled(host);
+   case REGSLEEP:
+   return omap_mmc_regsleep_to_enabled(host);
case OFF:
return omap_mmc_off_to_enabled(host);
default:
@@ 

[PATCH 19/32] ARM: OMAP: mmc-twl4030: add regulator sleep / wake function

2009-07-10 Thread Adrian Hunter
>From 99e5f5c1e7e4e8195cae27d2fc5be75424d5bc75 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Wed, 8 Jul 2009 13:20:30 +0300
Subject: [PATCH] ARM: OMAP: mmc-twl4030: add regulator sleep / wake function

Add the ability for the driver to put the card power
regulators to sleep and wake them up again.

Signed-off-by: Adrian Hunter 
---
 arch/arm/mach-omap2/mmc-twl4030.c |   57 +
 arch/arm/plat-omap/include/mach/mmc.h |2 +
 2 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/mmc-twl4030.c 
b/arch/arm/mach-omap2/mmc-twl4030.c
index 3678f0e..f95c702 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -334,6 +334,61 @@ static int twl_mmc23_set_power(struct device *dev, int 
slot, int power_on, int v
return ret;
 }
 
+static int twl_mmc1_set_sleep(struct device *dev, int slot, int sleep, int vdd,
+ int cardsleep)
+{
+   struct twl_mmc_controller *c = &hsmmc[0];
+   int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
+
+   return regulator_set_mode(c->vcc, mode);
+}
+
+static int twl_mmc23_set_sleep(struct device *dev, int slot, int sleep, int 
vdd,
+  int cardsleep)
+{
+   struct twl_mmc_controller *c = NULL;
+   struct omap_mmc_platform_data *mmc = dev->platform_data;
+   int i, err, mode;
+
+   for (i = 1; i < ARRAY_SIZE(hsmmc); i++) {
+   if (mmc == hsmmc[i].mmc) {
+   c = &hsmmc[i];
+   break;
+   }
+   }
+
+   if (c == NULL)
+   return -ENODEV;
+
+   /*
+* If we don't see a Vcc regulator, assume it's a fixed
+* voltage always-on regulator.
+*/
+   if (!c->vcc)
+   return 0;
+
+   mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
+
+   if (!c->vcc_aux)
+   return regulator_set_mode(c->vcc, mode);
+
+   if (cardsleep) {
+   /* VCC can be turned off if card is asleep */
+   struct regulator *vcc_aux = c->vcc_aux;
+
+   c->vcc_aux = NULL;
+   if (sleep)
+   err = twl_mmc23_set_power(dev, slot, 0, 0);
+   else
+   err = twl_mmc23_set_power(dev, slot, 1, vdd);
+   c->vcc_aux = vcc_aux;
+   } else
+   err = regulator_set_mode(c->vcc, mode);
+   if (err)
+   return err;
+   return regulator_set_mode(c->vcc_aux, mode);
+}
+
 static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
 
 void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
@@ -427,6 +482,7 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info 
*controllers)
case 1:
/* on-chip level shifting via PBIAS0/PBIAS1 */
mmc->slots[0].set_power = twl_mmc1_set_power;
+   mmc->slots[0].set_sleep = twl_mmc1_set_sleep;
break;
case 2:
if (c->ext_clock)
@@ -437,6 +493,7 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info 
*controllers)
case 3:
/* off-chip level shifting, or none */
mmc->slots[0].set_power = twl_mmc23_set_power;
+   mmc->slots[0].set_sleep = twl_mmc23_set_sleep;
break;
default:
pr_err("MMC%d configuration not supported!\n", c->mmc);
diff --git a/arch/arm/plat-omap/include/mach/mmc.h 
b/arch/arm/plat-omap/include/mach/mmc.h
index 82f1e29..9390297 100644
--- a/arch/arm/plat-omap/include/mach/mmc.h
+++ b/arch/arm/plat-omap/include/mach/mmc.h
@@ -95,6 +95,8 @@ struct omap_mmc_platform_data {
int (* set_bus_mode)(struct device *dev, int slot, int 
bus_mode);
int (* set_power)(struct device *dev, int slot, int power_on, 
int vdd);
int (* get_ro)(struct device *dev, int slot);
+   int (*set_sleep)(struct device *dev, int slot, int sleep,
+int vdd, int cardsleep);
 
/* return MMC cover switch state, can be NULL if not supported.
 *
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 18/32] omap_hsmmc: support for deeper power saving states

2009-07-10 Thread Adrian Hunter
>From a86c083ca740b4311daf3dc8e219506b63756896 Mon Sep 17 00:00:00 2001
From: Denis Karpov 
Date: Mon, 11 May 2009 14:41:30 +0300
Subject: [PATCH] omap_hsmmc: support for deeper power saving states

Support for multi-level dynamic power saving states in omap_hsmmc
(ENABLED->DISABLED->OFF).
In the "deepest" state (OFF) we switch off the voltage regulators.

Signed-off-by: Denis Karpov 
Signed-off-by: Adrian Hunter 
---
 arch/arm/mach-omap2/mmc-twl4030.c |3 +
 arch/arm/mach-omap2/mmc-twl4030.h |1 +
 arch/arm/plat-omap/include/mach/mmc.h |3 +
 drivers/mmc/host/omap_hsmmc.c |  245 +
 4 files changed, 222 insertions(+), 30 deletions(-)

diff --git a/arch/arm/mach-omap2/mmc-twl4030.c 
b/arch/arm/mach-omap2/mmc-twl4030.c
index 67c22c6..3678f0e 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -412,6 +412,9 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info 
*controllers)
if (c->nonremovable)
mmc->slots[0].nonremovable = 1;
 
+   if (c->power_saving)
+   mmc->slots[0].power_saving = 1;
+
/* NOTE:  MMC slots should have a Vcc regulator set up.
 * This may be from a TWL4030-family chip, another
 * controllable regulator, or a fixed supply.
diff --git a/arch/arm/mach-omap2/mmc-twl4030.h 
b/arch/arm/mach-omap2/mmc-twl4030.h
index 75b0c64..a47e685 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.h
+++ b/arch/arm/mach-omap2/mmc-twl4030.h
@@ -13,6 +13,7 @@ struct twl4030_hsmmc_info {
boolext_clock;  /* use external pin for input clock */
boolcover_only; /* No card detect - just cover switch */
boolnonremovable;   /* Nonremovable e.g. eMMC */
+   boolpower_saving;   /* Try to sleep or power off when possible */
int gpio_cd;/* or -EINVAL */
int gpio_wp;/* or -EINVAL */
char*name;  /* or NULL for default */
diff --git a/arch/arm/plat-omap/include/mach/mmc.h 
b/arch/arm/plat-omap/include/mach/mmc.h
index bab486c..82f1e29 100644
--- a/arch/arm/plat-omap/include/mach/mmc.h
+++ b/arch/arm/plat-omap/include/mach/mmc.h
@@ -86,6 +86,9 @@ struct omap_mmc_platform_data {
/* nonremovable e.g. eMMC */
unsigned nonremovable:1;
 
+   /* Try to sleep or power off when possible */
+   unsigned power_saving:1;
+
int switch_pin; /* gpio (card detect) */
int gpio_wp;/* gpio (write protect) */
 
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 7b56988..c69ab89 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -111,6 +111,10 @@
 #define OMAP_MMC_MASTER_CLOCK  9600
 #define DRIVER_NAME"mmci-omap-hs"
 
+/* Timeouts for entering power saving states on inactivity, msec */
+#define OMAP_MMC_DISABLED_TIMEOUT  100
+#define OMAP_MMC_OFF_TIMEOUT   1000
+
 /*
  * One controller can have multiple slots, like on some omap boards using
  * omap.c controller driver. Luckily this is not currently done on any known
@@ -155,6 +159,7 @@ struct mmc_omap_host {
int dbclk_enabled;
int response_busy;
int context_loss;
+   int dpm_state;
 
struct  omap_mmc_platform_data  *pdata;
 };
@@ -985,29 +990,6 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct 
mmc_request *req)
return 0;
 }
 
-static int omap_mmc_enable(struct mmc_host *mmc)
-{
-   struct mmc_omap_host *host = mmc_priv(mmc);
-   int err;
-
-   err = clk_enable(host->fclk);
-   if (err)
-   return err;
-   dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
-   omap_mmc_restore_ctx(host);
-   return 0;
-}
-
-static int omap_mmc_disable(struct mmc_host *mmc, int lazy)
-{
-   struct mmc_omap_host *host = mmc_priv(mmc);
-
-   omap_mmc_save_ctx(host);
-   clk_disable(host->fclk);
-   dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n");
-   return 0;
-}
-
 /*
  * Request function. for read/write operation
  */
@@ -1061,6 +1043,8 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct 
mmc_ios *ios)
host->power_mode = ios->power_mode;
}
 
+   /* FIXME: set registers based only on changes to ios */
+
con = OMAP_HSMMC_READ(host->base, CON);
switch (mmc->ios.bus_width) {
case MMC_BUS_WIDTH_8:
@@ -1133,7 +1117,10 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, 
struct mmc_ios *ios)
else
OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
 
-   mmc_host_lazy_disable(host->mmc);
+   if (host->power_mode == MMC_POWER_OFF)
+   mmc_host_disable(host->mmc);
+   else
+   mmc_host_l

[PATCH 16/32] omap_hsmmc: fix scatter-gather list sanity checking

2009-07-10 Thread Adrian Hunter
>From 85020821e459904d381684dde45a2a500e02cadb Mon Sep 17 00:00:00 2001
From: Jarkko Lavinen 
Date: Fri, 24 Apr 2009 14:20:43 +0300
Subject: [PATCH] omap_hsmmc: fix scatter-gather list sanity checking

Do not use host->dma_len when it is uninitialzed.
Finish the request with an error if the mmc_omap_prepare_data()
fails.

Signed-off-by: Jarkko Lavinen 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   14 --
 1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 41500ac..15f1a9a 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -871,7 +871,7 @@ mmc_omap_start_dma_transfer(struct mmc_omap_host *host, 
struct mmc_request *req)
struct mmc_data *data = req->data;
 
/* Sanity check: all the SG entries must be aligned by block size. */
-   for (i = 0; i < host->dma_len; i++) {
+   for (i = 0; i < data->sg_len; i++) {
struct scatterlist *sgl;
 
sgl = data->sg + i;
@@ -1014,10 +1014,20 @@ static int omap_mmc_disable(struct mmc_host *mmc, int 
lazy)
 static void omap_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
 {
struct mmc_omap_host *host = mmc_priv(mmc);
+   int err;
 
WARN_ON(host->mrq != NULL);
host->mrq = req;
-   mmc_omap_prepare_data(host, req);
+   err = mmc_omap_prepare_data(host, req);
+   if (err) {
+   req->cmd->error = err;
+   if (req->data)
+   req->data->error = err;
+   host->mrq = NULL;
+   mmc_request_done(mmc, req);
+   return;
+   }
+
mmc_omap_start_command(host, req->cmd, req->data);
 }
 
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 14/32] omap_hsmmc: set open drain bit correctly

2009-07-10 Thread Adrian Hunter
>From 78e90903abbc084ebdd7716498eac9429c61e878 Mon Sep 17 00:00:00 2001
From: Denis Karpov 
Date: Thu, 23 Apr 2009 16:44:58 +0300
Subject: [PATCH] omap_hsmmc: set open drain bit correctly

The code could set the bit to 1 but not reset it to 0.

Signed-off-by: Denis Karpov 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |6 --
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 762aa01..2e2a81c 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -,9 +,11 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, 
struct mmc_ios *ios)
if (do_send_init_stream)
send_init_stream(host);
 
+   con = OMAP_HSMMC_READ(host->base, CON);
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-   OMAP_HSMMC_WRITE(host->base, CON,
-   OMAP_HSMMC_READ(host->base, CON) | OD);
+   OMAP_HSMMC_WRITE(host->base, CON, con | OD);
+   else
+   OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
 
mmc_host_lazy_disable(host->mmc);
 }
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 13/32] omap_hsmmc: context save/restore support

2009-07-10 Thread Adrian Hunter
>From 3eb49df725b26329e85db6e4fc6f72fc029501a3 Mon Sep 17 00:00:00 2001
From: Denis Karpov 
Date: Wed, 22 Apr 2009 16:04:25 +0200
Subject: [PATCH] omap_hsmmc: context save/restore support

Keep the context over PM dynamic OFF states.

Signed-off-by: Denis Karpov 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |  194 ++--
 1 files changed, 184 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dad0548..762aa01 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -37,6 +37,7 @@
 
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSCONFIG   0x0010
+#define OMAP_HSMMC_SYSSTATUS   0x0014
 #define OMAP_HSMMC_CON 0x002C
 #define OMAP_HSMMC_BLK 0x0104
 #define OMAP_HSMMC_ARG 0x0108
@@ -94,6 +95,8 @@
 #define DUAL_VOLT_OCR_BIT  7
 #define SRC(1 << 25)
 #define SRD(1 << 26)
+#define SOFTRESET  (1 << 1)
+#define RESETDONE  (1 << 0)
 
 /*
  * FIXME: Most likely all the data using these _DEVID defines should come
@@ -152,6 +155,8 @@ struct mmc_omap_host {
int slot_id;
int dbclk_enabled;
int response_busy;
+   int context_loss;
+
struct  omap_mmc_platform_data  *pdata;
 };
 
@@ -166,6 +171,166 @@ static void omap_mmc_stop_clock(struct mmc_omap_host 
*host)
dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
 }
 
+#ifdef CONFIG_PM
+
+/*
+ * Restore the MMC host context, if it was lost as result of a
+ * power state change.
+ */
+static int omap_mmc_restore_ctx(struct mmc_omap_host *host)
+{
+   struct mmc_ios *ios = &host->mmc->ios;
+   struct omap_mmc_platform_data *pdata = host->pdata;
+   int context_loss = 0;
+   u32 hctl, capa, con;
+   u16 dsor = 0;
+   unsigned long timeout;
+
+   if (pdata->get_context_loss_count) {
+   context_loss = pdata->get_context_loss_count(host->dev);
+   if (context_loss < 0)
+   return 1;
+   }
+
+   dev_dbg(mmc_dev(host->mmc), "context was %slost\n",
+   context_loss == host->context_loss ? "not " : "");
+   if (host->context_loss == context_loss)
+   return 1;
+
+   /* Wait for hardware reset */
+   timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+   while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
+   && time_before(jiffies, timeout))
+   ;
+
+   /* Do software reset */
+   OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET);
+   timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+   while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
+   && time_before(jiffies, timeout))
+   ;
+
+   OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
+   OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
+
+   if (host->id == OMAP_MMC1_DEVID) {
+   if (host->power_mode != MMC_POWER_OFF &&
+   (1 << ios->vdd) <= MMC_VDD_23_24)
+   hctl = SDVS18;
+   else
+   hctl = SDVS30;
+   capa = VS30 | VS18;
+   } else {
+   hctl = SDVS18;
+   capa = VS18;
+   }
+
+   OMAP_HSMMC_WRITE(host->base, HCTL,
+   OMAP_HSMMC_READ(host->base, HCTL) | hctl);
+
+   OMAP_HSMMC_WRITE(host->base, CAPA,
+   OMAP_HSMMC_READ(host->base, CAPA) | capa);
+
+   OMAP_HSMMC_WRITE(host->base, HCTL,
+   OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+
+   timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+   while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP
+   && time_before(jiffies, timeout))
+   ;
+
+   OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+   OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+   OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+   /* Do not initialize card-specific things if the power is off */
+   if (host->power_mode == MMC_POWER_OFF)
+   goto out;
+
+   con = OMAP_HSMMC_READ(host->base, CON);
+   switch (ios->bus_width) {
+   case MMC_BUS_WIDTH_8:
+   OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
+   break;
+   case MMC_BUS_WIDTH_4:
+   OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
+   OMAP_HSMMC_WRITE(host->base, HCTL,
+   OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
+   break;
+   case MMC_BUS_WIDTH_1:
+   OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
+   OMAP_HSMMC_WRITE(host->base, HCTL,
+   OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
+   break;

[PATCH 12/32] omap_hsmmc: keep track of power mode

2009-07-10 Thread Adrian Hunter
>From ad6fd97ce361b6527fc3a951ca6efa5f9a0b59ee Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Tue, 7 Jul 2009 16:44:11 +0300
Subject: [PATCH] omap_hsmmc: keep track of power mode

This patch is preparation for adding context save
and restore support.

Keep track of the current power mode so that the
context restore function can avoid restoring the
context for a card if the power has been switched
off.  If the power is off, the card must be
reinitialized anyway which will re-establish the
context.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   27 +++
 1 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 0fded10..dad0548 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -141,6 +141,7 @@ struct mmc_omap_host {
unsigned intdma_len;
unsigned intdma_sg_idx;
unsigned char   bus_mode;
+   unsigned char   power_mode;
u32 *buffer;
u32 bytesleft;
int suspended;
@@ -856,16 +857,25 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct 
mmc_ios *ios)
unsigned long regval;
unsigned long timeout;
u32 con;
+   int do_send_init_stream = 0;
 
mmc_host_enable(host->mmc);
 
-   switch (ios->power_mode) {
-   case MMC_POWER_OFF:
-   mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
-   break;
-   case MMC_POWER_UP:
-   mmc_slot(host).set_power(host->dev, host->slot_id, 1, ios->vdd);
-   break;
+   if (ios->power_mode != host->power_mode) {
+   switch (ios->power_mode) {
+   case MMC_POWER_OFF:
+   mmc_slot(host).set_power(host->dev, host->slot_id,
+0, 0);
+   break;
+   case MMC_POWER_UP:
+   mmc_slot(host).set_power(host->dev, host->slot_id,
+1, ios->vdd);
+   break;
+   case MMC_POWER_ON:
+   do_send_init_stream = 1;
+   break;
+   }
+   host->power_mode = ios->power_mode;
}
 
con = OMAP_HSMMC_READ(host->base, CON);
@@ -931,7 +941,7 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct 
mmc_ios *ios)
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
 
-   if (ios->power_mode == MMC_POWER_ON)
+   if (do_send_init_stream)
send_init_stream(host);
 
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
@@ -1109,6 +1119,7 @@ static int __init omap_mmc_probe(struct platform_device 
*pdev)
host->slot_id   = 0;
host->mapbase   = res->start;
host->base  = ioremap(host->mapbase, SZ_4K);
+   host->power_mode = -1;
 
platform_set_drvdata(pdev, host);
INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 8/32] mmc: check status after MMC SWITCH command

2009-07-10 Thread Adrian Hunter
>From cda3074c6233408ec29365c5e63b80567bff8c5c Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Wed, 3 Jun 2009 12:22:29 +0300
Subject: [PATCH] mmc: check status after MMC SWITCH command

According to the standard, the SWITCH command should
be followed by a SEND_STATUS command to check for
errors.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/core/mmc.c |   24 ++--
 drivers/mmc/core/mmc_ops.c |   23 +++
 include/linux/mmc/mmc.h|1 +
 3 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 8e2e3d2..f87cc0b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -416,12 +416,17 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 1);
-   if (err)
+   if (err && err != -EBADMSG)
goto free_card;
 
-   mmc_card_set_highspeed(card);
-
-   mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+   if (err) {
+   printk(KERN_WARNING "%s: switch to highspeed failed\n",
+  mmc_hostname(card->host));
+   err = 0;
+   } else {
+   mmc_card_set_highspeed(card);
+   mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+   }
}
 
/*
@@ -456,10 +461,17 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 EXT_CSD_BUS_WIDTH, ext_csd_bit);
 
-   if (err)
+   if (err && err != -EBADMSG)
goto free_card;
 
-   mmc_set_bus_width(card->host, bus_width);
+   if (err) {
+   printk(KERN_WARNING "%s: switch to bus width %d "
+  "failed\n", mmc_hostname(card->host),
+  1 << bus_width);
+   err = 0;
+   } else {
+   mmc_set_bus_width(card->host, bus_width);
+   }
}
 
if (!oldcard)
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 355c604..d2cb5c6 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -390,6 +390,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 
value)
 {
int err;
struct mmc_command cmd;
+   u32 status;
 
BUG_ON(!card);
BUG_ON(!card->host);
@@ -407,6 +408,28 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 
value)
if (err)
return err;
 
+   /* Must check status to be sure of no errors */
+   do {
+   err = mmc_send_status(card, &status);
+   if (err)
+   return err;
+   if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+   break;
+   if (mmc_host_is_spi(card->host))
+   break;
+   } while (R1_CURRENT_STATE(status) == 7);
+
+   if (mmc_host_is_spi(card->host)) {
+   if (status & R1_SPI_ILLEGAL_COMMAND)
+   return -EBADMSG;
+   } else {
+   if (status & 0xFDFFA000)
+   printk(KERN_WARNING "%s: unexpected status %#x after "
+  "switch", mmc_hostname(card->host), status);
+   if (status & R1_SWITCH_ERROR)
+   return -EBADMSG;
+   }
+
return 0;
 }
 
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index b2b4095..c02c8db 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -128,6 +128,7 @@
 #define R1_STATUS(x)(x & 0xE000)
 #define R1_CURRENT_STATE(x)((x & 0x1E00) >> 9) /* sx, b (4 bits) */
 #define R1_READY_FOR_DATA  (1 << 8)/* sx, a */
+#define R1_SWITCH_ERROR(1 << 7)/* sx, c */
 #define R1_APP_CMD (1 << 5)/* sr, c */
 
 /*
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 11/32] ARM: OMAP: mmc-twl4030: add context loss counter support

2009-07-10 Thread Adrian Hunter
>From 57e1d1301b974e57f65a8f7b1287629b3c97a3b8 Mon Sep 17 00:00:00 2001
From: Denis Karpov 
Date: Tue, 7 Jul 2009 15:54:44 +0300
Subject: [PATCH] ARM: OMAP: mmc-twl4030: add context loss counter support

PM dynamic OFF state results in context loss.  That is, the host
controller has been powered off at some point, which means the
registers have been reset.  The driver must detect when this
happens, and restore the context.  This patch adds the means
to detect context loss.

Note, the PM side is not yet implemented.

Signed-off-by: Denis Karpov 
Signed-off-by: Adrian Hunter 
---
 arch/arm/mach-omap2/mmc-twl4030.c |   15 +++
 arch/arm/plat-omap/include/mach/mmc.h |3 +++
 2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/mmc-twl4030.c 
b/arch/arm/mach-omap2/mmc-twl4030.c
index 1541fd4..5be3111 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -192,6 +192,18 @@ static int twl_mmc_resume(struct device *dev, int slot)
 #define twl_mmc_resume NULL
 #endif
 
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
+
+static int twl4030_mmc_get_context_loss(struct device *dev)
+{
+   /* FIXME: PM DPS not implemented yet */
+   return 0;
+}
+
+#else
+#define twl4030_mmc_get_context_loss NULL
+#endif
+
 static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
int vdd)
 {
@@ -384,6 +396,9 @@ void __init twl4030_mmc_init(struct twl4030_hsmmc_info 
*controllers)
} else
mmc->slots[0].switch_pin = -EINVAL;
 
+   mmc->get_context_loss_count =
+   twl4030_mmc_get_context_loss;
+
/* write protect normally uses an OMAP gpio */
if (gpio_is_valid(c->gpio_wp)) {
gpio_request(c->gpio_wp, "mmc_wp");
diff --git a/arch/arm/plat-omap/include/mach/mmc.h 
b/arch/arm/plat-omap/include/mach/mmc.h
index 81d5b36..2f7cf31 100644
--- a/arch/arm/plat-omap/include/mach/mmc.h
+++ b/arch/arm/plat-omap/include/mach/mmc.h
@@ -59,6 +59,9 @@ struct omap_mmc_platform_data {
int (*suspend)(struct device *dev, int slot);
int (*resume)(struct device *dev, int slot);
 
+   /* Return context loss count due to PM states changing */
+   int (*get_context_loss_count)(struct device *dev);
+
u64 dma_mask;
 
struct omap_mmc_slot_data {
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 10/32] omap_hsmmc: make use of new enable/disable interface

2009-07-10 Thread Adrian Hunter
>From 9b89eb8712def837ddfd40819ae578656ea893cb Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Thu, 23 Apr 2009 10:01:29 +0300
Subject: [PATCH] omap_hsmmc: make use of new enable/disable interface

For the moment enable / disable just turns the fclk
on and off.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   68 +++--
 1 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index cbd8376..0fded10 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -598,7 +598,9 @@ static void mmc_omap_detect(struct work_struct *work)
if (host->carddetect) {
mmc_detect_change(host->mmc, (HZ * 200) / 1000);
} else {
+   mmc_host_enable(host->mmc);
mmc_omap_reset_controller_fsm(host, SRD);
+   mmc_host_lazy_disable(host->mmc);
mmc_detect_change(host->mmc, (HZ * 50) / 1000);
}
 }
@@ -811,6 +813,27 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct 
mmc_request *req)
return 0;
 }
 
+static int omap_mmc_enable(struct mmc_host *mmc)
+{
+   struct mmc_omap_host *host = mmc_priv(mmc);
+   int err;
+
+   err = clk_enable(host->fclk);
+   if (err)
+   return err;
+   dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
+   return 0;
+}
+
+static int omap_mmc_disable(struct mmc_host *mmc, int lazy)
+{
+   struct mmc_omap_host *host = mmc_priv(mmc);
+
+   clk_disable(host->fclk);
+   dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n");
+   return 0;
+}
+
 /*
  * Request function. for read/write operation
  */
@@ -834,6 +857,8 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct 
mmc_ios *ios)
unsigned long timeout;
u32 con;
 
+   mmc_host_enable(host->mmc);
+
switch (ios->power_mode) {
case MMC_POWER_OFF:
mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
@@ -912,6 +937,8 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct 
mmc_ios *ios)
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) | OD);
+
+   mmc_host_lazy_disable(host->mmc);
 }
 
 static int omap_hsmmc_get_cd(struct mmc_host *mmc)
@@ -962,6 +989,8 @@ static void omap_hsmmc_init(struct mmc_omap_host *host)
 }
 
 static struct mmc_host_ops mmc_omap_ops = {
+   .enable = omap_mmc_enable,
+   .disable = omap_mmc_disable,
.request = omap_mmc_request,
.set_ios = omap_mmc_set_ios,
.get_cd = omap_hsmmc_get_cd,
@@ -976,7 +1005,16 @@ static int mmc_regs_show(struct seq_file *s, void *data)
struct mmc_host *mmc = s->private;
struct mmc_omap_host *host = mmc_priv(mmc);
 
-   seq_printf(s, "mmc%d regs:\n", mmc->index);
+   seq_printf(s, "mmc%d:\n"
+   " enabled:\t%d\n"
+   " nesting_cnt:\t%d\n"
+   "\nregs:\n",
+   mmc->index, mmc->enabled ? 1 : 0, mmc->nesting_cnt);
+
+   if (clk_enable(host->fclk) != 0) {
+   seq_printf(s, "can't read the regs\n");
+   goto err;
+   }
 
seq_printf(s, "SYSCONFIG:\t0x%08x\n",
OMAP_HSMMC_READ(host->base, SYSCONFIG));
@@ -992,6 +1030,9 @@ static int mmc_regs_show(struct seq_file *s, void *data)
OMAP_HSMMC_READ(host->base, ISE));
seq_printf(s, "CAPA:\t\t0x%08x\n",
OMAP_HSMMC_READ(host->base, CAPA));
+
+   clk_disable(host->fclk);
+err:
return 0;
 }
 
@@ -1092,14 +1133,16 @@ static int __init omap_mmc_probe(struct platform_device 
*pdev)
goto err1;
}
 
-   if (clk_enable(host->fclk) != 0) {
+   mmc->caps |= MMC_CAP_DISABLE;
+   mmc_set_disable_delay(mmc, msecs_to_jiffies(100));
+   if (mmc_host_enable(host->mmc) != 0) {
clk_put(host->iclk);
clk_put(host->fclk);
goto err1;
}
 
if (clk_enable(host->iclk) != 0) {
-   clk_disable(host->fclk);
+   mmc_host_disable(host->mmc);
clk_put(host->iclk);
clk_put(host->fclk);
goto err1;
@@ -1190,6 +1233,8 @@ static int __init omap_mmc_probe(struct platform_device 
*pdev)
OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
 
+   mmc_host_lazy_disable(host->mmc);
+
mmc_add_host(mmc);
 
if (host->pdata->slots[host->slot_id].name != NULL) {
@@ -1218,7 +1263,7 @@ err_irq_cd:
 err_irq_cd_init:
free_irq(host->irq, host);
 err_irq:
-   clk_disable(host->fclk);
+   mmc_host_disable(host->mmc);
clk_disable(host->iclk);
clk_put(host->fclk);
clk_put(host->iclk);
@@ -1243,

[PATCH 9/32] omap_hsmmc: add debugfs entry (host registers)

2009-07-10 Thread Adrian Hunter
>From 4951591bffd4c215e4d74e13fc46f0a625264288 Mon Sep 17 00:00:00 2001
From: Denis Karpov 
Date: Wed, 22 Apr 2009 14:21:34 +0200
Subject: [PATCH] omap_hsmmc: add debugfs entry (host registers)

Adds /kernel/debug/mmc/regs entry,
contents show registers' state and some driver internal
state variables.

Signed-off-by: Denis Karpov 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/host/omap_hsmmc.c |   57 +
 1 files changed, 57 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 1cf9cfb..cbd8376 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -17,6 +17,8 @@
 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -967,6 +969,59 @@ static struct mmc_host_ops mmc_omap_ops = {
/* NYET -- enable_sdio_irq */
 };
 
+#ifdef CONFIG_DEBUG_FS
+
+static int mmc_regs_show(struct seq_file *s, void *data)
+{
+   struct mmc_host *mmc = s->private;
+   struct mmc_omap_host *host = mmc_priv(mmc);
+
+   seq_printf(s, "mmc%d regs:\n", mmc->index);
+
+   seq_printf(s, "SYSCONFIG:\t0x%08x\n",
+   OMAP_HSMMC_READ(host->base, SYSCONFIG));
+   seq_printf(s, "CON:\t\t0x%08x\n",
+   OMAP_HSMMC_READ(host->base, CON));
+   seq_printf(s, "HCTL:\t\t0x%08x\n",
+   OMAP_HSMMC_READ(host->base, HCTL));
+   seq_printf(s, "SYSCTL:\t\t0x%08x\n",
+   OMAP_HSMMC_READ(host->base, SYSCTL));
+   seq_printf(s, "IE:\t\t0x%08x\n",
+   OMAP_HSMMC_READ(host->base, IE));
+   seq_printf(s, "ISE:\t\t0x%08x\n",
+   OMAP_HSMMC_READ(host->base, ISE));
+   seq_printf(s, "CAPA:\t\t0x%08x\n",
+   OMAP_HSMMC_READ(host->base, CAPA));
+   return 0;
+}
+
+static int mmc_regs_open(struct inode *inode, struct file *file)
+{
+   return single_open(file, mmc_regs_show, inode->i_private);
+}
+
+static const struct file_operations mmc_regs_fops = {
+   .open   = mmc_regs_open,
+   .read   = seq_read,
+   .llseek = seq_lseek,
+   .release= single_release,
+};
+
+static void omap_mmc_debugfs(struct mmc_host *mmc)
+{
+   if (mmc->debugfs_root)
+   debugfs_create_file("regs", S_IRUSR, mmc->debugfs_root,
+   mmc, &mmc_regs_fops);
+}
+
+#else
+
+static void omap_mmc_debugfs(struct mmc_host *mmc)
+{
+}
+
+#endif
+
 static int __init omap_mmc_probe(struct platform_device *pdev)
 {
struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
@@ -1150,6 +1205,8 @@ static int __init omap_mmc_probe(struct platform_device 
*pdev)
goto err_cover_switch;
}
 
+   omap_mmc_debugfs(mmc);
+
return 0;
 
 err_cover_switch:
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 5/32] mmc: add mmc card sleep and awake support

2009-07-10 Thread Adrian Hunter
>From b2f023bed880e3560aaa7de5caa6f899d79840f5 Mon Sep 17 00:00:00 2001
From: Jarkko Lavinen 
Date: Tue, 12 May 2009 19:46:14 +0300
Subject: [PATCH] mmc: add mmc card sleep and awake support

Add support for the new MMC command SLEEP_AWAKE.

Signed-off-by: Jarkko Lavinen 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/core/core.c|   40 
 drivers/mmc/core/core.h|2 +
 drivers/mmc/core/mmc.c |   54 +++
 drivers/mmc/core/mmc_ops.c |   36 +
 drivers/mmc/core/mmc_ops.h |1 +
 include/linux/mmc/card.h   |2 +
 include/linux/mmc/host.h   |5 
 include/linux/mmc/mmc.h|2 +
 8 files changed, 137 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b76a0f7..1461025 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1176,6 +1176,46 @@ void mmc_power_restore_host(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_power_restore_host);
 
+int mmc_card_awake(struct mmc_host *host)
+{
+   int err = -ENOSYS;
+
+   mmc_bus_get(host);
+
+   if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
+   err = host->bus_ops->awake(host);
+
+   mmc_bus_put(host);
+
+   return err;
+}
+EXPORT_SYMBOL(mmc_card_awake);
+
+int mmc_card_sleep(struct mmc_host *host)
+{
+   int err = -ENOSYS;
+
+   mmc_bus_get(host);
+
+   if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
+   err = host->bus_ops->sleep(host);
+
+   mmc_bus_put(host);
+
+   return err;
+}
+EXPORT_SYMBOL(mmc_card_sleep);
+
+int mmc_card_can_sleep(struct mmc_host *host)
+{
+   struct mmc_card *card = host->card;
+
+   if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
+   return 1;
+   return 0;
+}
+EXPORT_SYMBOL(mmc_card_can_sleep);
+
 #ifdef CONFIG_PM
 
 /**
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index f7eb4c4..c386348 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -16,6 +16,8 @@
 #define MMC_CMD_RETRIES3
 
 struct mmc_bus_ops {
+   int (*awake)(struct mmc_host *);
+   int (*sleep)(struct mmc_host *);
void (*remove)(struct mmc_host *);
void (*detect)(struct mmc_host *);
void (*suspend)(struct mmc_host *);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 01f7226..8e2e3d2 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -160,7 +160,6 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 {
int err;
u8 *ext_csd;
-   unsigned int ext_csd_struct;
 
BUG_ON(!card);
 
@@ -207,16 +206,16 @@ static int mmc_read_ext_csd(struct mmc_card *card)
goto out;
}
 
-   ext_csd_struct = ext_csd[EXT_CSD_REV];
-   if (ext_csd_struct > 3) {
+   card->ext_csd.rev = ext_csd[EXT_CSD_REV];
+   if (card->ext_csd.rev > 3) {
printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
"version %d\n", mmc_hostname(card->host),
-   ext_csd_struct);
+   card->ext_csd.rev);
err = -EINVAL;
goto out;
}
 
-   if (ext_csd_struct >= 2) {
+   if (card->ext_csd.rev >= 2) {
card->ext_csd.sectors =
ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
@@ -241,6 +240,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
goto out;
}
 
+   if (card->ext_csd.rev >= 3) {
+   u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
+
+   /* Sleep / awake timeout in 100ns units */
+   if (sa_shift > 0 && sa_shift <= 0x17)
+   card->ext_csd.sa_timeout =
+   1 << ext_csd[EXT_CSD_S_A_TIMEOUT];
+   }
+
 out:
kfree(ext_csd);
 
@@ -557,9 +565,41 @@ static void mmc_power_restore(struct mmc_host *host)
mmc_release_host(host);
 }
 
+static int mmc_sleep(struct mmc_host *host)
+{
+   struct mmc_card *card = host->card;
+   int err = -ENOSYS;
+
+   if (card && card->ext_csd.rev >= 3) {
+   err = mmc_card_sleepawake(host, 1);
+   if (err < 0)
+   pr_debug("%s: Error %d while putting card into sleep",
+mmc_hostname(host), err);
+   }
+
+   return err;
+}
+
+static int mmc_awake(struct mmc_host *host)
+{
+   struct mmc_card *card = host->card;
+   int err = -ENOSYS;
+
+   if (card && card->ext_csd.rev >= 3) {
+   err = mmc_card_sleepawake(host, 0);
+   if (err < 0)
+   pr_debug("%s: Error %d while awaking sleeping card",
+mmc_hostname(host), err);
+   }
+
+   return err;
+}
+
 #ifdef CONFIG_MMC_UNSAFE_RESUME
 
 static const struct

[PATCH 7/32] mmc: add host capabilities for SD only and MMC only

2009-07-10 Thread Adrian Hunter
>From 27ed1443884c0e46855485cfc2190e1d80a0f568 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Tue, 7 Jul 2009 12:20:48 +0300
Subject: [PATCH] mmc: add host capabilities for SD only and MMC only

Some hosts can accept only certain types of cards.
For example, an eMMC is MMC only and a uSD slot may
be SD only.  However the MMC card scanning logic
checks for all card types one by one.

Add host capabilities to specify which card types
cannot be used, and amend the card scanning logic
to skip scanning for those types.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/core/core.c  |   16 +++-
 include/linux/mmc/host.h |7 +++
 2 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c5a7857..db43a1d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1066,7 +1066,11 @@ void mmc_rescan(struct work_struct *work)
mmc_power_up(host);
mmc_go_idle(host);
 
-   mmc_send_if_cond(host, host->ocr_avail);
+   if (!(host->caps & MMC_CAP_NOT_SDIO) || !(host->caps & MMC_CAP_NOT_SD))
+   mmc_send_if_cond(host, host->ocr_avail);
+
+   if (host->caps & MMC_CAP_NOT_SDIO)
+   goto not_sdio;
 
/*
 * First we search for SDIO...
@@ -1078,6 +1082,10 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
 
+not_sdio:
+   if (host->caps & MMC_CAP_NOT_SD)
+   goto not_sd;
+
/*
 * ...then normal SD...
 */
@@ -1088,6 +1096,10 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
 
+not_sd:
+   if (host->caps & MMC_CAP_NOT_MMC)
+   goto not_mmc;
+
/*
 * ...and finally MMC.
 */
@@ -1098,6 +1110,8 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
 
+not_mmc:
+
mmc_release_host(host);
mmc_power_off(host);
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 0a60b02..e996967 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -150,6 +150,13 @@ struct mmc_host {
 #define MMC_CAP_DISABLE(1 << 7)/* Can the host be 
disabled */
 #define MMC_CAP_NONREMOVABLE   (1 << 8)/* Nonremovable e.g. eMMC */
 #define MMC_CAP_WAIT_WHILE_BUSY(1 << 9)/* Waits while card is 
busy */
+#define MMC_CAP_NOT_SDIO   (1 << 10)   /* Card cannot be SDIO */
+#define MMC_CAP_NOT_SD (1 << 11)   /* Card cannot be SD */
+#define MMC_CAP_NOT_MMC(1 << 12)   /* Card cannot be MMC */
+
+#define MMC_CAP_SDIO_ONLY  (MMC_CAP_NOT_SD | MMC_CAP_NOT_MMC)
+#define MMC_CAP_SD_ONLY(MMC_CAP_NOT_SDIO | MMC_CAP_NOT_MMC)
+#define MMC_CAP_MMC_ONLY   (MMC_CAP_NOT_SDIO | MMC_CAP_NOT_SD)
 
/* host specific block data */
unsigned intmax_seg_size;   /* see 
blk_queue_max_segment_size */
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 6/32] mmc: power off once at removal

2009-07-10 Thread Adrian Hunter
>From 72aa4541a135f40ebe41e67680be912ad56a076f Mon Sep 17 00:00:00 2001
From: Denis Karpov 
Date: Thu, 14 May 2009 09:11:38 +0200
Subject: [PATCH] mmc: power off once at removal

Fix MMC host stop sequence: power off once.

Signed-off-by: Denis Karpov 
Signed-off-by: Adrian Hunter 
---
 drivers/mmc/core/core.c |2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1461025..c5a7857 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1134,6 +1134,8 @@ void mmc_stop_host(struct mmc_host *host)
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_release_host(host);
+   mmc_bus_put(host);
+   return;
}
mmc_bus_put(host);
 
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/32] mmc: add ability to save power by powering off cards

2009-07-10 Thread Adrian Hunter
>From dd860f790842933bb4b4ece789b895115ecd1be8 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Mon, 11 May 2009 12:20:57 +0300
Subject: [PATCH] mmc: add ability to save power by powering off cards

Power can be saved by powering off cards that are not
in use.  This is similar to suspend / resume except
it is under the control of the driver, and does not
require any power management support.  It can only
be used when the driver can monitor whether the card
is removed, otherwise it is unsafe.  This is possible
because, unlike suspend, the driver still receives
card detect and / or cover switch interrupts.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/core/core.c  |   34 ++
 drivers/mmc/core/core.h  |2 ++
 drivers/mmc/core/mmc.c   |   11 +++
 drivers/mmc/core/sd.c|   11 +++
 include/linux/mmc/host.h |3 +++
 5 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b262dc6..b76a0f7 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1142,6 +1142,40 @@ void mmc_stop_host(struct mmc_host *host)
mmc_power_off(host);
 }
 
+void mmc_power_save_host(struct mmc_host *host)
+{
+   mmc_bus_get(host);
+
+   if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
+   mmc_bus_put(host);
+   return;
+   }
+
+   if (host->bus_ops->power_save)
+   host->bus_ops->power_save(host);
+
+   mmc_bus_put(host);
+
+   mmc_power_off(host);
+}
+EXPORT_SYMBOL(mmc_power_save_host);
+
+void mmc_power_restore_host(struct mmc_host *host)
+{
+   mmc_bus_get(host);
+
+   if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
+   mmc_bus_put(host);
+   return;
+   }
+
+   mmc_power_up(host);
+   host->bus_ops->power_restore(host);
+
+   mmc_bus_put(host);
+}
+EXPORT_SYMBOL(mmc_power_restore_host);
+
 #ifdef CONFIG_PM
 
 /**
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index c819eff..f7eb4c4 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -20,6 +20,8 @@ struct mmc_bus_ops {
void (*detect)(struct mmc_host *);
void (*suspend)(struct mmc_host *);
void (*resume)(struct mmc_host *);
+   void (*power_save)(struct mmc_host *);
+   void (*power_restore)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 3e35075..01f7226 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -549,6 +549,14 @@ static void mmc_resume(struct mmc_host *host)
 
 }
 
+static void mmc_power_restore(struct mmc_host *host)
+{
+   host->card->state &= ~MMC_STATE_HIGHSPEED;
+   mmc_claim_host(host);
+   mmc_init_card(host, host->ocr, host->card);
+   mmc_release_host(host);
+}
+
 #ifdef CONFIG_MMC_UNSAFE_RESUME
 
 static const struct mmc_bus_ops mmc_ops = {
@@ -556,6 +564,7 @@ static const struct mmc_bus_ops mmc_ops = {
.detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
+   .power_restore = mmc_power_restore,
 };
 
 static void mmc_attach_bus_ops(struct mmc_host *host)
@@ -570,6 +579,7 @@ static const struct mmc_bus_ops mmc_ops = {
.detect = mmc_detect,
.suspend = NULL,
.resume = NULL,
+   .power_restore = mmc_power_restore,
 };
 
 static const struct mmc_bus_ops mmc_ops_unsafe = {
@@ -577,6 +587,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
.detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
+   .power_restore = mmc_power_restore,
 };
 
 static void mmc_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 80cccd2..debe26e 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -603,6 +603,14 @@ static void mmc_sd_resume(struct mmc_host *host)
 
 }
 
+static void mmc_sd_power_restore(struct mmc_host *host)
+{
+   host->card->state &= ~MMC_STATE_HIGHSPEED;
+   mmc_claim_host(host);
+   mmc_sd_init_card(host, host->ocr, host->card);
+   mmc_release_host(host);
+}
+
 #ifdef CONFIG_MMC_UNSAFE_RESUME
 
 static const struct mmc_bus_ops mmc_sd_ops = {
@@ -610,6 +618,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
.detect = mmc_sd_detect,
.suspend = mmc_sd_suspend,
.resume = mmc_sd_resume,
+   .power_restore = mmc_sd_power_restore,
 };
 
 static void mmc_sd_attach_bus_ops(struct mmc_host *host)
@@ -624,6 +633,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
.detect = mmc_sd_detect,
.suspend = NULL,
.resume = NULL,
+   .power_restore = mmc_sd_power_restore,
 };
 
 static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
@@ -631,6 +641,7 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
.detect = mmc_sd_detect

[PATCH 1/32] mmc: add 'enable' and 'disable' methods to mmc host

2009-07-10 Thread Adrian Hunter
>From a0164897276e4d1f972fd90b1e9499e1ab8d221e Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Wed, 22 Apr 2009 12:50:45 +0300
Subject: [PATCH] mmc: add 'enable' and 'disable' methods to mmc host

MMC hosts that support power saving can use the 'enable' and
'disable' methods to exit and enter power saving states.
An explanation of their use is provided in the comments
added to include/linux/mmc/host.h.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/core/core.c  |  174 --
 drivers/mmc/core/host.c  |1 +
 drivers/mmc/core/host.h  |2 +
 include/linux/mmc/host.h |   47 
 4 files changed, 218 insertions(+), 6 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index d84c880..41fd127 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -344,6 +344,98 @@ unsigned int mmc_align_data_size(struct mmc_card *card, 
unsigned int sz)
 EXPORT_SYMBOL(mmc_align_data_size);
 
 /**
+ * mmc_host_enable - enable a host.
+ * @host: mmc host to enable
+ *
+ * Hosts that support power saving can use the 'enable' and 'disable'
+ * methods to exit and enter power saving states. For more information
+ * see comments for struct mmc_host_ops.
+ */
+int mmc_host_enable(struct mmc_host *host)
+{
+   if (!(host->caps & MMC_CAP_DISABLE))
+   return 0;
+
+   if (host->en_dis_recurs)
+   return 0;
+
+   if (host->nesting_cnt++)
+   return 0;
+
+   cancel_delayed_work_sync(&host->disable);
+
+   if (host->enabled)
+   return 0;
+
+   if (host->ops->enable) {
+   int err;
+
+   host->en_dis_recurs = 1;
+   err = host->ops->enable(host);
+   host->en_dis_recurs = 0;
+
+   if (err) {
+   pr_debug("%s: enable error %d\n",
+mmc_hostname(host), err);
+   return err;
+   }
+   }
+   host->enabled = 1;
+   return 0;
+}
+EXPORT_SYMBOL(mmc_host_enable);
+
+static int mmc_host_do_disable(struct mmc_host *host, int lazy)
+{
+   if (host->ops->disable) {
+   int err;
+
+   host->en_dis_recurs = 1;
+   err = host->ops->disable(host, lazy);
+   host->en_dis_recurs = 0;
+
+   if (err < 0) {
+   pr_debug("%s: disable error %d\n",
+mmc_hostname(host), err);
+   return err;
+   }
+   if (err > 0)
+   mmc_schedule_delayed_work(&host->disable, err);
+   }
+   host->enabled = 0;
+   return 0;
+}
+
+/**
+ * mmc_host_disable - disable a host.
+ * @host: mmc host to disable
+ *
+ * Hosts that support power saving can use the 'enable' and 'disable'
+ * methods to exit and enter power saving states. For more information
+ * see comments for struct mmc_host_ops.
+ */
+int mmc_host_disable(struct mmc_host *host)
+{
+   int err;
+
+   if (!(host->caps & MMC_CAP_DISABLE))
+   return 0;
+
+   if (host->en_dis_recurs)
+   return 0;
+
+   if (--host->nesting_cnt)
+   return 0;
+
+   if (!host->enabled)
+   return 0;
+
+   err = mmc_host_do_disable(host, 0);
+   return err;
+}
+EXPORT_SYMBOL(mmc_host_disable);
+
+/**
  * __mmc_claim_host - exclusively claim a host
  * @host: mmc host to claim
  * @abort: whether or not the operation should be aborted
@@ -379,11 +471,81 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t 
*abort)
wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
+   if (!stop)
+   mmc_host_enable(host);
return stop;
 }
 
 EXPORT_SYMBOL(__mmc_claim_host);
 
+static int mmc_try_claim_host(struct mmc_host *host)
+{
+   int claimed_host = 0;
+   unsigned long flags;
+
+   spin_lock_irqsave(&host->lock, flags);
+   if (!host->claimed) {
+   host->claimed = 1;
+   claimed_host = 1;
+   }
+   spin_unlock_irqrestore(&host->lock, flags);
+   return claimed_host;
+}
+
+static void mmc_do_release_host(struct mmc_host *host)
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(&host->lock, flags);
+   host->claimed = 0;
+   spin_unlock_irqrestore(&host->lock, flags);
+
+   wake_up(&host->wq);
+}
+
+void mmc_host_deeper_disable(struct work_struct *work)
+{
+   struct mmc_host *host =
+   container_of(work, struct mmc_host, disable.work);
+
+   /* If the host is claimed then we do not want to disable it anymore */
+   if (!mmc_try_claim_host(host))
+   return;
+   mmc_host_do_disable(host, 1);
+   mmc_do_release_host(host);
+}
+
+/**
+ * mmc_host_lazy_disable - lazily disable a host.
+ * @host: mmc 

[PATCH 3/32] mmc: add MMC_CAP_NONREMOVABLE host capability

2009-07-10 Thread Adrian Hunter
>From 52fa498f893db9a7dc203cee36ad8889241ab0b0 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Mon, 11 May 2009 10:03:41 +0300
Subject: [PATCH] mmc: add MMC_CAP_NONREMOVABLE host capability

eMMC's are not removable, so unsafe resume is OK always.

To permit this a new host capability MMC_CAP_NONREMOVABLE
has been added and suspend / resume updated accordingly.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/core/mmc.c   |   41 ++---
 drivers/mmc/core/sd.c|   41 ++---
 include/linux/mmc/host.h |1 +
 3 files changed, 69 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 06084db..3e35075 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -507,8 +507,6 @@ static void mmc_detect(struct mmc_host *host)
}
 }
 
-#ifdef CONFIG_MMC_UNSAFE_RESUME
-
 /*
  * Suspend callback from host.
  */
@@ -551,20 +549,49 @@ static void mmc_resume(struct mmc_host *host)
 
 }
 
-#else
+#ifdef CONFIG_MMC_UNSAFE_RESUME
 
-#define mmc_suspend NULL
-#define mmc_resume NULL
+static const struct mmc_bus_ops mmc_ops = {
+   .remove = mmc_remove,
+   .detect = mmc_detect,
+   .suspend = mmc_suspend,
+   .resume = mmc_resume,
+};
 
-#endif
+static void mmc_attach_bus_ops(struct mmc_host *host)
+{
+   mmc_attach_bus(host, &mmc_ops);
+}
+
+#else
 
 static const struct mmc_bus_ops mmc_ops = {
.remove = mmc_remove,
.detect = mmc_detect,
+   .suspend = NULL,
+   .resume = NULL,
+};
+
+static const struct mmc_bus_ops mmc_ops_unsafe = {
+   .remove = mmc_remove,
+   .detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
 };
 
+static void mmc_attach_bus_ops(struct mmc_host *host)
+{
+   const struct mmc_bus_ops *bus_ops;
+
+   if (host->caps & MMC_CAP_NONREMOVABLE)
+   bus_ops = &mmc_ops_unsafe;
+   else
+   bus_ops = &mmc_ops;
+   mmc_attach_bus(host, bus_ops);
+}
+
+#endif
+
 /*
  * Starting point for MMC card init.
  */
@@ -575,7 +602,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
BUG_ON(!host);
WARN_ON(!host->claimed);
 
-   mmc_attach_bus(host, &mmc_ops);
+   mmc_attach_bus_ops(host);
 
/*
 * We need to get OCR a different way for SPI.
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index cd81c39..80cccd2 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -561,8 +561,6 @@ static void mmc_sd_detect(struct mmc_host *host)
}
 }
 
-#ifdef CONFIG_MMC_UNSAFE_RESUME
-
 /*
  * Suspend callback from host.
  */
@@ -605,20 +603,49 @@ static void mmc_sd_resume(struct mmc_host *host)
 
 }
 
-#else
+#ifdef CONFIG_MMC_UNSAFE_RESUME
 
-#define mmc_sd_suspend NULL
-#define mmc_sd_resume NULL
+static const struct mmc_bus_ops mmc_sd_ops = {
+   .remove = mmc_sd_remove,
+   .detect = mmc_sd_detect,
+   .suspend = mmc_sd_suspend,
+   .resume = mmc_sd_resume,
+};
 
-#endif
+static void mmc_sd_attach_bus_ops(struct mmc_host *host)
+{
+   mmc_attach_bus(host, &mmc_sd_ops);
+}
+
+#else
 
 static const struct mmc_bus_ops mmc_sd_ops = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
+   .suspend = NULL,
+   .resume = NULL,
+};
+
+static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
+   .remove = mmc_sd_remove,
+   .detect = mmc_sd_detect,
.suspend = mmc_sd_suspend,
.resume = mmc_sd_resume,
 };
 
+static void mmc_sd_attach_bus_ops(struct mmc_host *host)
+{
+   const struct mmc_bus_ops *bus_ops;
+
+   if (host->caps & MMC_CAP_NONREMOVABLE)
+   bus_ops = &mmc_sd_ops_unsafe;
+   else
+   bus_ops = &mmc_sd_ops;
+   mmc_attach_bus(host, bus_ops);
+}
+
+#endif
+
 /*
  * Starting point for SD card init.
  */
@@ -629,7 +656,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
BUG_ON(!host);
WARN_ON(!host->claimed);
 
-   mmc_attach_bus(host, &mmc_sd_ops);
+   mmc_sd_attach_bus_ops(host);
 
/*
 * We need to get OCR a different way for SPI.
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 9cc5be9..6847fce 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -148,6 +148,7 @@ struct mmc_host {
 #define MMC_CAP_NEEDS_POLL (1 << 5)/* Needs polling for 
card-detection */
 #define MMC_CAP_8_BIT_DATA (1 << 6)/* Can the host do 8 bit 
transfers */
 #define MMC_CAP_DISABLE(1 << 7)/* Can the host be 
disabled */
+#define MMC_CAP_NONREMOVABLE   (1 << 8)/* Nonremovable e.g. eMMC */
 
/* host specific block data */
unsigned intmax_seg_size;   /* see 
blk_queue_max_segment_size */
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/m

[PATCH 0/32] mmc and omap_hsmmc patches

2009-07-10 Thread Adrian Hunter
Hi Pierre

Here are 32 patches for mmc and omap_hsmmc.

Sorry there are so many.

They mostly relate to trying to save power.

They split into 2 groups: the first 8 affect mmc core only
and the remaining ones affect omap_hsmmc only.

They apply cleanly on top of Linux 2.6.31-rc2

Adrian Hunter (20):
  mmc: add 'enable' and 'disable' methods to mmc host
  mmc: allow host claim / release nesting
  mmc: add MMC_CAP_NONREMOVABLE host capability
  mmc: add ability to save power by powering off cards
  mmc: add host capabilities for SD only and MMC only
  mmc: check status after MMC SWITCH command
  omap_hsmmc: make use of new enable/disable interface
  omap_hsmmc: keep track of power mode
  omap_hsmmc: ensure workqueues are empty before suspend
  omap_hsmmc: make use of new MMC_CAP_NONREMOVABLE host capability
  ARM: OMAP: mmc-twl4030: add regulator sleep / wake function
  omap_hsmmc: put MMC regulator to sleep
  omap_hsmmc: clear interrupt status after init sequence
  omap_hsmmc: cater for weird CMD6 behaviour
  omap_hsmmc: prevent races with irq handler
  omap_hsmmc: pass host capabilities for SD only and MMC only
  omap_hsmmc: protect the card when the cover is open
  omap_hsmmc: ensure all clock enables and disables are paired
  omap_hsmmc: set a large data timeout for commands with busy signal
  ARM: OMAP: RX51: set MMC capabilities and power-saving flag

Denis Karpov (8):
  mmc: power off once at removal
  omap_hsmmc: add debugfs entry (host registers)
  ARM: OMAP: mmc-twl4030: add context loss counter support
  omap_hsmmc: context save/restore support
  omap_hsmmc: set open drain bit correctly
  omap_hsmmc: support for deeper power saving states
  omap_hsmmc: cleanup macro usage
  omap_hsmmc: code refactoring

Jarkko Lavinen (4):
  mmc: add mmc card sleep and awake support
  omap_hsmmc: fix scatter-gather list sanity checking
  omap_hsmmc: add mmc card sleep and awake support
  omap_hsmmc: fix NULL pointer dereference

 arch/arm/mach-omap2/board-rx51-peripherals.c |5 +
 arch/arm/mach-omap2/mmc-twl4030.c|   77 ++
 arch/arm/mach-omap2/mmc-twl4030.h|2 +
 arch/arm/plat-omap/include/mach/mmc.h|   11 +
 drivers/mmc/core/core.c  |  288 +++-
 drivers/mmc/core/core.h  |4 +
 drivers/mmc/core/host.c  |1 +
 drivers/mmc/core/host.h  |2 +
 drivers/mmc/core/mmc.c   |  130 +++-
 drivers/mmc/core/mmc_ops.c   |   59 ++
 drivers/mmc/core/mmc_ops.h   |1 +
 drivers/mmc/core/sd.c|   52 ++-
 drivers/mmc/host/omap_hsmmc.c| 1025 +-
 include/linux/mmc/card.h |2 +
 include/linux/mmc/core.h |1 +
 include/linux/mmc/host.h |   65 ++
 include/linux/mmc/mmc.h  |3 +
 17 files changed, 1512 insertions(+), 216 deletions(-)


Regards
Adrian
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/32] mmc: allow host claim / release nesting

2009-07-10 Thread Adrian Hunter
>From 2d65438fce412a63f09f90fb9af1049c775cbd70 Mon Sep 17 00:00:00 2001
From: Adrian Hunter 
Date: Mon, 27 Apr 2009 13:38:42 +0300
Subject: [PATCH] mmc: allow host claim / release nesting

This change allows the MMC host to be claimed in
situations where the host may or may not have
already been claimed.  Also 'mmc_try_claim_host()'
is now exported.

Signed-off-by: Adrian Hunter 
---
 drivers/mmc/core/core.c  |   34 +-
 include/linux/mmc/core.h |1 +
 include/linux/mmc/host.h |2 ++
 3 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 41fd127..b262dc6 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -458,16 +458,18 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t 
*abort)
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
stop = abort ? atomic_read(abort) : 0;
-   if (stop || !host->claimed)
+   if (stop || !host->claimed || host->claimer == current)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
-   if (!stop)
+   if (!stop) {
host->claimed = 1;
-   else
+   host->claimer = current;
+   host->claim_cnt += 1;
+   } else
wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
@@ -478,29 +480,43 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t 
*abort)
 
 EXPORT_SYMBOL(__mmc_claim_host);
 
-static int mmc_try_claim_host(struct mmc_host *host)
+/**
+ * mmc_try_claim_host - try exclusively to claim a host
+ * @host: mmc host to claim
+ *
+ * Returns %1 if the host is claimed, %0 otherwise.
+ */
+int mmc_try_claim_host(struct mmc_host *host)
 {
int claimed_host = 0;
unsigned long flags;
 
spin_lock_irqsave(&host->lock, flags);
-   if (!host->claimed) {
+   if (!host->claimed || host->claimer == current) {
host->claimed = 1;
+   host->claimer = current;
+   host->claim_cnt += 1;
claimed_host = 1;
}
spin_unlock_irqrestore(&host->lock, flags);
return claimed_host;
 }
+EXPORT_SYMBOL(mmc_try_claim_host);
 
 static void mmc_do_release_host(struct mmc_host *host)
 {
unsigned long flags;
 
spin_lock_irqsave(&host->lock, flags);
-   host->claimed = 0;
-   spin_unlock_irqrestore(&host->lock, flags);
-
-   wake_up(&host->wq);
+   if (--host->claim_cnt) {
+   /* Release for nested claim */
+   spin_unlock_irqrestore(&host->lock, flags);
+   } else {
+   host->claimed = 0;
+   host->claimer = NULL;
+   spin_unlock_irqrestore(&host->lock, flags);
+   wake_up(&host->wq);
+   }
 }
 
 void mmc_host_deeper_disable(struct work_struct *work)
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 7ac8b50..e4898e9 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -139,6 +139,7 @@ extern unsigned int mmc_align_data_size(struct mmc_card *, 
unsigned int);
 
 extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
 extern void mmc_release_host(struct mmc_host *host);
+extern int mmc_try_claim_host(struct mmc_host *host);
 
 /**
  * mmc_claim_host - exclusively claim a host
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 583c068..9cc5be9 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -182,6 +182,8 @@ struct mmc_host {
struct mmc_card *card;  /* device attached to this host 
*/
 
wait_queue_head_t   wq;
+   struct task_struct  *claimer;   /* task that has host claimed */
+   int claim_cnt;  /* "claim" nesting count */
 
struct delayed_work detect;
 
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2:2][MTD][NAND]omap : Adding DMA mode support in nand prefetch/post-write

2009-07-10 Thread Artem Bityutskiy
On Fri, 2009-07-10 at 17:25 +0530, vimal singh wrote:
> + /* The fifo depth is 64 bytes. We have a sync at each frame and frame
> +  * length is 64 bytes.
> +  */
> + int buf_len = len/64;

To optimize performance it is better not to rely on gcc and use <<

-- 
Best regards,
Artem Bityutskiy (Битюцкий Артём)

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2:2][MTD][NAND]omap : Adding DMA mode support in nand prefetch/post-write

2009-07-10 Thread vimal singh
This patch adds DMA mode support for nand prefetch/post-write engine.

Signed-off-by: Vimal Singh 
---

 drivers/mtd/nand/Kconfig |9 ++
 drivers/mtd/nand/omap2.c |  186 ++-
 2 files changed, 193 insertions(+), 2 deletions(-)

Index: mtd-2.6/drivers/mtd/nand/Kconfig
===
--- mtd-2.6.orig/drivers/mtd/nand/Kconfig
+++ mtd-2.6/drivers/mtd/nand/Kconfig
@@ -88,6 +88,15 @@ config MTD_NAND_OMAP_PREFETCH
 The NAND device can be accessed for Read/Write using GPMC PREFETCH 
engine
 to improve the performance.

+config MTD_NAND_OMAP_PREFETCH_DMA
+   depends on MTD_NAND_OMAP_PREFETCH
+   bool "DMA mode"
+   default n
+   help
+The GPMC PREFETCH engine can be configured eigther in MPU interrupt 
mode
+or in DMA interrupt mode.
+Say y for DMA mode or MPU mode will be used
+
 config MTD_NAND_TS7250
tristate "NAND Flash device on TS-7250 board"
depends on MACH_TS72XX
Index: mtd-2.6/drivers/mtd/nand/omap2.c
===
--- mtd-2.6.orig/drivers/mtd/nand/omap2.c
+++ mtd-2.6/drivers/mtd/nand/omap2.c
@@ -18,8 +18,7 @@
 #include 
 #include 

-#include 
-
+#include 
 #include 
 #include 

@@ -118,8 +117,19 @@ static int use_prefetch = 1;
 /* "modprobe ... use_prefetch=0" etc */
 module_param(use_prefetch, bool, 0);
 MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH");
+
+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
+static int use_dma = 1;
+
+/* "modprobe ... use_dma=0" etc */
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
+#else
+const int use_dma;
+#endif
 #else
 const int use_prefetch;
+const int use_dma;
 #endif

 struct omap_nand_info {
@@ -135,6 +145,8 @@ struct omap_nand_info {
void __iomem*gpmc_cs_baseaddr;
void __iomem*gpmc_baseaddr;
void __iomem*nand_pref_fifo_add;
+   struct completion   comp;
+   int dma_ch;
 };

 /**
@@ -356,6 +368,147 @@ static void omap_write_buf_pref(struct m
gpmc_prefetch_reset();
 }

+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
+/*
+ * omap_nand_dma_cb: callback on the completion of dma transfer
+ * @lch: logical channel
+ * @ch_satuts: channel status
+ * @data: pointer to completion data structure
+ */
+static void omap_nand_dma_cb(int lch, u16 ch_status, void *data)
+{
+   complete((struct completion *) data);
+}
+
+/*
+ * omap_nand_dma_transfer: configer and start dma transfer
+ * @mtd: MTD device structure
+ * @addr: virtual address in RAM of source/destination
+ * @len: number of data bytes to be transferred
+ * @is_write: flag for read/write operation
+ */
+static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+   unsigned int len, int is_write)
+{
+   struct omap_nand_info *info = container_of(mtd,
+   struct omap_nand_info, mtd);
+   uint32_t prefetch_status = 0;
+   enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
+   DMA_FROM_DEVICE;
+   dma_addr_t dma_addr;
+   int ret;
+
+   /* The fifo depth is 64 bytes. We have a sync at each frame and frame
+* length is 64 bytes.
+*/
+   int buf_len = len/64;
+
+   if (addr >= high_memory) {
+   struct page *p1;
+
+   if (((size_t)addr & PAGE_MASK) !=
+   ((size_t)(addr + len - 1) & PAGE_MASK))
+   goto out_copy;
+   p1 = vmalloc_to_page(addr);
+   if (!p1)
+   goto out_copy;
+   addr = page_address(p1) + ((size_t)addr & ~PAGE_MASK);
+   }
+
+   dma_addr = dma_map_single(&info->pdev->dev, addr, len, dir);
+   if (dma_mapping_error(&info->pdev->dev, dma_addr)) {
+   dev_err(&info->pdev->dev,
+   "Couldn't DMA map a %d byte buffer\n", len);
+   goto out_copy;
+   }
+
+   if (is_write) {
+   omap_set_dma_dest_params(info->dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
+   info->phys_base, 0, 0);
+   omap_set_dma_src_params(info->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
+   dma_addr, 0, 0);
+   omap_set_dma_transfer_params(info->dma_ch, OMAP_DMA_DATA_TYPE_S32,
+   0x10, buf_len, OMAP_DMA_SYNC_FRAME,
+   OMAP24XX_DMA_GPMC, OMAP_DMA_DST_SYNC);
+   } else {
+   omap_set_dma_src_params(info->dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
+   info->phys_base, 0, 0);
+   omap_set_dma_dest_params(info->dma_ch, 0, OMAP_DMA_AMODE_POST

[PATCH 1:2] [MTD][NAND]omap: Adding support for nand prefetch-read and post-write, in MPU mode.

2009-07-10 Thread vimal singh
This patch adds prefetch support to access nand flash in mpu mode.
This patch also adds 8-bit nand support (omap_read/write_buf8).
Prefetch can be used for both 8- and 16-bit devices.

Signed-off-by: Vimal Singh 
---

 arch/arm/mach-omap2/gpmc.c |   63 -
 arch/arm/plat-omap/include/mach/gpmc.h |4
 drivers/mtd/nand/Kconfig   |8 +
 drivers/mtd/nand/omap2.c   |  158 +++--
 4 files changed, 225 insertions(+), 8 deletions(-)

Index: mtd-2.6/arch/arm/mach-omap2/gpmc.c
===
--- mtd-2.6.orig/arch/arm/mach-omap2/gpmc.c
+++ mtd-2.6/arch/arm/mach-omap2/gpmc.c
@@ -57,6 +57,11 @@
 #define GPMC_CHUNK_SHIFT   24  /* 16 MB */
 #define GPMC_SECTION_SHIFT 28  /* 128 MB */

+#define PREFETCH_FIFOTHRESHOLD (0x40 << 8)
+#define CS_NUM_SHIFT   24
+#define ENABLE_PREFETCH(0x1 << 7)
+#define DMA_MPU_MODE   2
+
 static struct resource gpmc_mem_root;
 static struct resource gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -386,6 +391,63 @@ void gpmc_cs_free(int cs)
 }
 EXPORT_SYMBOL(gpmc_cs_free);

+/**
+ * gpmc_prefetch_enable - configures and starts prefetch transfer
+ * @cs: nand cs (chip select) number
+ * @dma_mode: dma mode enable (1) or disable (0)
+ * @u32_count: number of bytes to be transferred
+ * @is_write: prefetch read(0) or write post(1) mode
+ */
+int gpmc_prefetch_enable(int cs, int dma_mode,
+   unsigned int u32_count, int is_write)
+{
+   uint32_t prefetch_config1;
+
+   if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
+   /* Set the amount of bytes to be prefetched */
+   gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
+
+   /* Set dma/mpu mode, the prefetch read / post write and
+* enable the engine. Set which cs is has requested for.
+*/
+   prefetch_config1 = ((cs << CS_NUM_SHIFT) |
+   PREFETCH_FIFOTHRESHOLD |
+   ENABLE_PREFETCH |
+   (dma_mode << DMA_MPU_MODE) |
+   (0x1 & is_write));
+   gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1);
+   } else {
+   return -EBUSY;
+   }
+   /*  Start the prefetch engine */
+   gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1);
+
+   return 0;
+}
+EXPORT_SYMBOL(gpmc_prefetch_enable);
+
+/**
+ * gpmc_prefetch_reset - disables and stops the prefetch engine
+ */
+void gpmc_prefetch_reset(void)
+{
+   /* Stop the PFPW engine */
+   gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
+
+   /* Reset/disable the PFPW engine */
+   gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
+}
+EXPORT_SYMBOL(gpmc_prefetch_reset);
+
+/**
+ * gpmc_prefetch_status - reads prefetch status of engine
+ */
+int  gpmc_prefetch_status(void)
+{
+   return gpmc_read_reg(GPMC_PREFETCH_STATUS);
+}
+EXPORT_SYMBOL(gpmc_prefetch_status);
+
 static void __init gpmc_mem_init(void)
 {
int cs;
@@ -452,6 +514,5 @@ void __init gpmc_init(void)
l &= 0x03 << 3;
l |= (0x02 << 3) | (1 << 0);
gpmc_write_reg(GPMC_SYSCONFIG, l);
-
gpmc_mem_init();
 }
Index: mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h
===
--- mtd-2.6.orig/arch/arm/plat-omap/include/mach/gpmc.h
+++ mtd-2.6/arch/arm/plat-omap/include/mach/gpmc.h
@@ -103,6 +103,10 @@ extern int gpmc_cs_request(int cs, unsig
 extern void gpmc_cs_free(int cs);
 extern int gpmc_cs_set_reserved(int cs, int reserved);
 extern int gpmc_cs_reserved(int cs);
+extern int gpmc_prefetch_enable(int cs, int dma_mode,
+   unsigned int u32_count, int is_write);
+extern void gpmc_prefetch_reset(void);
+extern int gpmc_prefetch_status(void);
 extern void __init gpmc_init(void);

 #endif
Index: mtd-2.6/drivers/mtd/nand/Kconfig
===
--- mtd-2.6.orig/drivers/mtd/nand/Kconfig
+++ mtd-2.6/drivers/mtd/nand/Kconfig
@@ -80,6 +80,14 @@ config MTD_NAND_OMAP2
help
   Support for NAND flash on Texas Instruments OMAP2 and OMAP3 
platforms.

+config MTD_NAND_OMAP_PREFETCH
+   bool "GPMC prefetch support for NAND Flash device"
+   depends on MTD_NAND && MTD_NAND_OMAP2
+   default y
+   help
+The NAND device can be accessed for Read/Write using GPMC PREFETCH 
engine
+to improve the performance.
+
 config MTD_NAND_TS7250
tristate "NAND Flash device on TS-7250 board"
depends on MACH_TS72XX
Index: mtd-2.6/drivers/mtd/nand/omap2.c
===
--- mtd-2.6.orig/drivers/mtd/nand/omap2.c
+++ mtd-2.6/drivers/mtd/nand/omap2.c
@@ -112,6 +112,16 @@
 static const c

[PATCH v2] OMAP: timer-gp: Fix for null pointer dereferencing issue

2009-07-10 Thread Mittal, Mukund
From: Mukund Mittal 

OMAP: timer-gp: Fix for null pointer dereferencing issue

Calling WARN() to warn for null pointer dereferencing for gpt pointer. 

Signed-off-by: Mukund Mittal 
---
 arch/arm/mach-omap2/timer-gp.c |   14 +++---
 1 files changed, 7 insertions(+), 7 deletions(-)

Index: linux-omap-2.6/arch/arm/mach-omap2/timer-gp.c
===
--- linux-omap-2.6.orig/arch/arm/mach-omap2/timer-gp.c
+++ linux-omap-2.6/arch/arm/mach-omap2/timer-gp.c
@@ -205,14 +205,9 @@ static void __init omap2_gp_clocksource_
 {
static struct omap_dm_timer *gpt;
u32 tick_rate, tick_period;
-   static char err1[] __initdata = KERN_ERR
-   "%s: failed to request dm-timer\n";
-   static char err2[] __initdata = KERN_ERR
-   "%s: can't register clocksource!\n";
 
gpt = omap_dm_timer_request();
-   if (!gpt)
-   printk(err1, clocksource_gpt.name);
+   WARN(!gpt, "%s: failed to request dm-timer\n", clocksource_gpt.name);
gpt_clocksource = gpt;
 
omap_dm_timer_set_source(gpt, OMAP_TIMER_SRC_SYS_CLK);
@@ -224,7 +219,8 @@ static void __init omap2_gp_clocksource_
clocksource_gpt.mult =
clocksource_khz2mult(tick_rate/1000, clocksource_gpt.shift);
if (clocksource_register(&clocksource_gpt))
-   printk(err2, clocksource_gpt.name);
+   printk(KERN_ERR "%s: can't register clocksource!\n",
+   clocksource_gpt.name);
 }
 #endif
 
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/2] [MTD] [NAND] Add prefetch and dma support for omap2/3 NAND driver

2009-07-10 Thread vimal singh
Hi,

I have splited gpmc prefetch support for NAND into two patches:
[PATCH 1:2] : Adding support for nand prefetch-read and post-write, in MPU mode.
[PATCH 2:2] : Adding DMA mode support in nand prefetch/post-write

These patches implements Tony's comments. (For comments and discussion see:
http://lists.infradead.org/pipermail/linux-mtd/2009-June/025993.html)

Other than that, gpmc_prefetch_(inti/request) call has been removed, as nothing
great was done in that and we really do not need that.

Function 'gpmc_prefetch_enable' does check for 'if prefetch is already being
used by some other driver?'. And if it is busy, normal cpu copy method for
read/write request will be used.

Thanks and regards,
vimal




--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 8/8] ehci: Support for ES3.x

2009-07-10 Thread Ajay Kumar Gupta
OMAP ES3.x supports portwise PHY or TLL mode of operation whereas
in ES2.x all the three ports can either be in PHY mode or in TLL
mode.Port3 can not be configured in PHY mode.

Port mode must be defined either PHY, TLL or UNKNOWN in platform
files.Be careful of the scenario where one port is set as PHY and
other in TLL but the OMAP silicon version is 2.x or earlier where
this scenario is *not* supported.

Changes are :
- Setup all the bypass configuration in omap_start_ehc()
  based on ES version.
- Remove UHH_HOSTCONFIG programming for bypass settings
  in omap_usb_utmi_init()

Signed-off-by: Ajay Kumar Gupta 
---
 drivers/usb/host/ehci-omap.c |   90 --
 1 files changed, 52 insertions(+), 38 deletions(-)

diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index e64ba9f..c0f9a19 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -32,7 +32,6 @@
  * - move DPLL5 programming to clock fw
  * - add suspend/resume
  * - move workarounds to board-files
- * - differentiate between ES2.x and ES3.x
  * - make it enumerate devices
  */
 
@@ -103,6 +102,9 @@
 #defineOMAP_UHH_SYSSTATUS  (0x14)
 #defineOMAP_UHH_HOSTCONFIG (0x40)
 #defineOMAP_UHH_HOSTCONFIG_ULPI_BYPASS (1 << 0)
+#defineOMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS  (1 << 0)
+#defineOMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS  (1 << 11)
+#defineOMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS  (1 << 12)
 #define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN (1 << 2)
 #define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN (1 << 3)
 #define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN(1 << 4)
@@ -186,16 +188,6 @@ static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, 
u8 tll_channel_mask)
unsigned reg;
int i;
 
-   reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
-   reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS
-   | OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
-   | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
-   | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN;
-   reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
-
-   /* Use UTMI Ports of TLL */
-   ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
-
/* Program the 3 TLL channels upfront */
for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i));
@@ -244,7 +236,9 @@ static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, 
u8 tll_channel_mask)
  */
 static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
 {
+   struct omap_chip_id oci = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES3);
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+   u8 tll_ch_mask = 0;
unsigned reg = 0;
int ret = 0;
 
@@ -363,37 +357,58 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, 
struct usb_hcd *hcd)
 
ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
 
-   if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
-   (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
-   (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) {
+   reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
 
-   reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
+   /* setup ULPI bypass and burst configurations */
+   reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
+   | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
+   | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
+   reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
 
-   reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
-   | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
-   | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
-   reg &= ~(OMAP_UHH_HOSTCONFIG_ULPI_BYPASS
-   | OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN);
+   /* Bypass the TLL module for PHY mode operation */
+   if (omap_chip_is(oci)) {
+   dev_dbg(omap->dev, "OMAP3 ES version > ES3\n");
+   if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
+   reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
+   else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
+   reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
 
-   /* Bypass the TLL module for PHY mode operation */
-   ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
-   dev_dbg(omap->dev, "Entered ULPI PHY MODE: success\n");
+   if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
+   reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS;
+   else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
+   re

[PATCH 2/8] ehci: adding mux pin for EHCI phy reset line

2009-07-10 Thread Ajay Kumar Gupta
GPIO135 is used as EHCI (port2) phy reset pin on Multi Media Daughter card
connected to OMAP3EVM.

Signed-off-by: Ajay Kumar Gupta 
---
Resubmitting so that all the patches are together.

 arch/arm/mach-omap2/mux.c |2 ++
 arch/arm/plat-omap/include/mach/mux.h |1 +
 2 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 026c4fc..80547cf 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -472,6 +472,8 @@ MUX_CFG_34XX("G25_34XX_GPIO86_OUT", 0x0fc,
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
 MUX_CFG_34XX("AG4_34XX_GPIO134_OUT", 0x160,
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AF4_34XX_GPIO135_OUT", 0x162,
+   OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
 MUX_CFG_34XX("AE4_34XX_GPIO136_OUT", 0x164,
OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
 MUX_CFG_34XX("AF6_34XX_GPIO140_UP", 0x16c,
diff --git a/arch/arm/plat-omap/include/mach/mux.h 
b/arch/arm/plat-omap/include/mach/mux.h
index 85a6217..498fa0c 100644
--- a/arch/arm/plat-omap/include/mach/mux.h
+++ b/arch/arm/plat-omap/include/mach/mux.h
@@ -846,6 +846,7 @@ enum omap34xx_index {
L8_34XX_GPIO63,
G25_34XX_GPIO86_OUT,
AG4_34XX_GPIO134_OUT,
+   AF4_34XX_GPIO135_OUT,
AE4_34XX_GPIO136_OUT,
AF6_34XX_GPIO140_UP,
AE6_34XX_GPIO141,
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/8] ehci: fix ehci pin mux init

2009-07-10 Thread Ajay Kumar Gupta
EHCI pin mux init fucntion is still using old #ifdef which are not defined
anymore.This causes pin mux init to always set TLL settings and thus EHCI
PHY mode doesn't work.

Fixing this issue by using phy_mode parameter to initialize mux settings.

Signed-off-by: Ajay Kumar Gupta 
Signed-off-by: Felipe Balbi 
---
Resubmitting so that all the patches are together.

 arch/arm/mach-omap2/usb-ehci.c |  167 
 1 files changed, 83 insertions(+), 84 deletions(-)

diff --git a/arch/arm/mach-omap2/usb-ehci.c b/arch/arm/mach-omap2/usb-ehci.c
index 0fe26f2..53e6e85 100644
--- a/arch/arm/mach-omap2/usb-ehci.c
+++ b/arch/arm/mach-omap2/usb-ehci.c
@@ -68,90 +68,89 @@ static struct platform_device ehci_device = {
 /*
  * setup_ehci_io_mux - initialize IO pad mux for USBHOST
  */
-static void setup_ehci_io_mux(void)
+static void setup_ehci_io_mux(enum ehci_hcd_omap_mode phy_mode)
 {
-#ifdef CONFIG_OMAP_EHCI_PHY_MODE
-   /* PHY mode of operation for board: 750-2083-001
-* ISP1504 connected to Port1 and Port2
-* Do Func Mux setting for 12-pin ULPI PHY mode
-*/
-
-   /* Port1 */
-   omap_cfg_reg(Y9_3430_USB1HS_PHY_STP);
-   omap_cfg_reg(Y8_3430_USB1HS_PHY_CLK);
-   omap_cfg_reg(AA14_3430_USB1HS_PHY_DIR);
-   omap_cfg_reg(AA11_3430_USB1HS_PHY_NXT);
-   omap_cfg_reg(W13_3430_USB1HS_PHY_DATA0);
-   omap_cfg_reg(W12_3430_USB1HS_PHY_DATA1);
-   omap_cfg_reg(W11_3430_USB1HS_PHY_DATA2);
-   omap_cfg_reg(Y11_3430_USB1HS_PHY_DATA3);
-   omap_cfg_reg(W9_3430_USB1HS_PHY_DATA4);
-   omap_cfg_reg(Y12_3430_USB1HS_PHY_DATA5);
-   omap_cfg_reg(W8_3430_USB1HS_PHY_DATA6);
-   omap_cfg_reg(Y13_3430_USB1HS_PHY_DATA7);
-
-   /* Port2 */
-   omap_cfg_reg(AA10_3430_USB2HS_PHY_STP);
-   omap_cfg_reg(AA8_3430_USB2HS_PHY_CLK);
-   omap_cfg_reg(AA9_3430_USB2HS_PHY_DIR);
-   omap_cfg_reg(AB11_3430_USB2HS_PHY_NXT);
-   omap_cfg_reg(AB10_3430_USB2HS_PHY_DATA0);
-   omap_cfg_reg(AB9_3430_USB2HS_PHY_DATA1);
-   omap_cfg_reg(W3_3430_USB2HS_PHY_DATA2);
-   omap_cfg_reg(T4_3430_USB2HS_PHY_DATA3);
-   omap_cfg_reg(T3_3430_USB2HS_PHY_DATA4);
-   omap_cfg_reg(R3_3430_USB2HS_PHY_DATA5);
-   omap_cfg_reg(R4_3430_USB2HS_PHY_DATA6);
-   omap_cfg_reg(T2_3430_USB2HS_PHY_DATA7);
-
-#else
-   /* Set Func mux for :
-* TLL mode of operation
-* 12-pin ULPI SDR TLL mode for Port1/2/3
-*/
-
-   /* Port1 */
-   omap_cfg_reg(Y9_3430_USB1HS_TLL_STP);
-   omap_cfg_reg(Y8_3430_USB1HS_TLL_CLK);
-   omap_cfg_reg(AA14_3430_USB1HS_TLL_DIR);
-   omap_cfg_reg(AA11_3430_USB1HS_TLL_NXT);
-   omap_cfg_reg(W13_3430_USB1HS_TLL_DATA0);
-   omap_cfg_reg(W12_3430_USB1HS_TLL_DATA1);
-   omap_cfg_reg(W11_3430_USB1HS_TLL_DATA2);
-   omap_cfg_reg(Y11_3430_USB1HS_TLL_DATA3);
-   omap_cfg_reg(W9_3430_USB1HS_TLL_DATA4);
-   omap_cfg_reg(Y12_3430_USB1HS_TLL_DATA5);
-   omap_cfg_reg(W8_3430_USB1HS_TLL_DATA6);
-   omap_cfg_reg(Y13_3430_USB1HS_TLL_DATA7);
-
-   /* Port2 */
-   omap_cfg_reg(AA10_3430_USB2HS_TLL_STP);
-   omap_cfg_reg(AA8_3430_USB2HS_TLL_CLK);
-   omap_cfg_reg(AA9_3430_USB2HS_TLL_DIR);
-   omap_cfg_reg(AB11_3430_USB2HS_TLL_NXT);
-   omap_cfg_reg(AB10_3430_USB2HS_TLL_DATA0);
-   omap_cfg_reg(AB9_3430_USB2HS_TLL_DATA1);
-   omap_cfg_reg(W3_3430_USB2HS_TLL_DATA2);
-   omap_cfg_reg(T4_3430_USB2HS_TLL_DATA3);
-   omap_cfg_reg(T3_3430_USB2HS_TLL_DATA4);
-   omap_cfg_reg(R3_3430_USB2HS_TLL_DATA5);
-   omap_cfg_reg(R4_3430_USB2HS_TLL_DATA6);
-   omap_cfg_reg(T2_3430_USB2HS_TLL_DATA7);
-
-   /* Port3 */
-   omap_cfg_reg(AB3_3430_USB3HS_TLL_STP);
-   omap_cfg_reg(AA6_3430_USB3HS_TLL_CLK);
-   omap_cfg_reg(AA3_3430_USB3HS_TLL_DIR);
-   omap_cfg_reg(Y3_3430_USB3HS_TLL_NXT);
-   omap_cfg_reg(AA5_3430_USB3HS_TLL_DATA0);
-   omap_cfg_reg(Y4_3430_USB3HS_TLL_DATA1);
-   omap_cfg_reg(Y5_3430_USB3HS_TLL_DATA2);
-   omap_cfg_reg(W5_3430_USB3HS_TLL_DATA3);
-   omap_cfg_reg(AB12_3430_USB3HS_TLL_DATA4);
-   omap_cfg_reg(AB13_3430_USB3HS_TLL_DATA5);
-   omap_cfg_reg(AA13_3430_USB3HS_TLL_DATA6);
-   omap_cfg_reg(AA12_3430_USB3HS_TLL_DATA7);
-#endif /* CONFIG_OMAP_EHCI_PHY_MODE */
+   if (phy_mode == EHCI_HCD_OMAP_MODE_PHY) {
+   /* PHY mode of operation for board: 750-2083-001
+* ISP1504 connected to Port1 and Port2
+* Do Func Mux setting for 12-pin ULPI PHY mode
+*/
+   /* Port1 */
+   omap_cfg_reg(Y9_3430_USB1HS_PHY_STP);
+   omap_cfg_reg(Y8_3430_USB1HS_PHY_CLK);
+   omap_cfg_reg(AA14_3430_USB1HS_PHY_DIR);
+   omap_cfg_reg(AA11_3430_USB1HS_PHY_NXT);
+   omap_cfg_reg(W13_3430_USB1HS_PHY_DATA0);
+   omap_cfg_reg(W12_3430_USB1HS_PHY_DATA1);
+   omap_cfg_reg(W11_3430_USB1HS_PHY_DATA2);
+   omap_cfg_r

[PATCH 5/8] ehci: increase timeout to fix ehci failure

2009-07-10 Thread Ajay Kumar Gupta
Sometime during TLL reset and waiting loop for TLL reset timeouts and thus
ehci init fails. Fixing this by increasing timeout value.

Signed-off-by: Ajay Kumar Gupta 
Signed-off-by: Felipe Balbi 
---
 drivers/usb/host/ehci-omap.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 8f8f022..e7d0898 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -245,7 +245,7 @@ static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, 
u8 tll_channel_mask)
  */
 static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
 {
-   unsigned long timeout = jiffies + msecs_to_jiffies(100);
+   unsigned long timeout = jiffies + msecs_to_jiffies(1000);
unsigned reg = 0;
int ret = 0;
 
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 7/8] omap3: Add CHIP_GE_OMAP3430ES3 for HSUSB

2009-07-10 Thread Ajay Kumar Gupta
OMAP3 HSUSB ports can be individually programmed in PHY or TLL
mode in ES3.0 onwards whereas this is not supported in ES2.1
and earlier versions.

CHIP_GE_OMAP3430ES3 is added to program this behavior at runtime.

Also updated the existing macros to use the priviously defined
*_GE_* logic instead of repeating the same logic again.

Signed-off-by: Ajay Kumar Gupta 
---
 arch/arm/plat-omap/include/mach/cpu.h |7 ---
 1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/arm/plat-omap/include/mach/cpu.h 
b/arch/arm/plat-omap/include/mach/cpu.h
index 285eaa3..5848717 100644
--- a/arch/arm/plat-omap/include/mach/cpu.h
+++ b/arch/arm/plat-omap/include/mach/cpu.h
@@ -428,10 +428,11 @@ IS_OMAP_TYPE(3430, 0x3430)
  * chips at ES2 and beyond, but not, for example, any OMAP lines after
  * OMAP3.
  */
-#define CHIP_GE_OMAP3430ES2(CHIP_IS_OMAP3430ES2 | \
-CHIP_IS_OMAP3430ES3_0 | \
-CHIP_IS_OMAP3430ES3_1)
 #define CHIP_GE_OMAP3430ES3_1  (CHIP_IS_OMAP3430ES3_1)
+#define CHIP_GE_OMAP3430ES3(CHIP_IS_OMAP3430ES3_0 | \
+CHIP_GE_OMAP3430ES3_1)
+#define CHIP_GE_OMAP3430ES2(CHIP_IS_OMAP3430ES2 | \
+CHIP_GE_OMAP3430ES3)
 
 
 int omap_chip_is(struct omap_chip_id oci);
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/8] ehci: correct EHCI init parameters on OMAP3EVM

2009-07-10 Thread Ajay Kumar Gupta
Multimedia Daughter card on OMAP3EVM uses port2 as EHCI port.
Other ports (port1 and port3)are not used.

GPIO135 has been used as EHCI phy reset pin so the mux config
is also setup.

Signed-off-by: Ajay Kumar Gupta 
---
Resubmitting with padconfig part in platform files.

 arch/arm/mach-omap2/board-omap3evm.c |4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-omap2/board-omap3evm.c 
b/arch/arm/mach-omap2/board-omap3evm.c
index 595beac..b497979 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -308,7 +308,9 @@ static void __init omap3_evm_init(void)
 
omap_serial_init();
usb_musb_init();
-   usb_ehci_init(EHCI_HCD_OMAP_MODE_PHY, true, true, 57, 61);
+   /* Setup EHCI phy reset padconfig */
+   omap_cfg_reg(AF4_34XX_GPIO135_OUT);
+   usb_ehci_init(EHCI_HCD_OMAP_MODE_PHY, false, true, -EINVAL, 135);
ads7846_dev_init();
 }
 
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 4/8] ehci: fix phy_reset init in ehci probe

2009-07-10 Thread Ajay Kumar Gupta
phy_reset is not getting updated from platform_data.

Signed-off-by: Ajay Kumar Gupta 
Signed-off-by: Felipe Balbi 
---
 drivers/usb/host/ehci-omap.c |1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 0058f03..8f8f022 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -590,6 +590,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 
platform_set_drvdata(pdev, omap);
omap->dev   = &pdev->dev;
+   omap->phy_reset = pdata->phy_reset;
omap->reset_gpio_port1  = pdata->reset_gpio_port1;
omap->reset_gpio_port2  = pdata->reset_gpio_port2;
omap->phy_mode  = pdata->phy_mode;
-- 
1.6.2.4

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 6/8] ehci: portwise configurations

2009-07-10 Thread Ajay Kumar Gupta
OMAP3 EHCI has three ports and we can configure port modes
(PHY/TLL) on per port basis in silicon version ES3.0 onwards.

This patch modifies the existing EHCI driver to accomodate
portwise mode configuration.

Changes being done:

- Pass platform_data pointer as parameter to usb_ehci_init()
  to avoid multiple parameters.
- Use platform_data pointer in usb-ehci.c as platform_data
  directly without copying it to another *pdata*.
- Initializing platform_data in all platform files with
  platform specific ehci parameters.
- Added port_mode[OMAP_HS_USB_PORTS]in platform_data
  structures.This allows to setup mux pins on per port basis.
- Added phy_reset_gpio[OMAP_HS_USB_PORTS].

Signed-off-by: Ajay Kumar Gupta 
---
 arch/arm/mach-omap2/board-3430sdp.c  |   15 +-
 arch/arm/mach-omap2/board-omap3beagle.c  |   15 +-
 arch/arm/mach-omap2/board-omap3evm.c |   15 +-
 arch/arm/mach-omap2/board-omap3pandora.c |   15 +-
 arch/arm/mach-omap2/usb-ehci.c   |   95 +++---
 arch/arm/plat-omap/include/mach/usb.h|   12 ++--
 drivers/usb/host/ehci-omap.c |   63 +++-
 7 files changed, 145 insertions(+), 85 deletions(-)

diff --git a/arch/arm/mach-omap2/board-3430sdp.c 
b/arch/arm/mach-omap2/board-3430sdp.c
index 21b4a52..4d7a176 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -478,6 +478,19 @@ static inline void board_smc91x_init(void)
 
 #endif
 
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+   .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+   .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+   .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+   .chargepump = true,
+   .phy_reset  = true,
+   .reset_gpio_port[0]  = 57,
+   .reset_gpio_port[1]  = 61,
+   .reset_gpio_port[2]  = -EINVAL
+};
+
 static void __init omap_3430sdp_init(void)
 {
omap3430_i2c_init();
@@ -495,7 +508,7 @@ static void __init omap_3430sdp_init(void)
omap_serial_init();
usb_musb_init();
board_smc91x_init();
-   usb_ehci_init(EHCI_HCD_OMAP_MODE_PHY, true, true, 57, 61);
+   usb_ehci_init(&ehci_pdata);
 }
 
 static void __init omap_3430sdp_map_io(void)
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c 
b/arch/arm/mach-omap2/board-omap3beagle.c
index b6a68d5..1868e56 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -392,6 +392,19 @@ static void __init omap3beagle_flash_init(void)
}
 }
 
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+   .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+   .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+   .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+   .chargepump = true,
+   .phy_reset  = true,
+   .reset_gpio_port[0]  = 57,
+   .reset_gpio_port[1]  = 61,
+   .reset_gpio_port[2]  = -EINVAL
+};
+
 static void __init omap3_beagle_init(void)
 {
omap3_beagle_i2c_init();
@@ -407,7 +420,7 @@ static void __init omap3_beagle_init(void)
gpio_direction_output(170, true);
 
usb_musb_init();
-   usb_ehci_init(EHCI_HCD_OMAP_MODE_PHY, true, true, 57, 61);
+   usb_ehci_init(&ehci_pdata);
omap3beagle_flash_init();
 }
 
diff --git a/arch/arm/mach-omap2/board-omap3evm.c 
b/arch/arm/mach-omap2/board-omap3evm.c
index b497979..d2477e7 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -295,6 +295,19 @@ static struct platform_device *omap3_evm_devices[] 
__initdata = {
&omap3evm_smc911x_device,
 };
 
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+   .port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+   .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+   .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+   .chargepump = false,
+   .phy_reset  = true,
+   .reset_gpio_port[0]  = -EINVAL,
+   .reset_gpio_port[1]  = 135,
+   .reset_gpio_port[2]  = -EINVAL
+};
+
 static void __init omap3_evm_init(void)
 {
omap3_evm_i2c_init();
@@ -310,7 +323,7 @@ static void __init omap3_evm_init(void)
usb_musb_init();
/* Setup EHCI phy reset padconfig */
omap_cfg_reg(AF4_34XX_GPIO135_OUT);
-   usb_ehci_init(EHCI_HCD_OMAP_MODE_PHY, false, true, -EINVAL, 135);
+   usb_ehci_init(&ehci_pdata);
ads7846_dev_init();
 }
 
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c 
b/arch/arm/mach-omap2/board-omap3pandora.c
index 85cc2a7..5b20b3d 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -384,6 +384,19 @@ static struct platform_device *omap3pandora_devices[] 
__initdata = {
&pandora_keys_gpio,
 };
 
+static struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+
+   .port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+   .port_mode[1] = EHCI_HC