RE: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8
> -Original Message- > From: Russell King - ARM Linux [mailto:li...@arm.linux.org.uk] > Sent: Thursday, September 10, 2009 12:04 AM > To: Syed Mohammed, Khasim > Cc: Aguirre Rodriguez, Sergio Alberto; Rabin Vincent; linux-arm- > ker...@lists.arm.linux.org.uk; linux-omap@vger.kernel.org > Subject: Re: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8 > > On Wed, Sep 09, 2009 at 01:16:48PM +0530, Syed Mohammed, Khasim wrote: > > Hi Russell, > > > > > -Original Message- > > > From: Russell King - ARM Linux [mailto:li...@arm.linux.org.uk] > > > Sent: Wednesday, September 09, 2009 12:47 PM > > > To: Syed Mohammed, Khasim > > > Cc: Aguirre Rodriguez, Sergio Alberto; Rabin Vincent; linux-arm- > > > ker...@lists.arm.linux.org.uk; linux-omap@vger.kernel.org > > > Subject: Re: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8 > > > > > > And how about my revised version, which is the version which is going > > > to be merged? > > > > Sorry for missing this out. This works, no issues reported. > > And so can I add a: > > Tested-by: Khasim Syed Mohammed I did test this, please add Tested-by. Thanks, Regards, Khasim -- 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 00/07] pm: remove late/early platform driver pm callbacks V2
On Wednesday 09 September 2009, Dan Williams wrote: > 2009/7/4 Rafael J. Wysocki : > > On Wednesday 24 June 2009, Magnus Damm wrote: > >> pm: remove late/early platform driver pm callbacks V2 > >> > >> [PATCH 01/07] arm: rework omap suspend_late()/resume_early() > >> [PATCH 02/07] dma: rework dw_dmac suspend_late()/resume_early() > >> [PATCH 03/07] dma: rework txx9dmac suspend_late()/resume_early() > >> [PATCH 04/07] i2c: rework i2c-pxa suspend_late()/resume_early() > >> [PATCH 05/07] i2c: rework i2c-s3c2410 suspend_late()/resume() V2 > >> [PATCH 06/07] usb: rework musb suspend()/resume_early() > >> [PATCH 07/07] pm: remove platform device suspend_late()/resume_early() V2 > >> > >> These patches simply remove ->suspend_late() and ->resume_early() > >> from struct platform_driver. Drivers are converted to dev_pm_ops > >> with CONFIG_SUSPEND in mind. Untested. > >> > >> All patches except [02/07] are known to compile. > >> > >> Signed-off-by: Magnus Damm > [..] > > > > The series is now in the linux-next branch of the suspend-2.6 tree. I'll > > move > > it into the for-linus branch, which is not rebased, if the patches are not > > reported to cause any problems in the next few days. > > > > Hi, > > My linux-next test builds for drivers/dma/ caught a missed conversion > of the at_hdmac driver. Please check the attached fix (compile tested > only) and include it in this series. Applied to suspend-2.6/linux-next, thanks. Best, Rafael -- 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: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8
On Wed, Sep 09, 2009 at 01:16:48PM +0530, Syed Mohammed, Khasim wrote: > Hi Russell, > > > -Original Message- > > From: Russell King - ARM Linux [mailto:li...@arm.linux.org.uk] > > Sent: Wednesday, September 09, 2009 12:47 PM > > To: Syed Mohammed, Khasim > > Cc: Aguirre Rodriguez, Sergio Alberto; Rabin Vincent; linux-arm- > > ker...@lists.arm.linux.org.uk; linux-omap@vger.kernel.org > > Subject: Re: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8 > > > > And how about my revised version, which is the version which is going > > to be merged? > > Sorry for missing this out. This works, no issues reported. And so can I add a: Tested-by: Khasim Syed Mohammed or is it a just a Reviewed-by: ? -- 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] OMAP3: Lock DPLL5 at boot
> > > > >Thanks for the changes, I will queue this in a for-next branch for .33. > > > > > > > > Is this for .33 or .32? > > > > > > I think it might be a little late for .32. If there is some crash or > > > instability that this fixes, we could queue it up for .32-fixes ? > > > > Well, without this, there's no way the child clocks can be enabled > > correctly. > > OK. So is it the case that USBHOST/USBTLL/USIM won't work without this > fix? Yup. Not sure about USIM - will check. > > If so then we'll queue it for .32-fixes. Since .32 is already at -rc9, I > think it is too late for .32. > Would be nice. Thanks! -- 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] OMAP3: Lock DPLL5 at boot
On Wed, 9 Sep 2009, Gadiyar, Anand wrote: > On Wed, 9 Sep 2009, Paul Walmsley wrote: > > On Wed, 9 Sep 2009, Pandita, Vikram wrote: > > > > > >From: linux-omap-ow...@vger.kernel.org > > > >[mailto:linux-omap-ow...@vger.kernel.org] On Behalf Of Paul > > > >Walmsley > > > >> $SUBJECT to reflect the change. > > > > > > > >Thanks for the changes, I will queue this in a for-next branch for .33. > > > > > > Is this for .33 or .32? > > > > I think it might be a little late for .32. If there is some crash or > > instability that this fixes, we could queue it up for .32-fixes ? > > Well, without this, there's no way the child clocks can be enabled correctly. OK. So is it the case that USBHOST/USBTLL/USIM won't work without this fix? If so then we'll queue it for .32-fixes. Since .32 is already at -rc9, I think it is too late for .32. - Paul -- 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] OMAP3: Lock DPLL5 at boot
On Wed, 9 Sep 2009, Paul Walmsley wrote: > On Wed, 9 Sep 2009, Pandita, Vikram wrote: > > > >From: linux-omap-ow...@vger.kernel.org > > >[mailto:linux-omap-ow...@vger.kernel.org] On Behalf Of Paul > > >Walmsley > > >> $SUBJECT to reflect the change. > > > > > >Thanks for the changes, I will queue this in a for-next branch for .33. > > > > Is this for .33 or .32? > > I think it might be a little late for .32. If there is some crash or > instability that this fixes, we could queue it up for .32-fixes ? > Well, without this, there's no way the child clocks can be enabled correctly. Possibly it qualifies as a bug-fix in clock framework? Rajendra had created this patch quite a while ago and it has received sufficient testing on various codebases - I guess we just missed sending it out to l-o early enough. - Anand -- 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] OMAP3: Lock DPLL5 at boot
On Wed, 9 Sep 2009, Pandita, Vikram wrote: > >From: linux-omap-ow...@vger.kernel.org > >[mailto:linux-omap-ow...@vger.kernel.org] On Behalf Of Paul > >Walmsley > >> $SUBJECT to reflect the change. > > > >Thanks for the changes, I will queue this in a for-next branch for .33. > > Is this for .33 or .32? I think it might be a little late for .32. If there is some crash or instability that this fixes, we could queue it up for .32-fixes ? - Paul -- 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] OMAP3: Lock DPLL5 at boot
Paul >-Original Message- >From: linux-omap-ow...@vger.kernel.org >[mailto:linux-omap-ow...@vger.kernel.org] On Behalf Of Paul >Walmsley >Sent: Wednesday, September 09, 2009 10:43 AM >To: Gadiyar, Anand >Cc: linux-omap@vger.kernel.org; Nayak, Rajendra; Cousson, Benoit >Subject: Re: [PATCH] OMAP3: Lock DPLL5 at boot > >On Tue, 8 Sep 2009, Anand Gadiyar wrote: > >> From: Rajendra Nayak >> >> OMAP3: Lock DPLL5 at boot >> >> Lock DPLL5 at 120MHz at boot. The USBHOST 120MHz f-clock and >> USBTLL f-clock are the only users of this DPLL, and 120MHz is >> is the only recommended rate for these clocks. >> >> With this patch, the 60 MHz ULPI clock is generated correctly. >> >> Tested on an OMAP3430 SDP. >> >> Signed-off-by: Rajendra Nayak >> Signed-off-by: Anand Gadiyar >> --- >> Incorporated all 3 comments by Paul and Benoit. Updated >> $SUBJECT to reflect the change. > >Thanks for the changes, I will queue this in a for-next branch for .33. Is this for .33 or .32? > > >- Paul >-- >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 -- 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] OMAP3: Lock DPLL5 at boot
On Tue, 8 Sep 2009, Anand Gadiyar wrote: > From: Rajendra Nayak > > OMAP3: Lock DPLL5 at boot > > Lock DPLL5 at 120MHz at boot. The USBHOST 120MHz f-clock and > USBTLL f-clock are the only users of this DPLL, and 120MHz is > is the only recommended rate for these clocks. > > With this patch, the 60 MHz ULPI clock is generated correctly. > > Tested on an OMAP3430 SDP. > > Signed-off-by: Rajendra Nayak > Signed-off-by: Anand Gadiyar > --- > Incorporated all 3 comments by Paul and Benoit. Updated > $SUBJECT to reflect the change. Thanks for the changes, I will queue this in a for-next branch for .33. - Paul -- 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: several OMAP newbie questions
Cliff Brake wrote: > On Tue, Sep 1, 2009 at 6:34 AM, Mike Rapoport wrote: > >> 3) If I'm not much mistaken, board specific pin mux configuration has to deal >> with arch/arm/plat-omap/include/mach/mux.h and arch/arm/mach-omap2/mux.c. For >> instance, if my board uses ULPI pins that have not been defined already, I >> need >> to patch those file with my pin mux definitions. Am I right here, or have I >> missed something? > > It seems to me there should be a global mux configuration per CPU, but > should be configurable per board, group of boards, etc. What I would > like is a set of routines can be used to configure the mux that is > then called by the board files (similar to PXA). Yeah, I actually was missing pxa_mfp_config()... The omap34xx_pins seems somewhat sparse... > > Cliff > -- > 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 > -- Sincerely yours, Mike. -- 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]PM: Initialization of SDRC params for DVFS on Zoom2
On Wednesday 09 September 2009 00:17:42 Kevin Hilman wrote: > "Reddy, Teerth" writes: > > This patch initializes the SDRC params for DVFS on Zoom2. > > > > Signed-off-by: Teerth Reddy > > --- > > arch/arm/mach-omap2/board-zoom2.c |6 -- > > 1 files changed, 4 insertions(+), 2 deletions(-) > > > > Index: linux-omap-pm/arch/arm/mach-omap2/board-zoom2.c > > === > > --- linux-omap-pm.orig/arch/arm/mach-omap2/board-zoom2.c > > +++ linux-omap-pm/arch/arm/mach-omap2/board-zoom2.c > > @@ -23,6 +23,7 @@ > > > > #include "mmc-twl4030.h" > > #include "omap3-opp.h" > > +#include "sdram-micron-mt46h32m32lf-6.h" > > > > static struct omap_uart_config zoom2_uart_config __initdata = { > > .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), > > @@ -36,8 +37,9 @@ static void __init omap_zoom2_init_irq(v > > { > > omap_board_config = zoom2_config; > > omap_board_config_size = ARRAY_SIZE(zoom2_config); > > - omap2_init_common_hw(NULL, NULL, omap3_mpu_rate_table, > > -omap3_dsp_rate_table, omap3_l3_rate_table); > > + omap2_init_common_hw(mt46h32m32lf6_sdrc_params, NULL, > > + omap3_mpu_rate_table, omap3_dsp_rate_table, > > + omap3_l3_rate_table); > > Not having looked at the Zoom2 schematics, are you sure this is only > using a single chip select? The other boards using the same part > (beagle, overo) are interfacing to this part using both CSes. > > Have you tested DVFS on Zoom2 using the full 256Mb? Good point! DVFS works fine using the two chip selects: omap2_init_common_hw(mt46h32m32lf6_sdrc_params, mt46h32m32lf6_sdrc_params, omap3_mpu_rate_table, omap3_dsp_rate_table, omap3_l3_rate_table); One remark though: since the memory chips are popped on top of the OMAP chip the schematics are not showing the chip selects connections. In any case U-Boot is configuring the SDRC module to use the 2 chip selects, so I think this change is needed. We need confirmation. Anyone from TI knows? Regards, Jean > > Kevin > > > omap_init_irq(); > > omap_gpio_init(); > > } > > -- > 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 -- 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 V3 29/30] omap_hsmmc: set a large data timeout for commands with busy signal
>From c85a80da2efe181ff256074f7bcd9099428f2572 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 64780da..b54f3e3 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -990,7 +990,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; @@ -1001,8 +1002,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; @@ -1036,12 +1037,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
[PATCH V3 30/30] ARM: OMAP: RX51: set MMC capabilities and power-saving flag
>From 165355201788f4efc00c37774070d8b9960e9b70 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 |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 56d931a..4ce5a76 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,7 @@ static struct twl4030_hsmmc_info mmc[] = { .cover_only = true, .gpio_cd= 160, .gpio_wp= -EINVAL, + .power_saving = true, }, { .name = "internal", @@ -109,6 +111,8 @@ static struct twl4030_hsmmc_info mmc[] = { .wires = 8, .gpio_cd= -EINVAL, .gpio_wp= -EINVAL, + .nonremovable = true, + .power_saving = true, }, {} /* 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 V3 27/30] omap_hsmmc: protect the card when the cover is open
>From bed30ea9b2f8c88199578df12faca269c0c5a91b 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 4249723..047e656 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -165,6 +165,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; }; @@ -349,6 +351,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); @@ -779,6 +784,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 */ @@ -796,8 +825,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); @@ -1033,8 +1064,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()) { spin_lock_irqsave(&host->irq_lock, host->flags); + /* +* 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; + spin_unlock_irqrestore(&host->irq_lock, host->flags); + 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); @@ -1725,6 +1780,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) { @@ -1890,6 +1947,8 @@ static int omap_hsmmc_resume(struct platform_device *pdev) "Unmask interrupt failed\n"); } + omap_hsmmc_protect_card(host); + /* Notify the core t
[PATCH V3 25/30] omap_hsmmc: prevent races with irq handler
>From 8dc8e911b67f5c77e95c203908ff2ad7ce728b13 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 adding a spinlock. Signed-off-by: Adrian Hunter --- drivers/mmc/host/omap_hsmmc.c | 25 + 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 205cc3a..50c7f94 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -146,6 +146,8 @@ struct mmc_omap_host { struct work_struct mmc_carddetect_work; void__iomem *base; resource_size_t mapbase; + spinlock_t irq_lock; /* Prevent races with irq handler */ + unsigned long flags; unsigned intid; unsigned intdma_len; unsigned intdma_sg_idx; @@ -452,6 +454,14 @@ 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 spinlock is unlocked +* by the interrupt handler, otherwise (i.e. for a new request) it is +* unlocked here. +*/ + if (!in_interrupt()) + spin_unlock_irqrestore(&host->irq_lock, host->flags); + OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg); OMAP_HSMMC_WRITE(host->base, CMD, cmdreg); } @@ -614,11 +624,14 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) struct mmc_data *data; int end_cmd = 0, end_trans = 0, status; + spin_lock(&host->irq_lock); + if (host->mrq == NULL) { OMAP_HSMMC_WRITE(host->base, STAT, OMAP_HSMMC_READ(host->base, STAT)); /* Flush posted write */ OMAP_HSMMC_READ(host->base, STAT); + spin_unlock(&host->irq_lock); return IRQ_HANDLED; } @@ -683,6 +696,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) if ((end_trans || (status & TC)) && host->mrq) mmc_omap_xfer_done(host, data); + spin_unlock(&host->irq_lock); + return IRQ_HANDLED; } @@ -1011,6 +1026,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()) + spin_lock_irqsave(&host->irq_lock, host->flags); WARN_ON(host->mrq != NULL); host->mrq = req; err = mmc_omap_prepare_data(host, req); @@ -1019,6 +1041,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()) + spin_unlock_irqrestore(&host->irq_lock, host->flags); mmc_request_done(mmc, req); return; } @@ -1573,6 +1597,7 @@ static int __init omap_mmc_probe(struct platform_device *pdev) mmc->f_max = 5200; sema_init(&host->sem, 1); + spin_lock_init(&host->irq_lock); host->iclk = clk_get(&pdev->dev, "ick"); if (IS_ERR(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 V3 26/30] omap_hsmmc: code refactoring
>From 4bb38c80322897aba471fe50d0e6e9d774edbe96 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 50c7f94..4249723 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; @@ -172,7 +172,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); @@ -186,7 +186,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; @@ -314,7 +314,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; @@ -329,12 +329,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) { } @@ -344,7 +344,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; @@ -368,7 +368,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; @@ -378,35 +378,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; @@ -467,7 +467,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 V3 28/30] omap_hsmmc: ensure all clock enables and disables are paired
>From baf6574a1b5e7c4fdc4a66d9e038efeee75ea1a0 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 047e656..64780da 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -735,22 +735,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); @@ -1898,7 +1900,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) { @@ -1929,9 +1932,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 V3 24/30] omap_hsmmc: cater for weird CMD6 behaviour
>From 60731c064681d57c84ce563274f3f5869c598cce 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 42f3aad..205cc3a 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 V3 17/30] omap_hsmmc: support for deeper power saving states
>From 2323c5463bab8e67ad3b6210eab91f2151fc72c0 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 56f07f2..cb1cbd7 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.c +++ b/arch/arm/mach-omap2/mmc-twl4030.c @@ -418,6 +418,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 ed35b0d..acb7a78 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 V3 23/30] omap_hsmmc: clear interrupt status after init sequence
>From 8cd514349f0a383b8e59172067ac4a3a8829b907 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 a669757..42f3aad 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 V3 22/30] omap_hsmmc: cleanup macro usage
>From 5f9c3e4511904ff58ab1cf619f35a10cc528a94f 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 243ad97..a669757 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 V3 21/30] omap_hsmmc: fix NULL pointer dereference
>From bd81dee10c08ae9290c9a6170584549c15bc43d0 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 d6bf65b..243ad97 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 V3 19/30] omap_hsmmc: put MMC regulator to sleep
>From 0c1e00cc0560fe27deb79c8d132677c9f190ad15 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 acb7a78..cf6023b 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 V3 20/30] omap_hsmmc: add mmc card sleep and awake support
>From ea55481d3f16bcc2d7bda941972c722895afc7ee 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 cf6023b..d6bf65b 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 V3 18/30] ARM: OMAP: mmc-twl4030: add regulator sleep / wake function
>From 1650c5568cd7e4f3bcc3e77ee3a6a3c098e9a23c 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 cb1cbd7..c9c59a2 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.c +++ b/arch/arm/mach-omap2/mmc-twl4030.c @@ -340,6 +340,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) @@ -433,6 +488,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) @@ -443,6 +499,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 V3 16/30] omap_hsmmc: make use of new MMC_CAP_NONREMOVABLE host capability
>From 4344e2509599b187ff98b5ad8ea0f8dede2d9374 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 30d0286..56f07f2 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.c +++ b/arch/arm/mach-omap2/mmc-twl4030.c @@ -415,6 +415,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 df13a54..ed35b0d 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 V3 15/30] omap_hsmmc: fix scatter-gather list sanity checking
>From fff912de41b3c8b5036aaa4d8ac6762efac533f0 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 041af02..df13a54 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 V3 14/30] omap_hsmmc: ensure workqueues are empty before suspend
>From f97476c2395ae2a5003957caaf4897f43327e1dd 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 e0b9c49..041af02 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 V3 12/30] omap_hsmmc: context save/restore support
>From af66a8e899b8acf055fedd3a1fabf7ad9f0f2393 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 8a41629..d5e4f08 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 V3 13/30] omap_hsmmc: set open drain bit correctly
>From ca1bda2fa518c0263af943ffd953ab59515c949d 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 d5e4f08..e0b9c49 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 V3 10/30] ARM: OMAP: mmc-twl4030: add context loss counter support
>From 027d57463031f291c704f3048c49765c02e661b1 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 3c04c2f..30d0286 100644 --- a/arch/arm/mach-omap2/mmc-twl4030.c +++ b/arch/arm/mach-omap2/mmc-twl4030.c @@ -198,6 +198,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) { @@ -390,6 +402,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 V3 11/30] omap_hsmmc: keep track of power mode
>From c6da86a98f20740cf1c0944d92934322be6ab699 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 b1bee52..8a41629 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 V3 9/30] omap_hsmmc: make use of new enable/disable interface
>From bd1f7622b77a370f3750a7823462dffa2267d09a 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..b1bee52 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, 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,6 +1288,7 @@ stati
[PATCH V3 8/30] omap_hsmmc: add debugfs entry (host registers)
>From 9ef69fd17bbd1d598a7f262d5940f88dbfff526c 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 V3 7/30] mmc: check status after MMC SWITCH command
>From b1b7bb5d722ff81b28b006fa43eca3eb86769add 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 V3 6/30] mmc: power off once at removal
>From 1ba831889384b613e36b68476e0d2207deebabe0 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 0611bf7..8d03da4 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1137,6 +1137,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 V3 5/30] mmc: add mmc card sleep and awake support
>From 93c2813af7edee923a5d46362edfaeb24695d73f 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 39f7bd1..0611bf7 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1179,6 +1179,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 V3 4/30] mmc: add ability to save power by powering off cards
>From ead8ace5804bd9fa2093a5e2e0e80e1ab14d20b0 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 bab5015..39f7bd1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1145,6 +1145,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 V3 1/30] mmc: add 'enable' and 'disable' methods to mmc host
>From e1e0cfce4220d9a3f6c969c867cd716f9fb177a5 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 | 177 -- drivers/mmc/core/host.c |1 + drivers/mmc/core/host.h |2 + include/linux/mmc/host.h | 47 4 files changed, 221 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index d84c880..9bc8d27 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -344,6 +344,101 @@ 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) { + unsigned long delay = msecs_to_jiffies(err); + + mmc_schedule_delayed_work(&host->disable, delay); + } + } + 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 +474,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_ho
[PATCH V3 2/30] mmc: allow host claim / release nesting
>From 38406738784f19de180db9872a7e10bd02908dc8 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 9bc8d27..bab5015 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -461,16 +461,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); @@ -481,29 +483,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 338a9b3..631a2fe 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
[PATCH V3 3/30] mmc: add MMC_CAP_NONREMOVABLE host capability
>From d4af21bc85c82d996401466c71afc10e3723fd87 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 631a2fe..bb867d2 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 V3 0/30] mmc and omap_hsmmc patches
Hi Here is version 3 of our 30 patches for mmc and omap_hsmmc. They exclude Matt Fleming's change for card caps They split into 2 groups: the first 7 affect mmc core only and the remaining ones affect omap_hsmmc only. Madhusudhan Chikkature's patch: [PATCH V2] omap_hsmmc: Fix for the db clock failure message still applies cleanly on top. Adrian Hunter (18): 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: 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: 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 |4 + arch/arm/mach-omap2/mmc-twl4030.c| 78 ++ arch/arm/mach-omap2/mmc-twl4030.h|2 + arch/arm/plat-omap/include/mach/mmc.h| 11 + drivers/mmc/core/core.c | 275 +++- 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| 1035 +- include/linux/mmc/card.h |2 + include/linux/mmc/core.h |1 + include/linux/mmc/host.h | 58 ++ include/linux/mmc/mmc.h |3 + 17 files changed, 1503 insertions(+), 215 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] OMAP3 : PM : Functions to get freq from opp and vice-versa
There is no generic function to get OPP corresponding to frequency and vice versa. Function get_opp() - in resource34xx.c - is included only when CONFIG_OMAP_PM_SRF is enabled. Moreover, it is always called with an explicit addition of MAX_VDDn_OPP e.g. opp = get_opp(mpu_opps + MAX_VDD1_OPP, clk->rate); opp = get_opp(l3_opps + MAX_VDD2_OPP, clk->rate); This is 'addition' is required as there is no encapsulation of MIN and MAX VDDs associated to the table. This patch fixes the issue by creating a 'table' object that encapsulates the MIN and MAX values and the existing rate table. Signed-off-by: Sanjeev Premi --- arch/arm/mach-omap2/omap3-opp.h | 42 +++-- arch/arm/mach-omap2/pm.c | 49 + arch/arm/mach-omap2/pm34xx.c | 57 + arch/arm/plat-omap/include/mach/omap-pm.h | 25 + 4 files changed, 137 insertions(+), 36 deletions(-) diff --git a/arch/arm/mach-omap2/omap3-opp.h b/arch/arm/mach-omap2/omap3-opp.h index 3c9a582..52deb4a 100644 --- a/arch/arm/mach-omap2/omap3-opp.h +++ b/arch/arm/mach-omap2/omap3-opp.h @@ -21,42 +21,12 @@ #define S83M8300 #define S166M 16600 -static struct omap_opp omap3_mpu_rate_table[] = { - {0, 0, 0}, - /*OPP1*/ - {S125M, VDD1_OPP1, 0x1E}, - /*OPP2*/ - {S250M, VDD1_OPP2, 0x26}, - /*OPP3*/ - {S500M, VDD1_OPP3, 0x30}, - /*OPP4*/ - {S550M, VDD1_OPP4, 0x36}, - /*OPP5*/ - {S600M, VDD1_OPP5, 0x3C}, -}; +extern struct omap_opp omap3_mpu_rate_table[]; +extern struct omap_opp omap3_dsp_rate_table[]; +extern struct omap_opp omap3_l3_rate_table[]; -static struct omap_opp omap3_l3_rate_table[] = { - {0, 0, 0}, - /*OPP1*/ - {0, VDD2_OPP1, 0x1E}, - /*OPP2*/ - {S83M, VDD2_OPP2, 0x24}, - /*OPP3*/ - {S166M, VDD2_OPP3, 0x2C}, -}; - -static struct omap_opp omap3_dsp_rate_table[] = { - {0, 0, 0}, - /*OPP1*/ - {S90M, VDD1_OPP1, 0x1E}, - /*OPP2*/ - {S180M, VDD1_OPP2, 0x26}, - /*OPP3*/ - {S360M, VDD1_OPP3, 0x30}, - /*OPP4*/ - {S400M, VDD1_OPP4, 0x36}, - /*OPP5*/ - {S430M, VDD1_OPP5, 0x3C}, -}; +extern const struct omap_opp_table omap3_mpu_opp_table; +extern const struct omap_opp_table omap3_dsp_opp_table; +extern const struct omap_opp_table omap3_l3_opp_table; #endif diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index fec7d00..2bbe63f 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "prm-regbits-34xx.h" #include "pm.h" @@ -281,3 +282,51 @@ static int __init omap_pm_init(void) return error; } late_initcall(omap_pm_init); + +/* + * Get frequency corresponding to an OPP + */ +int opp_to_freq(unsigned long* freq, const struct omap_opp_table* table, u8 opp) +{ +int i, found=0; + +if (table && table->opps) { + for (i = table->min; i <= table->max; i++) { + if (table->opps[i].opp_id == opp) { + found = 1; + break; + } + } + + if (found) { + *freq = table->opps[i].rate; + return 1; + } + } + +return 0; +} + +/* + * Get OPP corresponding to a frequency + */ +int freq_to_opp(u8* opp, const struct omap_opp_table* table, unsigned long freq) +{ +int i, found=0; + +if (table && table->opps) { + for (i = table->min; i <= table->max; i++) { + if (table->opps[i].rate == freq) { + found = 1; + break; + } + } + + if (found) { + *opp = table->opps[i].opp_id; + return 1; + } + } + +return 0; +} diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 3d62b06..60b0441 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -50,6 +50,7 @@ #include "prm.h" #include "pm.h" #include "sdrc.h" +#include "omap3-opp.h" static int regset_save_on_suspend; @@ -93,6 +94,62 @@ static struct prm_setup_vc prm_setup = { .vdd1_off = 0x00, /* 0.6v */ }; +struct omap_opp omap3_mpu_rate_table[] = { + {0, 0, 0}, + /*OPP1*/ + {S125M, VDD1_OPP1, 0x1E}, + /*OPP2*/ + {S250M, VDD1_OPP2, 0x26}, + /*OPP3*/ + {S500M, VDD1_OPP3, 0x30}, + /*OPP4*/ + {S550M, VDD1_OPP4, 0x36}, + /*OPP5*/ + {S600M, VDD1_OPP5, 0x3C}, +}; + +struct omap_opp omap3_l3_rate_table[] = { + {0, 0, 0}, + /*OPP1*/ + {0, VDD2_OPP1, 0x1E}, + /*OPP2*/ + {S83M, VDD2_OPP2, 0x24}, + /*OPP3*/ + {S166M, VDD2_
RE: [PATCH 10/10] omap mailbox: OMAP4 Mailbox-driver Patch to support tasklet implementation
Hi Hiroshi, > -Original Message- > From: Hiroshi DOYU [mailto:hiroshi.d...@nokia.com] > Sent: Wednesday, September 09, 2009 2:32 PM > To: C.A, Subramaniam > Cc: linux-omap@vger.kernel.org; t...@atomide.com; > r...@arm.linux.org.uk; Kanigeri, Hari; Gupta, Ramesh > Subject: Re: [PATCH 10/10] omap mailbox: OMAP4 Mailbox-driver > Patch to support tasklet implementation > > Hi Subbu, > > From: "ext C.A, Subramaniam" > Subject: RE: [PATCH 10/10] omap mailbox: OMAP4 Mailbox-driver > Patch to support tasklet implementation > Date: Tue, 8 Sep 2009 19:43:48 +0200 > > [...] > > > > As I described in the comment on [PATCH 8/10], I think > that it would > > > be better to keep "mach-omap2/mailbox.c" simple and to add some > > > additional logic on "plat-omap/mailbox.c". > > > > > > Would it be possbile to move this tasklet implementation to > > > "plat-omap/mailbox.c"? > > > > The implementation of the tasklet itself is maintained in > > plat-omap/mailbox.c Since, I wanted to maintain a separate > tasklet for > > each mailbox instance used to send messages from MPU, I had to > > associate the the tasklet to the mailbox. Hence, the > changes were done > > in mach-omap2/mailbox.c > > > > Please give your comments on this approach. > > Wouldn't just converting work_queue to tasklet work like below? > > (I havne't tested this at all, though...) I will try that out and let you know. Also your approach seems better as you are replacing the work queue implementaion as well. > > diff --git a/arch/arm/plat-omap/include/mach/mailbox.h > b/arch/arm/plat-omap/include/mach/mailbox.h > index b7a6991..1f4e53e 100644 > --- a/arch/arm/plat-omap/include/mach/mailbox.h > +++ b/arch/arm/plat-omap/include/mach/mailbox.h > @@ -52,6 +52,8 @@ struct omap_mbox { > > struct omap_mbox_queue *txq, *rxq; > > + struct tasklet_struct tx_tasklet; > + > struct omap_mbox_ops*ops; > > mbox_msg_t seq_snd, seq_rcv; > diff --git a/arch/arm/plat-omap/mailbox.c > b/arch/arm/plat-omap/mailbox.c index 40424ed..37267ca 100644 > --- a/arch/arm/plat-omap/mailbox.c > +++ b/arch/arm/plat-omap/mailbox.c > @@ -184,22 +184,17 @@ int omap_mbox_msg_send(struct omap_mbox > *mbox, mbox_msg_t msg, void* arg) } > EXPORT_SYMBOL(omap_mbox_msg_send); > > -static void mbox_tx_work(struct work_struct *work) > +static void mbox_tx_tasklet(unsigned long data) > { > int ret; > struct request *rq; > - struct omap_mbox_queue *mq = container_of(work, > - struct omap_mbox_queue, work); > - struct omap_mbox *mbox = mq->queue->queuedata; > + struct omap_mbox *mbox = (struct omap_mbox *)data; > struct request_queue *q = mbox->txq->queue; > > while (1) { > struct omap_msg_tx_data *tx_data; > > - spin_lock(q->queue_lock); > rq = blk_fetch_request(q); > - spin_unlock(q->queue_lock); > - > if (!rq) > break; > > @@ -208,15 +203,10 @@ static void mbox_tx_work(struct > work_struct *work) > ret = __mbox_msg_send(mbox, tx_data->msg, tx_data->arg); > if (ret) { > enable_mbox_irq(mbox, IRQ_TX); > - spin_lock(q->queue_lock); > blk_requeue_request(q, rq); > - spin_unlock(q->queue_lock); > return; > } > - > - spin_lock(q->queue_lock); > __blk_end_request_all(rq, 0); > - spin_unlock(q->queue_lock); > } > } > > @@ -266,7 +256,7 @@ static void __mbox_tx_interrupt(struct > omap_mbox *mbox) { > disable_mbox_irq(mbox, IRQ_TX); > ack_mbox_irq(mbox, IRQ_TX); > - schedule_work(&mbox->txq->work); > + tasklet_schedule(&mbox->tx_tasklet); > } > > static void __mbox_rx_interrupt(struct omap_mbox *mbox) @@ > -434,7 +424,9 @@ static int omap_mbox_init(struct omap_mbox *mbox) > goto fail_request_irq; > } > > - mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work); > + tasklet_init(&mbox->tx_tasklet, mbox_tx_tasklet, > (unsigned long)mbox); > + > + mq = mbox_queue_alloc(mbox, mbox_txq_fn, NULL); > if (!mq) { > ret = -ENOMEM; > goto fail_alloc_txq; > > -- 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 6/10] omap mailbox: remove unnecessary arg for omap_mbox_msg_send
From: "ext C.A, Subramaniam" Subject: RE: [PATCH 6/10] omap mailbox: remove unnecessary arg for omap_mbox_msg_send Date: Mon, 7 Sep 2009 17:32:48 +0200 > Hi Russell, > 'arg' is used later in Patch 10, as part of the tasklet > implementation, for writing messages to the mailbox. Should I be > removing it in patch 6 and introduce it only for the tasklet > implementation? If just converting work queue to tasklet as below, can we get rid of the special struct "struct omap_msg_tx_data"? http://marc.info/?l=linux-omap&m=125248696005088&w=2 -- 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 10/10] omap mailbox: OMAP4 Mailbox-driver Patch to support tasklet implementation
Hi Subbu, From: "ext C.A, Subramaniam" Subject: RE: [PATCH 10/10] omap mailbox: OMAP4 Mailbox-driver Patch to support tasklet implementation Date: Tue, 8 Sep 2009 19:43:48 +0200 [...] > > As I described in the comment on [PATCH 8/10], I think that > > it would be better to keep "mach-omap2/mailbox.c" simple and > > to add some additional logic on "plat-omap/mailbox.c". > > > > Would it be possbile to move this tasklet implementation to > > "plat-omap/mailbox.c"? > > The implementation of the tasklet itself is maintained in plat-omap/mailbox.c > Since, I wanted to maintain a separate tasklet for each mailbox > instance used to send messages from MPU, I had to associate the the tasklet > to the mailbox. Hence, the changes were done in mach-omap2/mailbox.c > > Please give your comments on this approach. Wouldn't just converting work_queue to tasklet work like below? (I havne't tested this at all, though...) diff --git a/arch/arm/plat-omap/include/mach/mailbox.h b/arch/arm/plat-omap/include/mach/mailbox.h index b7a6991..1f4e53e 100644 --- a/arch/arm/plat-omap/include/mach/mailbox.h +++ b/arch/arm/plat-omap/include/mach/mailbox.h @@ -52,6 +52,8 @@ struct omap_mbox { struct omap_mbox_queue *txq, *rxq; + struct tasklet_struct tx_tasklet; + struct omap_mbox_ops*ops; mbox_msg_t seq_snd, seq_rcv; diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 40424ed..37267ca 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c @@ -184,22 +184,17 @@ int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg) } EXPORT_SYMBOL(omap_mbox_msg_send); -static void mbox_tx_work(struct work_struct *work) +static void mbox_tx_tasklet(unsigned long data) { int ret; struct request *rq; - struct omap_mbox_queue *mq = container_of(work, - struct omap_mbox_queue, work); - struct omap_mbox *mbox = mq->queue->queuedata; + struct omap_mbox *mbox = (struct omap_mbox *)data; struct request_queue *q = mbox->txq->queue; while (1) { struct omap_msg_tx_data *tx_data; - spin_lock(q->queue_lock); rq = blk_fetch_request(q); - spin_unlock(q->queue_lock); - if (!rq) break; @@ -208,15 +203,10 @@ static void mbox_tx_work(struct work_struct *work) ret = __mbox_msg_send(mbox, tx_data->msg, tx_data->arg); if (ret) { enable_mbox_irq(mbox, IRQ_TX); - spin_lock(q->queue_lock); blk_requeue_request(q, rq); - spin_unlock(q->queue_lock); return; } - - spin_lock(q->queue_lock); __blk_end_request_all(rq, 0); - spin_unlock(q->queue_lock); } } @@ -266,7 +256,7 @@ static void __mbox_tx_interrupt(struct omap_mbox *mbox) { disable_mbox_irq(mbox, IRQ_TX); ack_mbox_irq(mbox, IRQ_TX); - schedule_work(&mbox->txq->work); + tasklet_schedule(&mbox->tx_tasklet); } static void __mbox_rx_interrupt(struct omap_mbox *mbox) @@ -434,7 +424,9 @@ static int omap_mbox_init(struct omap_mbox *mbox) goto fail_request_irq; } - mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work); + tasklet_init(&mbox->tx_tasklet, mbox_tx_tasklet, (unsigned long)mbox); + + mq = mbox_queue_alloc(mbox, mbox_txq_fn, NULL); if (!mq) { ret = -ENOMEM; goto fail_alloc_txq; -- 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: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8
Hi Russell, > -Original Message- > From: Russell King - ARM Linux [mailto:li...@arm.linux.org.uk] > Sent: Wednesday, September 09, 2009 12:47 PM > To: Syed Mohammed, Khasim > Cc: Aguirre Rodriguez, Sergio Alberto; Rabin Vincent; linux-arm- > ker...@lists.arm.linux.org.uk; linux-omap@vger.kernel.org > Subject: Re: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8 > > On Wed, Sep 09, 2009 at 10:12:48AM +0530, Syed Mohammed, Khasim wrote: > > Hello all, > > > > > -Original Message- > > > From: Aguirre Rodriguez, Sergio Alberto > > > Sent: Wednesday, September 09, 2009 7:35 AM > > > To: Russell King - ARM Linux; Rabin Vincent > > > Cc: Syed Mohammed, Khasim; linux-arm-ker...@lists.arm.linux.org.uk; > linux- > > > o...@vger.kernel.org > > > Subject: RE: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8 > > > > > > From: Russell King - ARM Linux [li...@arm.linux.org.uk] > > > Sent: Tuesday, September 08, 2009 11:23 PM > > > > > > > > > > Acks and tested-bys would be useful please. > > > > > > > > Haven't heard anything, so I've committed it as is. It is my intention > > > > to push it to Linus as is in the next couple of days. > > > > > > Russell, > > > > > > I don't have ways of testing this, but I think Khasim's testing will make > > > more sense, > > > since he reported the bug... anyways, it's probably too late. > > > > > I am really sorry, wanted to try this out when RMK returns from vacation > meanwhile forgot :( > > > > The below logic from Rabin works great !!! no issues with this as well. > > And how about my revised version, which is the version which is going > to be merged? Sorry for missing this out. This works, no issues reported. +int pfn_valid(unsigned long pfn) +{ +struct meminfo *mi = &meminfo; +unsigned int left = 0, right = mi->nr_banks; + +do { +unsigned int mid = (right + left) / 2; +struct membank *bank = &mi->bank[mid]; + +if (pfn < bank_pfn_start(bank)) +right = mid; +else if (pfn >= bank_pfn_end(bank)) +left = mid + 1; +else +return 1; +} while (left < right); +return 0; +} Thanks. Regards, Khasim -- 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: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8
On Wed, Sep 09, 2009 at 10:12:48AM +0530, Syed Mohammed, Khasim wrote: > Hello all, > > > -Original Message- > > From: Aguirre Rodriguez, Sergio Alberto > > Sent: Wednesday, September 09, 2009 7:35 AM > > To: Russell King - ARM Linux; Rabin Vincent > > Cc: Syed Mohammed, Khasim; linux-arm-ker...@lists.arm.linux.org.uk; linux- > > o...@vger.kernel.org > > Subject: RE: Exception while handling MEM Hole on OMAP3 / ARM Cortex A8 > > > > From: Russell King - ARM Linux [li...@arm.linux.org.uk] > > Sent: Tuesday, September 08, 2009 11:23 PM > > > > > > > > Acks and tested-bys would be useful please. > > > > > > Haven't heard anything, so I've committed it as is. It is my intention > > > to push it to Linus as is in the next couple of days. > > > > Russell, > > > > I don't have ways of testing this, but I think Khasim's testing will make > > more sense, > > since he reported the bug... anyways, it's probably too late. > > > I am really sorry, wanted to try this out when RMK returns from vacation > meanwhile forgot :( > > The below logic from Rabin works great !!! no issues with this as well. And how about my revised version, which is the version which is going to be merged? -- 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