omap_hsmmc patches
Subsystems (5)
v2 cover omap_hsmmc patches
Hi
Here is V2 of some patches for omap_hsmmc.
Changes in V2:
OMAP: sDMA: descriptor autoloading feature
- removed the feature entirely as per Tony Lindgren
mmc: omap_hsmmc: fix few bugs when set the clock divisor
- added cpu_relax() as per Grazvydas Ignotas
mmc: omap_hsmmc: fix missing mmc_release_host() in no_off case
- removed {} as per Sergei Shtylyov
OMAP: hsmmc: implement clock switcher
- changed to >= threshold as per Grazvydas Ignotas
Adrian Hunter (6):
mmc: omap_hsmmc: correct debug report error status mnemonics
OMAP: board-rm680: set MMC nomux flag
mmc: omap_hsmmc: ensure pbias configuration is always done
mmc: omap_hsmmc: fix oops in omap_hsmmc_dma_cb
OMAP: hsmmc: add platform data for eMMC hardware reset gpio
mmc: omap_hsmmc: add a hardware reset before initialization
Andy Shevchenko (8):
mmc: omap_hsmmc: move hardcoded frequency constants to definition block
mmc: omap_hsmmc: reduce a bit the error handlers in probe()
mmc: omap_hsmmc: split duplicate code to calc_divisor() function
mmc: omap_hsmmc: introduce start_clock and re-use stop_clock
mmc: omap_hsmmc: fix few bugs when set the clock divisor
mmc: omap_hsmmc: split same pieces of code to separate functions
OMAP: hsmmc: implement clock switcher
mmc: omap_hsmmc: adjust host controller clock in regard to current OPP
Jarkko Lavinen (1):
OMAP: hsmmc: Do not mux the slot if non default muxing is already done
Sudhir Bera (1):
mmc: omap_hsmmc: fix missing mmc_release_host() in no_off case
arch/arm/mach-omap2/board-rm680.c | 1 + arch/arm/mach-omap2/hsmmc.c | 188 +++++++++++++++++- arch/arm/mach-omap2/hsmmc.h | 2 + arch/arm/plat-omap/include/plat/mmc.h | 9 + drivers/mmc/host/omap_hsmmc.c | 353 ++++++++++++++++++++------------- 5 files changed, 414 insertions(+), 139 deletions(-)
Regards
Adrian
PATCH v2 1/16 mmc: omap_hsmmc: fix missing mmc_release_host() in no_off case
From: Sudhir Bera <[email protected]>
In fact the no_off check here will not be hit because 'omap_hsmmc_disabled_to_sleep()' won't schedule a deeper disable in the no_off case.
--- drivers/mmc/host/omap_hsmmc.c | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-)
drivers/mmc/host/omap_hsmmc.c +4 -6
@@ -1770,15 +1770,13 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host)return 0 ;if (mmc_slot (host).no_off) -return 0 ; + goto out;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_release_host (host->mmc); -return 0 ; - } +mmc_slot (host).get_cover_state (host->dev, host->slot_id)))) + goto out;mmc_slot (host).set_power (host->dev, host->slot_id,0 ,0 ); host->vdd =0 ;
@@ -1788,7 +1786,7 @@ static int omap_hsmmc_sleep_to_off(struct omap_hsmmc_host *host) host->dpm_state == CARDSLEEP ? "CARDSLEEP" : "REGSLEEP"); host->dpm_state =OFF ; - +out:mmc_release_host (host->mmc);return 0 ;
Signature · 1 line
1.7.0.4
PATCH v2 2/16 mmc: omap_hsmmc: correct debug report error status mnemonics
In reply to Adrian HunterCERR and BADA were in the wrong place and there are only 32 not 35.
--- drivers/mmc/host/omap_hsmmc.c | 19 +++++++++++-------- 1 files changed, 11 insertions(+), 8 deletions(-)
drivers/mmc/host/omap_hsmmc.c +11 -8
@@ -970,14 +970,14 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)* Readable error output */ #ifdef CONFIG_MMC_DEBUG -static void omap_hsmmc_report_irq (struct omap_hsmmc_host *host,u32 status) +static void omap_hsmmc_dbg_report_irq (struct omap_hsmmc_host *host,u32 status) {/* --- means reserved bit without definition at documentation */ static const char *omap_hsmmc_status_bits[] = { -"CC" ,"TC" ,"BGE" ,"---" ,"BWR" ,"BRR" ,"---" ,"---" ,"CIRQ" , -"OBI" ,"---" ,"---" ,"---" ,"---" ,"---" ,"ERRI" ,"CTO" ,"CCRC" , -"CEB" ,"CIE" ,"DTO" ,"DCRC" ,"DEB" ,"---" ,"ACE" ,"---" , -"---" ,"---" ,"---" ,"CERR" ,"CERR" ,"BADA" ,"---" ,"---" ,"---" +"CC" ,"TC" ,"BGE" ,"---" ,"BWR" ,"BRR" ,"---" ,"---" , +"CIRQ" ,"OBI" ,"---" ,"---" ,"---" ,"---" ,"---" ,"ERRI" , +"CTO" ,"CCRC" ,"CEB" ,"CIE" ,"DTO" ,"DCRC" ,"DEB" ,"---" , +"ACE" ,"---" ,"---" ,"---" ,"CERR" ,"BADA" ,"---" ,"---" };char res[256 ];char *buf = res;
@@ -994,6 +994,11 @@ static void omap_hsmmc_report_irq(struct omap_hsmmc_host *host, u32 status) dev_dbg(mmc_dev(host->mmc), "%s\n", res); } +#else +static inline void omap_hsmmc_dbg_report_irq (struct omap_hsmmc_host *host, +u32 status) +{ +}#endif /* CONFIG_MMC_DEBUG */ /*
@@ -1052,9 +1057,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)dev_dbg (mmc_dev (host->mmc),"IRQ Status is %x\n" , status);if (status &ERR ) { -#ifdef CONFIG_MMC_DEBUG -omap_hsmmc_report_irq (host, status); -#endif +omap_hsmmc_dbg_report_irq (host, status);if ((status &CMD_TIMEOUT ) || (status &CMD_CRC )) {if (host->cmd) {
Signature · 1 line
1.7.0.4
PATCH v2 3/16 mmc: omap_hsmmc: move hardcoded frequency constants to definition block
In reply to Adrian HunterFrom: Andy Shevchenko <[email protected]>
Move the min and max frequency constants to the definition block in the source file.
--- drivers/mmc/host/omap_hsmmc.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
drivers/mmc/host/omap_hsmmc.c +4 -2
@@ -118,6 +118,8 @@#define MMC_TIMEOUT_MS 20#define OMAP_MMC_MASTER_CLOCK 96000000 +#define OMAP_MMC_MIN_CLOCK 400000 +#define OMAP_MMC_MAX_CLOCK 52000000#define DRIVER_NAME "omap_hsmmc"/* Timeouts for entering power saving states on inactivity, msec */
@@ -2091,8 +2093,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)if (mmc_slot (host).vcc_aux_disable_is_sleep)mmc_slot (host).no_off =1 ; - mmc->f_min =400000 ; - mmc->f_max =52000000 ; + mmc->f_min =OMAP_MMC_MIN_CLOCK ; + mmc->f_max =OMAP_MMC_MAX_CLOCK ;spin_lock_init (&host->irq_lock);
Signature · 1 line
1.7.0.4
PATCH v2 4/16 mmc: omap_hsmmc: reduce a bit the error handlers in probe()
In reply to Adrian HunterFrom: Andy Shevchenko <[email protected]>
--- drivers/mmc/host/omap_hsmmc.c | 17 ++++++----------- 1 files changed, 6 insertions(+), 11 deletions(-)
drivers/mmc/host/omap_hsmmc.c +6 -11
@@ -2119,18 +2119,11 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)/* we start off in DISABLED state */ host->dpm_state =DISABLED ; -if (clk_enable (host->iclk) !=0 ) { -clk_put (host->iclk); -clk_put (host->fclk); - goto err1; - } +if (clk_enable (host->iclk) !=0 ) + goto err2; -if (mmc_host_enable (host->mmc) !=0 ) { -clk_disable (host->iclk); -clk_put (host->iclk); -clk_put (host->fclk); - goto err1; - } +if (mmc_host_enable (host->mmc) !=0 ) + goto err3;if (cpu_is_omap2430 ()) { host->dbclk =clk_get (&pdev->dev,"mmchsdb_fck" );
@@ -2275,7 +2268,9 @@ err_irq_cd_init:free_irq (host->irq, host); err_irq:mmc_host_disable (host->mmc); +err3:clk_disable (host->iclk); +err2:clk_put (host->fclk);clk_put (host->iclk);if (host->got_dbclk) {
Signature · 1 line
1.7.0.4
PATCH v2 4/16 mmc: omap_hsmmc: reduce a bit the error handlers in probe()
Quoted 2 lines · Adrian Hunter
From: Andy Shevchenko <[email protected]>
Add patch description here.
Quoted 6 lines
Signed-off-by Andy Shevchenko <[email protected]>Signed-off-by Adrian Hunter <[email protected]>---
?drivers/mmc/host/omap_hsmmc.c | ? 17 ++++++----------- ?1 files changed, 6 insertions(+), 11 deletions(-)
<<snip>>
PATCH v2 4/16 mmc: omap_hsmmc: reduce a bit the error handlers in probe()
Quoted 5 lines · Charulatha
Quoted 2 lines · Adrian Hunter
From: Andy Shevchenko <[email protected]>
Add patch description here.
You mean something like following:
"The code contains similarities in the error path of probe function. Let's combine them at one place."
?
Quoted 14 lines
Quoted 7 lines
Signed-off-by Andy Shevchenko <[email protected]>Signed-off-by Adrian Hunter <[email protected]>---
?drivers/mmc/host/omap_hsmmc.c | ? 17 ++++++----------- ?1 files changed, 6 insertions(+), 11 deletions(-)<<snip>>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
With Best Regards, Andy Shevchenko
[PATCHv2.1] mmc: omap_hsmmc: reduce a bit the error handlers in probe()
In reply to Varadarajan, CharulathaThe code contains the similarities in the error path of probe function. Let's combine them at one place.
--- drivers/mmc/host/omap_hsmmc.c | 17 ++++++----------- 1 files changed, 6 insertions(+), 11 deletions(-)
drivers/mmc/host/omap_hsmmc.c +6 -11
@@ -2118,18 +2118,11 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)/* we start off in DISABLED state */ host->dpm_state =DISABLED ; -if (clk_enable (host->iclk) !=0 ) { -clk_put (host->iclk); -clk_put (host->fclk); - goto err1; - } +if (clk_enable (host->iclk) !=0 ) + goto err2; -if (mmc_host_enable (host->mmc) !=0 ) { -clk_disable (host->iclk); -clk_put (host->iclk); -clk_put (host->fclk); - goto err1; - } +if (mmc_host_enable (host->mmc) !=0 ) + goto err3;if (cpu_is_omap2430 ()) { host->dbclk =clk_get (&pdev->dev,"mmchsdb_fck" );
@@ -2274,7 +2267,9 @@ err_irq_cd_init:free_irq (host->irq, host); err_irq:mmc_host_disable (host->mmc); +err3:clk_disable (host->iclk); +err2:clk_put (host->fclk);clk_put (host->iclk);if (host->got_dbclk) {
Signature · 1 line
1.6.3.3
PATCH v2 5/16 mmc: omap_hsmmc: split duplicate code to calc_divisor() function
In reply to Adrian HunterFrom: Andy Shevchenko <[email protected]>
There are two places where the same calculations are done. Let's split them to separate function.
In addition the new function is simplified by usage DIV_ROUND_UP kernel macro.
--- drivers/mmc/host/omap_hsmmc.c | 45 ++++++++++++++++------------------------ 1 files changed, 18 insertions(+), 27 deletions(-)
drivers/mmc/host/omap_hsmmc.c +18 -27
@@ -584,6 +584,20 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)OMAP_HSMMC_WRITE (host->base,STAT ,STAT_CLEAR ); } +/* Calculate divisor for the given clock frequency */ +static u16 calc_divisor (struct mmc_ios *ios) +{ +u16 dsor =0 ; + +if (ios->clock) { + dsor =DIV_ROUND_UP (OMAP_MMC_MASTER_CLOCK , ios->clock); +if (dsor >250 ) + dsor =250 ; + } + +return dsor; +} +#ifdef CONFIG_PM /*
@@ -596,7 +610,6 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)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) {
@@ -675,21 +688,10 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)break ; } -if (ios->clock) { - dsor =OMAP_MMC_MASTER_CLOCK / ios->clock; -if (dsor <1 ) - dsor =1 ; - -if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock) - dsor++; - -if (dsor >250 ) - dsor =250 ; - } -OMAP_HSMMC_WRITE (host->base,SYSCTL ,OMAP_HSMMC_READ (host->base,SYSCTL ) & ~CEN ); -OMAP_HSMMC_WRITE (host->base,SYSCTL , (dsor <<6 ) | (DTO <<16 )); +OMAP_HSMMC_WRITE (host->base,SYSCTL , + (calc_divisor (ios) <<6 ) | (DTO <<16 ));OMAP_HSMMC_WRITE (host->base,SYSCTL ,OMAP_HSMMC_READ (host->base,SYSCTL ) |ICE );
@@ -1530,7 +1532,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)static void omap_hsmmc_set_ios (struct mmc_host *mmc,struct mmc_ios *ios) {struct omap_hsmmc_host *host =mmc_priv (mmc); -u16 dsor =0 ;unsigned long regval;unsigned long timeout;u32 con;
@@ -1594,21 +1595,11 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } -if (ios->clock) { - dsor =OMAP_MMC_MASTER_CLOCK / ios->clock; -if (dsor <1 ) - dsor =1 ; - -if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock) - dsor++; - -if (dsor >250 ) - dsor =250 ; - }omap_hsmmc_stop_clock (host); + regval =OMAP_HSMMC_READ (host->base,SYSCTL ); regval = regval & ~(CLKD_MASK ); - regval = regval | (dsor <<6 ) | (DTO <<16 ); + regval = regval | (calc_divisor (ios) <<6 ) | (DTO <<16 );OMAP_HSMMC_WRITE (host->base,SYSCTL , regval);OMAP_HSMMC_WRITE (host->base,SYSCTL ,OMAP_HSMMC_READ (host->base,SYSCTL ) |ICE );
Signature · 1 line
1.7.0.4
[PATCHv2.1] mmc: omap_hsmmc: split duplicate code to calc_divisor() function
There are two places where the same calculations are done. Let's split them to separate function.
In addition the new function is simplified by usage DIV_ROUND_UP kernel macro.
--- drivers/mmc/host/omap_hsmmc.c | 46 +++++++++++++++++------------------------ 1 files changed, 19 insertions(+), 27 deletions(-)
drivers/mmc/host/omap_hsmmc.c +19 -27
@@ -17,6 +17,7 @@#include <linux/module.h> #include <linux/init.h> +#include <linux/kernel.h> #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/interrupt.h>
@@ -584,6 +585,20 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)OMAP_HSMMC_WRITE (host->base,STAT ,STAT_CLEAR ); } +/* Calculate divisor for the given clock frequency */ +static u16 calc_divisor (struct mmc_ios *ios) +{ +u16 dsor =0 ; + +if (ios->clock) { + dsor =DIV_ROUND_UP (OMAP_MMC_MASTER_CLOCK , ios->clock); +if (dsor >250 ) + dsor =250 ; + } + +return dsor; +} +#ifdef CONFIG_PM /*
@@ -596,7 +611,6 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)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) {
@@ -675,21 +689,10 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)break ; } -if (ios->clock) { - dsor =OMAP_MMC_MASTER_CLOCK / ios->clock; -if (dsor <1 ) - dsor =1 ; - -if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock) - dsor++; - -if (dsor >250 ) - dsor =250 ; - } -OMAP_HSMMC_WRITE (host->base,SYSCTL ,OMAP_HSMMC_READ (host->base,SYSCTL ) & ~CEN ); -OMAP_HSMMC_WRITE (host->base,SYSCTL , (dsor <<6 ) | (DTO <<16 )); +OMAP_HSMMC_WRITE (host->base,SYSCTL , + (calc_divisor (ios) <<6 ) | (DTO <<16 ));OMAP_HSMMC_WRITE (host->base,SYSCTL ,OMAP_HSMMC_READ (host->base,SYSCTL ) |ICE );
@@ -1527,7 +1530,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)static void omap_hsmmc_set_ios (struct mmc_host *mmc,struct mmc_ios *ios) {struct omap_hsmmc_host *host =mmc_priv (mmc); -u16 dsor =0 ;unsigned long regval;unsigned long timeout;u32 con;
@@ -1591,21 +1593,11 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } -if (ios->clock) { - dsor =OMAP_MMC_MASTER_CLOCK / ios->clock; -if (dsor <1 ) - dsor =1 ; - -if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock) - dsor++; - -if (dsor >250 ) - dsor =250 ; - }omap_hsmmc_stop_clock (host); + regval =OMAP_HSMMC_READ (host->base,SYSCTL ); regval = regval & ~(CLKD_MASK ); - regval = regval | (dsor <<6 ) | (DTO <<16 ); + regval = regval | (calc_divisor (ios) <<6 ) | (DTO <<16 );OMAP_HSMMC_WRITE (host->base,SYSCTL , regval);OMAP_HSMMC_WRITE (host->base,SYSCTL ,OMAP_HSMMC_READ (host->base,SYSCTL ) |ICE );
Signature · 1 line
1.6.3.3
PATCH v2 6/16 mmc: omap_hsmmc: introduce start_clock and re-use stop_clock
In reply to Adrian HunterFrom: Andy Shevchenko <[email protected]>
There is similar piece of code in two functions which enables clock. Split this code to omap_hsmmc_start_clock(). Re-use omap_hsmmc_stop_clock() in omap_hsmmc_context_restore() as well.
--- drivers/mmc/host/omap_hsmmc.c | 19 +++++++++++++------ 1 files changed, 13 insertions(+), 6 deletions(-)
drivers/mmc/host/omap_hsmmc.c +13 -6
@@ -548,6 +548,15 @@ static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) }/* +* Start clock to the card +*/ +static void omap_hsmmc_start_clock (struct omap_hsmmc_host *host) +{ +OMAP_HSMMC_WRITE (host->base,SYSCTL , +OMAP_HSMMC_READ (host->base,SYSCTL ) |CEN ); +} + +/* * Stop clock to the card */ static void omap_hsmmc_stop_clock (struct omap_hsmmc_host *host)
@@ -688,8 +697,8 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)break ; } -OMAP_HSMMC_WRITE (host->base,SYSCTL , -OMAP_HSMMC_READ (host->base,SYSCTL ) & ~CEN ); +omap_hsmmc_stop_clock (host); +OMAP_HSMMC_WRITE (host->base,SYSCTL , (calc_divisor (ios) <<6 ) | (DTO <<16 )); OMAP_HSMMC_WRITE(host->base, SYSCTL,
@@ -700,8 +709,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) && time_before(jiffies, timeout)) ; -OMAP_HSMMC_WRITE (host->base,SYSCTL , -OMAP_HSMMC_READ (host->base,SYSCTL ) |CEN ); +omap_hsmmc_start_clock (host); con =OMAP_HSMMC_READ (host->base,CON );if (ios->bus_mode ==MMC_BUSMODE_OPENDRAIN )
@@ -1610,8 +1618,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) && time_before(jiffies, timeout))msleep (1 ); -OMAP_HSMMC_WRITE (host->base,SYSCTL , -OMAP_HSMMC_READ (host->base,SYSCTL ) |CEN ); +omap_hsmmc_start_clock (host);if (do_send_init_stream)send_init_stream (host);
Signature · 1 line
1.7.0.4
PATCH v2 7/16 mmc: omap_hsmmc: fix few bugs when set the clock divisor
In reply to Adrian HunterFrom: Andy Shevchenko <[email protected]>
There are two pieces of code which similar, but not the same. Each of them contains a bug.
The SYSCTL register should be read before write in the omap_hsmmc_context_restore() to remain the state of the reserved bits.
Before set the clock divisor and DTO bits the value from the SYSCTL register should be masked properly. We were lucky to have no problems with DTO bits. So, make sure we have clear DTO bits properly in the omap_hsmmc_set_ios().
Additionally get rid of msleep(1). The actual time rare higher than 30us on OMAP 3630.
The result pieces of code are split to omap_hsmmc_set_clock() function.
--- drivers/mmc/host/omap_hsmmc.c | 59 +++++++++++++++++++--------------------- 1 files changed, 28 insertions(+), 31 deletions(-)
drivers/mmc/host/omap_hsmmc.c +28 -31
@@ -607,6 +607,32 @@ static u16 calc_divisor(struct mmc_ios *ios)return dsor; } +static void omap_hsmmc_set_clock (struct omap_hsmmc_host *host) +{ +struct mmc_ios *ios = &host->mmc->ios; +unsigned long regval; +unsigned long timeout; + +dev_dbg (mmc_dev (host->mmc),"Set clock to %uHz\n" , ios->clock); + +omap_hsmmc_stop_clock (host); + + regval =OMAP_HSMMC_READ (host->base,SYSCTL ); + regval = regval & ~(CLKD_MASK |DTO_MASK ); + regval = regval | (calc_divisor (ios) <<6 ) | (DTO <<16 ); +OMAP_HSMMC_WRITE (host->base,SYSCTL , regval); +OMAP_HSMMC_WRITE (host->base,SYSCTL , +OMAP_HSMMC_READ (host->base,SYSCTL ) |ICE ); + +/* Wait till the ICS bit is set */ + timeout = jiffies +msecs_to_jiffies (MMC_TIMEOUT_MS ); +while ((OMAP_HSMMC_READ (host->base,SYSCTL ) &ICS ) !=ICS + &&time_before (jiffies, timeout)) +cpu_relax (); + +omap_hsmmc_start_clock (host); +} +#ifdef CONFIG_PM /*
@@ -697,19 +723,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)break ; } -omap_hsmmc_stop_clock (host); - -OMAP_HSMMC_WRITE (host->base,SYSCTL , - (calc_divisor (ios) <<6 ) | (DTO <<16 )); -OMAP_HSMMC_WRITE (host->base,SYSCTL , -OMAP_HSMMC_READ (host->base,SYSCTL ) |ICE ); - - timeout = jiffies +msecs_to_jiffies (MMC_TIMEOUT_MS ); -while ((OMAP_HSMMC_READ (host->base,SYSCTL ) &ICS ) !=ICS - &&time_before (jiffies, timeout)) - ; - -omap_hsmmc_start_clock (host); +omap_hsmmc_set_clock (host); con =OMAP_HSMMC_READ (host->base,CON );if (ios->bus_mode ==MMC_BUSMODE_OPENDRAIN )
@@ -1540,8 +1554,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)static void omap_hsmmc_set_ios (struct mmc_host *mmc,struct mmc_ios *ios) {struct omap_hsmmc_host *host =mmc_priv (mmc); -unsigned long regval; -unsigned long timeout;u32 con;int do_send_init_stream =0 ;
@@ -1603,22 +1615,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } -omap_hsmmc_stop_clock (host); - - regval =OMAP_HSMMC_READ (host->base,SYSCTL ); - regval = regval & ~(CLKD_MASK ); - regval = regval | (calc_divisor (ios) <<6 ) | (DTO <<16 ); -OMAP_HSMMC_WRITE (host->base,SYSCTL , regval); -OMAP_HSMMC_WRITE (host->base,SYSCTL , -OMAP_HSMMC_READ (host->base,SYSCTL ) |ICE ); - -/* Wait till the ICS bit is set */ - timeout = jiffies +msecs_to_jiffies (MMC_TIMEOUT_MS ); -while ((OMAP_HSMMC_READ (host->base,SYSCTL ) &ICS ) !=ICS - &&time_before (jiffies, timeout)) -msleep (1 ); - -omap_hsmmc_start_clock (host); +omap_hsmmc_set_clock (host);if (do_send_init_stream)send_init_stream (host);
Signature · 1 line
1.7.0.4
PATCH v2 8/16 mmc: omap_hsmmc: split same pieces of code to separate functions
In reply to Adrian HunterFrom: Andy Shevchenko <[email protected]>
There are few places with the same functionality. This patch creates two functions omap_hsmmc_set_bus_width() and omap_hsmmc_set_bus_mode() to do the job.
--- drivers/mmc/host/omap_hsmmc.c | 85 ++++++++++++++++++++--------------------- 1 files changed, 41 insertions(+), 44 deletions(-)
drivers/mmc/host/omap_hsmmc.c +41 -44
@@ -633,6 +633,41 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)omap_hsmmc_start_clock (host); } +static void omap_hsmmc_set_bus_width (struct omap_hsmmc_host *host) +{ +struct mmc_ios *ios = &host->mmc->ios; +u32 con; + + 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 ; + } +} + +static void omap_hsmmc_set_bus_mode (struct omap_hsmmc_host *host) +{ +struct mmc_ios *ios = &host->mmc->ios; +u32 con; + + con =OMAP_HSMMC_READ (host->base,CON ); +if (ios->bus_mode ==MMC_BUSMODE_OPENDRAIN ) +OMAP_HSMMC_WRITE (host->base,CON , con |OD ); +else +OMAP_HSMMC_WRITE (host->base,CON , con & ~OD ); +} +#ifdef CONFIG_PM /*
@@ -644,7 +679,7 @@ 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;int context_loss =0 ; -u32 hctl, capa, con; +u32 hctl, capa;unsigned long timeout;if (pdata->get_context_loss_count) {
@@ -706,30 +741,12 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)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 ; - } +omap_hsmmc_set_bus_width (host);omap_hsmmc_set_clock (host); - con =OMAP_HSMMC_READ (host->base,CON ); -if (ios->bus_mode ==MMC_BUSMODE_OPENDRAIN ) -OMAP_HSMMC_WRITE (host->base,CON , con |OD ); -else -OMAP_HSMMC_WRITE (host->base,CON , con & ~OD ); +omap_hsmmc_set_bus_mode (host); + out: host->context_loss = context_loss;
@@ -1554,7 +1571,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)static void omap_hsmmc_set_ios (struct mmc_host *mmc,struct mmc_ios *ios) {struct omap_hsmmc_host *host =mmc_priv (mmc); -u32 con;int do_send_init_stream =0 ;mmc_host_enable (host->mmc);
@@ -1580,22 +1596,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)/* 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 : -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 ; - } +omap_hsmmc_set_bus_width (host);if (host->pdata->controller_flags &OMAP_HSMMC_SUPPORTS_DUAL_VOLT ) {/* Only MMC1 can interface at 3V without some flavor
@@ -1620,11 +1621,7 @@ static void omap_hsmmc_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 , con |OD ); -else -OMAP_HSMMC_WRITE (host->base,CON , con & ~OD ); +omap_hsmmc_set_bus_mode (host);if (host->power_mode ==MMC_POWER_OFF )mmc_host_disable (host->mmc);
Signature · 1 line
1.7.0.4
PATCH v2 9/16 OMAP: hsmmc: Do not mux the slot if non default muxing is already done
In reply to Adrian HunterFrom: Jarkko Lavinen <[email protected]>
Allow the bootloader do all the muxing.
--- arch/arm/mach-omap2/hsmmc.c | 3 ++- arch/arm/mach-omap2/hsmmc.h | 1 + 2 files changed, 3 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/hsmmc.c +2 -1
@@ -440,7 +440,8 @@ void __init omap_init_hsmmc(struct omap2_hsmmc_info *hsmmcinfo, int ctrl_nr)pr_err ("%s fails!\n" , __func__); goto done; } -omap_hsmmc_mux (mmc_data, (ctrl_nr -1 )); +if (!hsmmcinfo->nomux) +omap_hsmmc_mux (mmc_data, (ctrl_nr -1 )); name ="omap_hsmmc" ; ohl = omap_hsmmc_latency;
arch/arm/mach-omap2/hsmmc.h +1 -0
@@ -19,6 +19,7 @@ struct omap2_hsmmc_info {bool power_saving;/* Try to sleep or power off when possible */ bool no_off;/* power_saving and power is not to go off */ bool vcc_aux_disable_is_sleep;/* Regulator off remapped to sleep */ +bool nomux;/* No default muxing for this slot */ int gpio_cd;/* or -EINVAL */ int gpio_wp;/* or -EINVAL */ char *name;/* or NULL for default */
Signature · 1 line
1.7.0.4
PATCH v2 10/16 OMAP: board-rm680: set MMC nomux flag
In reply to Adrian HunterLet the bootloader do all the pad configuration.
--- arch/arm/mach-omap2/board-rm680.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/board-rm680.c +1 -0
@@ -116,6 +116,7 @@ static struct omap2_hsmmc_info mmc[] __initdata = { .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED, .gpio_cd = -EINVAL, .gpio_wp = -EINVAL, + .nomux = true, }, {/* Terminator */ } };
Signature · 1 line
1.7.0.4
PATCH v2 11/16 mmc: omap_hsmmc: ensure pbias configuration is always done
In reply to Adrian HunterGo through the driver's set_power() functions rather than calling regulator_enable/disable() directly because otherwise pbias configuration for MMC1 is not done.
--- drivers/mmc/host/omap_hsmmc.c | 17 ++++++++--------- 1 files changed, 8 insertions(+), 9 deletions(-)
drivers/mmc/host/omap_hsmmc.c +8 -9
@@ -445,15 +445,14 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)* framework is fixed, we need a workaround like this * (which is safe for MMC, but not in general). */ -if (regulator_is_enabled (host->vcc) >0 ) { -regulator_enable (host->vcc); -regulator_disable (host->vcc); - } -if (host->vcc_aux) { -if (regulator_is_enabled (reg) >0 ) { -regulator_enable (reg); -regulator_disable (reg); - } +if (regulator_is_enabled (host->vcc) >0 || + (host->vcc_aux &®ulator_is_enabled (host->vcc_aux))) { +int vdd =ffs (mmc_slot (host).ocr_mask) -1 ; + +mmc_slot (host).set_power (host->dev, host->slot_id, +1 , vdd); +mmc_slot (host).set_power (host->dev, host->slot_id, +0 ,0 ); } }
Signature · 1 line
1.7.0.4
PATCH v2 11/16 mmc: omap_hsmmc: ensure pbias configuration is always done
Quoted 3 lines · Adrian Hunter
Go through the driver's
set_power()functions rather than calling regulator_enable/disable() directly because otherwise pbias configuration for MMC1 is not done.
Hi Chris,
Are you OK to queue this patch as bug fix. Rest of the patches of this series is either
merged or not needed. Should I rebase and repost this alone ?
FWIW:
Quoted 41 lines
Signed-off-by Adrian Hunter <[email protected]>---
?drivers/mmc/host/omap_hsmmc.c | ? 17 ++++++++--------- ?1 files changed, 8 insertions(+), 9 deletions(-)drivers/mmc/host/omap_hsmmc.c +0
-0@@ -445,15 +445,14 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)? ? ? ? ? ? ? ?* framework is fixed, we need a workaround like this ? ? ? ? ? ? ? ?* (which is safe for MMC, but not in general).
? ? ? ? ? ? ? ?*/
- ? ? ? ? ? ? ? if (regulator_is_enabled(host->vcc)> 0) {
- ? ? ? ? ? ? ? ? ? ? ?regulator_enable(host->vcc);
- ? ? ? ? ? ? ? ? ? ? ?regulator_disable(host->vcc);
- ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? if (host->vcc_aux) {
- ? ? ? ? ? ? ? ? ? ? ? if (regulator_is_enabled(reg)> 0) {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?regulator_enable(reg);
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?regulator_disable(reg);
- ? ? ? ? ? ? ? ? ? ? ? }
+ ? ? ? ? ? ? ? if (regulator_is_enabled(host->vcc)> 0 ||
+ ? ? ? ? ? ? ? ? ? (host->vcc_aux&®ulator_is_enabled(host->vcc_aux))) {
+ ? ? ? ? ? ? ? ? ? ? ? int vdd = ffs(mmc_slot(host).ocr_mask) - 1; +
+ ? ? ? ? ? ? ? ? ? ? ? mmc_slot(host).set_power(host->dev,host->slot_id,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?1, vdd);
+ ? ? ? ? ? ? ? ? ? ? ? mmc_slot(host).set_power(host->dev,host->slot_id,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0, 0);
? ? ? ? ? ? ? ?}
? ? ? ?}--
1.7.0.4--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html
PATCH v2 11/16 mmc: omap_hsmmc: ensure pbias configuration is always done
Hi,
Quoted 4 lines · Balaji
Quoted 3 lines · Adrian Hunter
Go through the driver's
set_power()functions rather than calling regulator_enable/disable() directly because otherwise pbias configuration for MMC1 is not done.
Quoted 8 lines
Hi Chris,
Are you OK to queue this patch as bug fix. Rest of the patches of this series is either
merged or not needed. Should I rebase and repost this alone ?FWIW:
Acked-by Balaji T K <[email protected]>
Thanks, I've pushed this to mmc-next for 3.2 now.
- Chris.
Signature · 2 lines
Chris Ball <[email protected]> <http://printf.net/> One Laptop Per Child
PATCH v2 12/16 mmc: omap_hsmmc: fix oops in omap_hsmmc_dma_cb
In reply to Adrian HunterIn the case of an I/O error, the DMA will have been cleaned up in the MMC interrupt and the request structure pointer will be null.
In that case, it is essential to check if the DMA
DMA is over before dereferencing host->mrq->data.
Oops as follows:
<3>[ 2293.695281] wl1271: ERROR sdio read failed (-110) <1>[ 2293.695739] Unable to handle kernel NULL pointer dereference at virtual address 00000004 <1>[ 2293.703094] pgd = b0004000 <1>[ 2293.705780] [00000004] *pgd=00000000 <0>[ 2293.709381] Internal error: Oops: 17 [#1] PREEMPT <0>[ 2293.714080] last sysfs file: /sys/devices/platform/omapdss/manager0/cpr_enable <4>[ 2293.721313] Modules linked in: ext2 dm_crypt xt_NFLOG xt_rateest
xt_RATEEST xt_condition iptable_filter ip_tables dm_mod xt_IDLETIMER nfnetlink_log nfnetlink as3645a ad58xx smiapp smiapp_power omap3_isp iovmm omap3_iommu iommu2 iommu wl12xx_spi bnep omaplfb bridgedriver g_file_storage cmt_speech ssi_protocol phonet hsi_char wl12xx_sdio wl12xx pvrsrvkm omap_ssi mailbox_mach vibra_spi radio_wl1273 mailbox bcm4751_gps lis3lv02d_i2c ak8975 lis3lv02d leds_lp5521 apds990x pn544 rtc_twl4030 twl4030_keypad twl4030_pwrbutton cmt twl5031_aci hci_h4p
<4>[ 2293.769287] CPU: 0 Not tainted (2.6.32.36-dfl61-20111603 #1) <4>[ 2293.775329] PC is at omap_hsmmc_dma_cb+0x18/0x140 <4>[ 2293.780029] LR is at omap2_dma_irq_handler+0x244/0x28c <4>[ 2293.785156] pc : [<b024e180>] lr : [<b0049ed0>] psr: a00001d3 <4>[ 2293.785186] sp : edfb3c48 ip : edfb3bf8 fp : edfb3d3c <4>[ 2293.796661] r10: fa05632c r9 : fa056000 r8 : ee4889c0 <4>[ 2293.801910] r7 : 00000020 r6 : 00000001 r5 : edfb2000 r4 : ee53e1c0 <4>[ 2293.808441] r3 : 00000000 r2 : edfb3c48 r1 : 00000020 r0 : 00000007 <4>[ 2293.814971] Flags: NzCv IRQs off FIQs off Mode SVC_32 ISA ARM Segment kernel <4>[ 2293.822479] Control: 10c5387d Table: bc9f4019 DAC: 00000017 <0>[ 2293.828247] Process phy0 (pid: 313, stack limit = 0xedfb22e8) <0>[ 2293.833984] Stack: (0xedfb3c48 to 0xedfb4000) ... <4>[ 2294.084320] [<b024e180>] (omap_hsmmc_dma_cb+0x18/0x140) from [<b0049ed0>] (omap2_dma_irq_handler+0x244/0x28c) <4>[ 2294.094268] [<b0049ed0>] (omap2_dma_irq_handler+0x244/0x28c) from [<b0093d44>] (handle_IRQ_event+0x34/0xf0) <4>[ 2294.104034] [<b0093d44>] (handle_IRQ_event+0x34/0xf0) from [<b0095bec>] (handle_level_irq+0xcc/0x170) <4>[ 2294.113250] [<b0095bec>] (handle_level_irq+0xcc/0x170) from [<b002c068>] (asm_do_IRQ+0x68/0x84) <4>[ 2294.121978] [<b002c068>] (asm_do_IRQ+0x68/0x84) from [<b002ca84>] (__irq_svc+0x44/0xa8) <4>[ 2294.129974] Exception stack(0xedfb3cc0 to 0xedfb3d08) <4>[ 2294.135040] 3cc0: 0021d5cd 00000000 3d20cc2d 00000002 edf7dd40 edfb2000 edf7dee8 edf7ddd8 <4>[ 2294.143249] 3ce0: 00000001 00000000 ee516080 edfb3d3c b04880b8 edfb3d08 b0059e5c b0344184 <4>[ 2294.151428] 3d00: 00000053 ffffffff <4>[ 2294.154968] [<b002ca84>] (__irq_svc+0x44/0xa8) from [<b0344184>] (schedule+0x248/0x3a8) <4>[ 2294.162963] [<b0344184>] (schedule+0x248/0x3a8) from [<b03448ac>] (schedule_timeout+0x1c/0x224) <4>[ 2294.171691] [<b03448ac>] (schedule_timeout+0x1c/0x224) from [<b0344738>] (wait_for_common+0xe8/0x1a8) <4>[ 2294.180938] [<b0344738>] (wait_for_common+0xe8/0x1a8) from [<b02459f8>] (mmc_wait_for_req+0x110/0x120) <4>[ 2294.190277] [<b02459f8>] (mmc_wait_for_req+0x110/0x120) from [<b0249bac>] (mmc_io_rw_extended+0x178/0x1e0) <4>[ 2294.199951] [<b0249bac>] (mmc_io_rw_extended+0x178/0x1e0) from [<b024ab54>] (sdio_io_rw_ext_helper+0x164/0x190) <4>[ 2294.210052] [<b024ab54>] (sdio_io_rw_ext_helper+0x164/0x190) from [<b024aba0>] (sdio_writesb+0x20/0x24) <4>[ 2294.219512] [<b024aba0>] (sdio_writesb+0x20/0x24) from [<af0d50e0>] (wl1271_sdio_raw_write+0x64/0xa4 [wl12xx_sdio]) <4>[ 2294.230041] [<af0d50e0>] (wl1271_sdio_raw_write+0x64/0xa4 [wl12xx_sdio]) from [<af0bd4bc>] (wl1271_tx_work_locked+0x548/0x5fc [wl12xx]) <4>[ 2294.242218] [<af0bd4bc>] (wl1271_tx_work_locked+0x548/0x5fc [wl12xx]) from [<af0ba944>] (wl1271_irq_work+0x230/0x314 [wl12xx]) <4>[ 2294.253631] [<af0ba944>] (wl1271_irq_work+0x230/0x314 [wl12xx]) from [<b00725ac>] (worker_thread+0x174/0x224) <4>[ 2294.263519] [<b00725ac>] (worker_thread+0x174/0x224) from [<b0075bac>] (kthread+0x7c/0x84) <4>[ 2294.271820] [<b0075bac>] (kthread+0x7c/0x84) from [<b002d950>] (kernel_thread_exit+0x0/0x8) <0>[ 2294.280181] Code: e5923008 e1a0200d e3c25d7f e3c5503f (e5936004) <4>[ 2294.286529] ---[ end trace e8fb05c679bd87ff ]---
--- drivers/mmc/host/omap_hsmmc.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
drivers/mmc/host/omap_hsmmc.c +2 -1
@@ -1364,7 +1364,7 @@ static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host,static void omap_hsmmc_dma_cb (int lch,u16 ch_status,void *cb_data) {struct omap_hsmmc_host *host = cb_data; -struct mmc_data *data = host->mrq->data; +struct mmc_data *data;int dma_ch, req_in_progress;if (!(ch_status &OMAP_DMA_BLOCK_IRQ )) {
@@ -1379,6 +1379,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)return ; } + data = host->mrq->data; host->dma_sg_idx++;if (host->dma_sg_idx < host->dma_len) {/* Fire up the next transfer. */
Signature · 1 line
1.7.0.4
PATCH v2 13/16 OMAP: hsmmc: implement clock switcher
In reply to Adrian HunterFrom: Andy Shevchenko <[email protected]>
There are 3 new platform data methods which should help us to do a clock switching when notification is happened or request is started.
The purpose of the patch is to avoid high frequency of MMC controller on low OPPs due to an HW bug in OMAP 3630.
The algorithm:
- the PM governor switches the clock of L3 (and therefore L4) bus on demand
- the MMC controller clock should follow the change
We have considered two OPPs for L3/L4 bus. Thus, we have corresponding flow:
- OPP1 -> OPP2 (in case of abort - OPP1)
- OPP2 -> OPP1 (in case of abort - OPP2)
During idle the MMC gates functional clock and we don't care about the frequency. Most important to get proper solution when notification comes during request. Then:
- in case of OPP1 -> OPP2 we update frequency limit and it will be used for new coming requests (it assumes the current frequency of the controller is lower then new one)
- otherwise we wait until no device has used higher frequency then upcoming one
Known issues and limitations:
- originally a clock notifier was used for the core L4 iclk but for upstream Adrian changed to a cpufreq notifier where we assume OPP1 below 400MHz and OPP2 above 400MHz
--- arch/arm/mach-omap2/hsmmc.c | 180 ++++++++++++++++++++++++++++++++- arch/arm/plat-omap/include/plat/mmc.h | 8 ++ 2 files changed, 187 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/hsmmc.c +179 -1
@@ -10,10 +10,15 @@* published by the Free Software Foundation. */ #include <linux/kernel.h> +#include <linux/err.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/mmc/card.h> #include <mach/hardware.h> +#include <plat/clock.h> #include <plat/mmc.h> #include <plat/omap-pm.h> #include <plat/mux.h>
@@ -23,6 +28,8 @@#include "hsmmc.h" #include "control.h" +#define HSMMC_MAX_FREQ 48000000 +#if defined(CONFIG_MMC_OMAP_HS ) || defined(CONFIG_MMC_OMAP_HS_MODULE )static u16 control_pbias_offset;
@@ -203,6 +210,155 @@ static int nop_mmc_set_power(struct device *dev, int slot, int power_on,return 0 ; } +#ifdef CONFIG_ARCH_OMAP3 +static struct hsmmc_max_freq_info { +struct device *dev; +int freq; +int high_speed; +} hsmmc_max_freq_info[OMAP34XX_NR_MMC ]; + +static unsigned int hsmmc_max_freq =HSMMC_MAX_FREQ ; +static DEFINE_SPINLOCK (hsmmc_max_freq_lock); + +static DECLARE_WAIT_QUEUE_HEAD (hsmmc_max_freq_wq); + +static int hsmmc_high_speed (struct device *dev) +{ +void *drvdata =platform_get_drvdata (to_platform_device (dev)); + struct mmc_host *mmc = container_of(drvdata, struct mmc_host, private); + +return mmc->card ?mmc_card_highspeed (mmc->card) :0 ; +} + +static unsigned int hsmmc_get_max_freq_hs (struct device *dev,int high_speed) +{ +return high_speed ? hsmmc_max_freq : hsmmc_max_freq >>1 ; +} + +static unsigned int hsmmc_get_max_freq (struct device *dev) +{ +return hsmmc_get_max_freq_hs (dev,hsmmc_high_speed (dev)); +} + +static unsigned int hsmmc_active (struct device *dev,unsigned int target_freq) +{ +int high_speed =hsmmc_high_speed (dev); +int i; +unsigned int max_freq, freq; +unsigned long flags; + +spin_lock_irqsave (&hsmmc_max_freq_lock, flags); + max_freq =hsmmc_get_max_freq_hs (dev, high_speed); + freq =min (target_freq, max_freq); +for (i =0 ; i <ARRAY_SIZE (hsmmc_max_freq_info); i++) { +if (!hsmmc_max_freq_info[i].dev) { + hsmmc_max_freq_info[i].dev = dev; + hsmmc_max_freq_info[i].freq = freq; + hsmmc_max_freq_info[i].high_speed = high_speed; +break ; + } + } +spin_unlock_irqrestore (&hsmmc_max_freq_lock, flags); +return freq; +} + +static void hsmmc_inactive (struct device *dev) +{ +int i; +unsigned long flags; + +spin_lock_irqsave (&hsmmc_max_freq_lock, flags); +for (i =0 ; i <ARRAY_SIZE (hsmmc_max_freq_info); i++) { +if (hsmmc_max_freq_info[i].dev == dev) { + hsmmc_max_freq_info[i].dev =NULL ; +spin_unlock_irqrestore (&hsmmc_max_freq_lock, flags); +/* +* Wake up the queue only in case we deactivated a +* device. +*/ +wake_up (&hsmmc_max_freq_wq); +return ; + } + } +spin_unlock_irqrestore (&hsmmc_max_freq_lock, flags); +} + +static bool hsmmc_max_freq_ok (void ) +{ +int i; +bool ret = true; +unsigned long flags; + +spin_lock_irqsave (&hsmmc_max_freq_lock, flags); +for (i =0 ; i <ARRAY_SIZE (hsmmc_max_freq_info); i++) { +if (hsmmc_max_freq_info[i].dev) { +unsigned int max_freq; + +if (hsmmc_max_freq_info[i].high_speed) + max_freq =HSMMC_MAX_FREQ >>1 ; +else + max_freq =HSMMC_MAX_FREQ >>2 ; + +if (hsmmc_max_freq_info[i].freq > max_freq) { + ret = false; +break ; + } + } + } +spin_unlock_irqrestore (&hsmmc_max_freq_lock, flags); +return ret; +} + +static int hsmmc_clk_notifier (struct notifier_block *nb,unsigned long event, +void *data) +{ +struct cpufreq_freqs *freqs = data; +unsigned int threshold =400000 ;/* between opp1 and opp2 */ + +switch (event) { +case CPUFREQ_PRECHANGE : +if (freqs->new < threshold && freqs->old >= threshold) { +/* opp2 -> opp1 */ + hsmmc_max_freq =HSMMC_MAX_FREQ >>1 ; + +/* Timeout is 1 sec */ +if (!wait_event_timeout (hsmmc_max_freq_wq, +hsmmc_max_freq_ok (), +msecs_to_jiffies (1000 ))) +pr_err ("MMC violates maximum frequency " +"constraint\n" ); + } +break ; +case CPUFREQ_POSTCHANGE : +if (freqs->old < threshold && freqs->new >= threshold) { +/* opp1 -> opp2 */ + hsmmc_max_freq =HSMMC_MAX_FREQ ; + } +break ; +default : +break ; + } + +return NOTIFY_DONE ; +} + +static struct notifier_block hsmmc_notifier_block = { + .notifier_call = hsmmc_clk_notifier, + .priority =INT_MAX , +}; + +static int __init hsmmc_init_notifier (void ) +{ +return cpufreq_register_notifier (&hsmmc_notifier_block, +CPUFREQ_TRANSITION_NOTIFIER ); +} +#else +static inline int hsmmc_init_notifier (void ) +{ +return 0 ; +} +#endif +static inline void omap_hsmmc_mux (struct omap_mmc_platform_data *mmc_controller,int controller_nr) {
@@ -401,6 +557,17 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,kfree (hc_name);return -ENODEV ; } + +/* +* The 3630's host controller cannot guarantee setup times at all +* frequencies, so notification and control of frequency changes +* is necessary. +*/ +if (cpu_is_omap3630 ()) { + mmc->get_max_freq = hsmmc_get_max_freq; + mmc->active = hsmmc_active; + mmc->inactive = hsmmc_inactive; + }return 0 ; }
@@ -507,9 +674,20 @@ void __init omap2_hsmmc_init(struct omap2_hsmmc_info *controllers) omap4_ctrl_pad_writel(reg, control_mmc1); } +/* +* The 3630's host controller cannot guarantee setup times at all +* frequencies, so notification and control of frequency changes +* is necessary. +*/ +if (cpu_is_omap3630 ()) { +if (hsmmc_init_notifier ()) { +pr_err ("Can't setup clock notifier for mmc driver!\n" ); +return ; + } + } +for (; controllers->mmc; controllers++)omap_init_hsmmc (controllers, controllers->mmc); - }#endif
arch/arm/plat-omap/include/plat/mmc.h +8 -0
@@ -27,6 +27,8 @@#define OMAP2420_MMC_SIZE OMAP1_MMC_SIZE#define OMAP2_MMC1_BASE 0x4809c000 +#define OMAP34XX_NR_MMC 3 +#define OMAP4_MMC_REG_OFFSET 0x100#define OMAP_MMC_MAX_SLOTS 2
@@ -63,6 +65,12 @@ struct omap_mmc_platform_data {/* Return context loss count due to PM states changing */ int (*get_context_loss_count)(struct device *dev); +/* Return max controller frequency for current OPP */ +unsigned int (*get_max_freq)(struct device *dev); + +unsigned int (*active)(struct device *dev,unsigned int target_freq); +void (*inactive)(struct device *dev); +u64 dma_mask;/* Integrating attributes from the omap_hwmod layer */
Signature · 1 line
1.7.0.4
Tony Lindgren
maintainerPATCH v2 13/16 OMAP: hsmmc: implement clock switcher
Quoted 7 lines · Adrian Hunter
From: Andy Shevchenko <[email protected]>
There are 3 new platform data methods which should help us to do a clock switching when notification is happened or request is started.
The purpose of the patch is to avoid high frequency of MMC controller on low OPPs due to an HW bug in OMAP 3630.
...
Quoted 22 lines
arch/arm/mach-omap2/hsmmc.c +22
-0+static int hsmmc_clk_notifier (struct notifier_block *nb,unsigned long event, +void *data) +{ +struct cpufreq_freqs *freqs = data; +unsigned int threshold =400000 ;/* between opp1 and opp2 */ + +switch (event) { +case CPUFREQ_PRECHANGE : +if (freqs->new < threshold && freqs->old >= threshold) { +/* opp2 -> opp1 */ + hsmmc_max_freq =HSMMC_MAX_FREQ >>1 ; + +/* Timeout is 1 sec */ +if (!wait_event_timeout (hsmmc_max_freq_wq, +hsmmc_max_freq_ok (), +msecs_to_jiffies (1000 ))) +pr_err ("MMC violates maximum frequency " +"constraint\n" ); + } +break ; +case CPUFREQ_POSTCHANGE : +if (freqs->old < threshold && freqs->new >= threshold) {
arch/arm/mach-omap2/hsmmc.c static int nop_mmc_set_power(struct device *dev, int slot, int power_on, · line 343
Quoted 10 lines
arch/arm/mach-omap2/hsmmc.c +10
-0+/* opp1 -> opp2 */ + hsmmc_max_freq =HSMMC_MAX_FREQ ; + } +break ; +default : +break ; + } + +return NOTIFY_DONE ; +}
I think the cpufreq notifier code should be in the driver, the platform init code should just prepare things for the driver.
Regards,
Tony
PATCH v2 14/16 mmc: omap_hsmmc: adjust host controller clock in regard to current OPP
In reply to Adrian HunterFrom: Andy Shevchenko <[email protected]>
We should like to adjust MMC host controller clock whenever the OPP is changed. OPP affects to L3/L4 bus frequency. Due to this we update the maximum frequency limits before each upcoming request and when the divisor is calculated.
--- drivers/mmc/host/omap_hsmmc.c | 65 +++++++++++++++++++++++++++++++++++++---- 1 files changed, 59 insertions(+), 6 deletions(-)
drivers/mmc/host/omap_hsmmc.c +59 -6
@@ -187,6 +187,9 @@ struct omap_hsmmc_host {int use_reg;int req_in_progress; +/* Actual output frequency of host controller */ +unsigned int freq; +struct omap_mmc_platform_data *pdata; };
@@ -592,13 +595,31 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)OMAP_HSMMC_WRITE (host->base,STAT ,STAT_CLEAR ); } +/* +* Recalculate desired clock frequency with regard to maximum possible +* frequency at current OPP. +* +* Choose either target frequency (ios->clock) or maximum possible frequency at +* current OPP (get_max_freq() returns this limit) +*/ +static void omap_hsmmc_recalc_freq (struct omap_hsmmc_host *host, +struct mmc_ios *ios) +{ +struct omap_mmc_platform_data *pdata = host->pdata; + +if (pdata->get_max_freq) + host->freq =min (ios->clock, pdata->get_max_freq (host->dev)); +else + host->freq = ios->clock; +} +/* Calculate divisor for the given clock frequency */ -static u16 calc_divisor (struct mmc_ios *ios) +static u16 calc_divisor (struct omap_hsmmc_host *host) {u16 dsor =0 ; -if (ios->clock) { - dsor =DIV_ROUND_UP (OMAP_MMC_MASTER_CLOCK , ios->clock); +if (host->freq) { + dsor =DIV_ROUND_UP (OMAP_MMC_MASTER_CLOCK , host->freq);if (dsor >250 ) dsor =250 ; }
@@ -608,17 +629,16 @@ static u16 calc_divisor(struct mmc_ios *ios)static void omap_hsmmc_set_clock (struct omap_hsmmc_host *host) { -struct mmc_ios *ios = &host->mmc->ios;unsigned long regval;unsigned long timeout; -dev_dbg (mmc_dev (host->mmc),"Set clock to %uHz\n" , ios->clock); +dev_dbg (mmc_dev (host->mmc),"Set clock to %uHz\n" , host->freq);omap_hsmmc_stop_clock (host); regval =OMAP_HSMMC_READ (host->base,SYSCTL ); regval = regval & ~(CLKD_MASK |DTO_MASK ); - regval = regval | (calc_divisor (ios) <<6 ) | (DTO <<16 ); + regval = regval | (calc_divisor (host) <<6 ) | (DTO <<16 );OMAP_HSMMC_WRITE (host->base,SYSCTL , regval);OMAP_HSMMC_WRITE (host->base,SYSCTL ,OMAP_HSMMC_READ (host->base,SYSCTL ) |ICE );
@@ -742,6 +762,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)omap_hsmmc_set_bus_width (host); +omap_hsmmc_recalc_freq (host, ios);omap_hsmmc_set_clock (host);omap_hsmmc_set_bus_mode (host);
@@ -925,6 +946,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_reqif (mrq->data && host->use_dma && dma_ch !=-1 )return ; host->mrq =NULL ; +if (host->pdata->inactive) + host->pdata->inactive (host->dev);mmc_request_done (host->mmc, mrq); }
@@ -984,6 +1007,9 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) }if ((host->data ==NULL && !host->response_busy) || cmd->error)omap_hsmmc_request_done (host, cmd->mrq); +else if (host->data ==NULL && host->response_busy && + host->pdata->inactive) + host->pdata->inactive (host->dev); }/*
@@ -1404,6 +1430,8 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)struct mmc_request *mrq = host->mrq; host->mrq =NULL ; +if (host->pdata->inactive) + host->pdata->inactive (host->dev);mmc_request_done (host->mmc, mrq); } }
@@ -1533,6 +1561,26 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)BUG_ON (host->req_in_progress);BUG_ON (host->dma_ch !=-1 ); + +if (host->pdata->active) { +unsigned int new_freq; + +/* +* active() returns minimum of two (target, maximum) +* frequencies. +*/ + new_freq = host->pdata->active (host->dev, mmc->ios.clock); + +/* +* We need to update actual frequency if it is not equal to the +* minimum of two (target and maximum) frequencies +*/ +if (host->freq != new_freq) { + host->freq = new_freq; +omap_hsmmc_set_clock (host); + } + } +if (host->protect_card) {if (host->reqs_blocked <3 ) {/*
@@ -1548,6 +1596,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)if (req->data) req->data->error = -EBADF ; req->cmd->retries =0 ; +if (host->pdata->inactive) + host->pdata->inactive (host->dev);mmc_request_done (mmc, req);return ; }else if (host->reqs_blocked)
@@ -1560,6 +1610,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)if (req->data) req->data->error = err; host->mrq =NULL ; +if (host->pdata->inactive) + host->pdata->inactive (host->dev);mmc_request_done (mmc, req);return ; }
@@ -1616,6 +1668,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } +omap_hsmmc_recalc_freq (host, ios);omap_hsmmc_set_clock (host);if (do_send_init_stream)
Signature · 1 line
1.7.0.4
PATCH v2 15/16 OMAP: hsmmc: add platform data for eMMC hardware reset gpio
In reply to Adrian HuntereMMC may have a hardware reset line connected to a gpio, so pass it to the driver.
--- arch/arm/mach-omap2/hsmmc.c | 5 +++++ arch/arm/mach-omap2/hsmmc.h | 1 + arch/arm/plat-omap/include/plat/mmc.h | 1 + 3 files changed, 7 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/hsmmc.c +5 -0
@@ -472,6 +472,11 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, mmc->slots[0 ].switch_pin = c->gpio_cd; mmc->slots[0 ].gpio_wp = c->gpio_wp; +if (c->gpio_hw_reset) + mmc->slots[0 ].gpio_hw_reset = c->gpio_hw_reset; +else + mmc->slots[0 ].gpio_hw_reset = -EINVAL ; + mmc->slots[0 ].remux = c->remux; mmc->slots[0 ].init_card = c->init_card;
arch/arm/mach-omap2/hsmmc.h +1 -0
@@ -22,6 +22,7 @@ struct omap2_hsmmc_info {bool nomux;/* No default muxing for this slot */ int gpio_cd;/* or -EINVAL */ int gpio_wp;/* or -EINVAL */ +int gpio_hw_reset;/* hardware reset */ char *name;/* or NULL for default */ struct device *dev;/* returned: pointer to mmc adapter */ int ocr_mask;/* temporary HACK */
arch/arm/plat-omap/include/plat/mmc.h +1 -0
@@ -119,6 +119,7 @@ struct omap_mmc_platform_data {int switch_pin;/* gpio (card detect) */ int gpio_wp;/* gpio (write protect) */ +int gpio_hw_reset;/* gpio (hardware reset) */ int (*set_bus_mode)(struct device *dev,int slot,int bus_mode); int (*set_power)(struct device *dev, int slot,
Signature · 1 line
1.7.0.4
Tony Lindgren
maintainerPATCH v2 15/16 OMAP: hsmmc: add platform data for eMMC hardware reset gpio
Quoted 4 lines · Adrian Hunter
eMMC may have a hardware reset line connected to a gpio, so pass it to the driver.
Signed-off-by Adrian Hunter <[email protected]>
This looks safe to merge via MMC list:
Quoted 49 lines
--- arch/arm/mach-omap2/hsmmc.c | 5 +++++ arch/arm/mach-omap2/hsmmc.h | 1 + arch/arm/plat-omap/include/plat/mmc.h | 1 + 3 files changed, 7 insertions(+), 0 deletions(-)arch/arm/mach-omap2/hsmmc.c +5
-0@@ -472,6 +472,11 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, mmc->slots[0 ].switch_pin = c->gpio_cd; mmc->slots[0 ].gpio_wp = c->gpio_wp; +if (c->gpio_hw_reset) + mmc->slots[0 ].gpio_hw_reset = c->gpio_hw_reset; +else + mmc->slots[0 ].gpio_hw_reset = -EINVAL ; + mmc->slots[0 ].remux = c->remux; mmc->slots[0 ].init_card = c->init_card;arch/arm/mach-omap2/hsmmc.h +1
-0@@ -22,6 +22,7 @@ struct omap2_hsmmc_info {bool nomux;/* No default muxing for this slot */ int gpio_cd;/* or -EINVAL */ int gpio_wp;/* or -EINVAL */ +int gpio_hw_reset;/* hardware reset */ char *name;/* or NULL for default */ struct device *dev;/* returned: pointer to mmc adapter */ int ocr_mask;/* temporary HACK */ arch/arm/plat-omap/include/plat/mmc.h +1
-0@@ -119,6 +119,7 @@ struct omap_mmc_platform_data {int switch_pin;/* gpio (card detect) */ int gpio_wp;/* gpio (write protect) */ +int gpio_hw_reset;/* gpio (hardware reset) */ int (*set_bus_mode)(struct device *dev,int slot,int bus_mode); int (*set_power)(struct device *dev, int slot,Signature · 1 line
1.7.0.4
PATCH v2 16/16 mmc: omap_hsmmc: add a hardware reset before initialization
In reply to Adrian HunterAfter a warm restart, an eMMC which cannot be powered off is in an unknown state, so reset it to be sure it will initialize.
--- drivers/mmc/host/omap_hsmmc.c | 38 +++++++++++++++++++++++++++++++++++++- 1 files changed, 37 insertions(+), 1 deletions(-)
drivers/mmc/host/omap_hsmmc.c +37 -1
@@ -530,10 +530,25 @@ static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata) }else pdata->slots[0 ].gpio_wp = -EINVAL ; +if (gpio_is_valid (pdata->slots[0 ].gpio_hw_reset)) { + ret =gpio_request (pdata->slots[0 ].gpio_hw_reset, +"mmc_hw_reset" ); +if (ret) + goto err_free_wp; + ret =gpio_direction_output (pdata->slots[0 ].gpio_hw_reset,1 ); +if (ret) + goto err_free_hw_reset; + }else + pdata->slots[0 ].gpio_hw_reset = -EINVAL ; +return 0 ; + +err_free_hw_reset: +gpio_free (pdata->slots[0 ].gpio_hw_reset); err_free_wp: -gpio_free (pdata->slots[0 ].gpio_wp); +if (gpio_is_valid (pdata->slots[0 ].gpio_wp)) +gpio_free (pdata->slots[0 ].gpio_wp); err_free_cd:if (gpio_is_valid (pdata->slots[0 ].switch_pin)) err_free_sp:
@@ -543,6 +558,8 @@ err_free_sp:static void omap_hsmmc_gpio_free (struct omap_mmc_platform_data *pdata) { +if (gpio_is_valid (pdata->slots[0 ].gpio_hw_reset)) +gpio_free (pdata->slots[0 ].gpio_hw_reset);if (gpio_is_valid (pdata->slots[0 ].gpio_wp))gpio_free (pdata->slots[0 ].gpio_wp);if (gpio_is_valid (pdata->slots[0 ].switch_pin))
@@ -803,6 +820,18 @@ static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)#endif +static void omap_hsmmc_do_hw_reset (struct omap_hsmmc_host *host) +{ +if (!gpio_is_valid (mmc_slot (host).gpio_hw_reset)) +return ; + +gpio_set_value_cansleep (mmc_slot (host).gpio_hw_reset,0 ); +udelay (9 ); +gpio_set_value_cansleep (mmc_slot (host).gpio_hw_reset,1 ); +usleep_range (1000 ,2000 ); +printk (KERN_INFO "%s: hardware reset done\n" ,mmc_hostname (host->mmc)); +} +/* * Send init stream sequence to card * before sending IDLE command
@@ -815,6 +844,13 @@ static void send_init_stream(struct omap_hsmmc_host *host)if (host->protect_card)return ; +/* +* After a warm restart, an eMMC which cannot be powered off is in an +* unknown state so reset it to be sure it will initialize. +*/ +if (mmc_slot (host).no_off) +omap_hsmmc_do_hw_reset (host); +disable_irq (host->irq);OMAP_HSMMC_WRITE (host->base,IE ,INT_EN_MASK );
Signature · 1 line
1.7.0.4
PATCH v2 16/16 mmc: omap_hsmmc: add a hardware reset before initialization
Hi,
Quoted 16 lines · Adrian Hunter
After a warm restart, an eMMC which cannot be powered off is in an unknown state, so reset it to be sure it will initialize.
Signed-off-by Adrian Hunter <[email protected]>---
?drivers/mmc/host/omap_hsmmc.c | ? 38 +++++++++++++++++++++++++++++++++++++- ?1 files changed, 37 insertions(+), 1 deletions(-)drivers/mmc/host/omap_hsmmc.c +0
-0@@ -530,10 +530,25 @@ static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)? ? ? ?} else
? ? ? ? ? ? ? ?pdata->slots[0].gpio_wp =-EINVAL;
Quoted 1 line
+ ? ? ? if (
gpio_is_valid(pdata->slots[0].gpio_hw_reset)) {
Not required as gpio_request takes care of it.
Quoted 5 lines
+ ? ? ? ? ? ? ? ret = gpio_request(pdata->slots[0].gpio_hw_reset,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"mmc_hw_reset");
+ ? ? ? ? ? ? ? if (ret)
+ ? ? ? ? ? ? ? ? ? ? ? gotoerr_free_wp;
+ ? ? ? ? ? ? ? ret =gpio_direction_output(pdata->slots[0].gpio_hw_reset, 1);
Use gpio_request_one instead.
Quoted 10 lines
+ ? ? ? ? ? ? ? if (ret)
+ ? ? ? ? ? ? ? ? ? ? ? gotoerr_free_hw_reset;
+ ? ? ? } else
+ ? ? ? ? ? ? ? pdata->slots[0].gpio_hw_reset =-EINVAL; +
? ? ? ?return 0;drivers/mmc/host/omap_hsmmc.c +3
-0+ +err_free_hw_reset: + ? ? ? gpio_free(pdata->slots[0].gpio_hw_reset);
Quoted 3 lines
?err_free_wp:
- ? ? ?gpio_free(pdata->slots[0].gpio_wp);
+ ? ? ? if (gpio_is_valid(pdata->slots[0].gpio_wp))
Not required as gpio_free takes care of it.
drivers/mmc/host/omap_hsmmc.c err_free_sp: · line 561
Quoted 9 lines
+ ? ? ? ? ? ? ?
gpio_free(pdata->slots[0].gpio_wp); ?err_free_cd:
? ? ? ?if (gpio_is_valid(pdata->slots[0].switch_pin)) ?err_free_sp:drivers/mmc/host/omap_hsmmc.c +1
-0@@ -543,6 +558,8 @@ err_free_sp: ?static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata) ?{ + ? ? ? if (gpio_is_valid(pdata->slots[0].gpio_hw_reset))
ditto
drivers/mmc/host/omap_hsmmc.c err_free_sp: · line 565
Quoted 4 lines
drivers/mmc/host/omap_hsmmc.c +1
-0+ ? ? ? ? ? ? ? gpio_free(pdata->slots[0].gpio_hw_reset); ? ? ? ?if (gpio_is_valid(pdata->slots[0].gpio_wp)) ? ? ? ? ? ? ? ?gpio_free(pdata->slots[0].gpio_wp); ? ? ? ?if (gpio_is_valid(pdata->slots[0].switch_pin))
<<snip>>
v2 cover omap_hsmmc patches
In reply to Adrian HunterHello,
it seems this series got lost in time, at least patches 01, 02, 03, 04, 05, 06, 07, 08, 12 look like valid standalone fixes and improvements to me, they don't touch other trees and still apply cleanly, so would be good to have.
Chris, can you queue these for upcoming merge window? These patches are also archived in patchwork here:
https://patchwork.kernel.org/project/linux-omap/list/?archive=both&page=8
Quoted 58 lines · Adrian Hunter
Hi
Here is V2 of some patches for
omap_hsmmc.Changes in V2:
? ? ? ?OMAP: sDMA: descriptor autoloading feature
? ? ? ? ? ? ? ?- removed the feature entirely as per Tony Lindgren? ? ? ?mmc:
omap_hsmmc: fix few bugs when set the clock divisor ? ? ? ? ? ? ? ?- addedcpu_relax()as per Grazvydas Ignotas? ? ? ?mmc:
omap_hsmmc: fix missingmmc_release_host()inno_offcase ? ? ? ? ? ? ? ?- removed {} as per Sergei Shtylyov? ? ? ?OMAP: hsmmc: implement clock switcher
? ? ? ? ? ? ? ?- changed to >= threshold as per Grazvydas IgnotasAdrian Hunter (6):
? ? ?mmc:omap_hsmmc: correct debug report error status mnemonics ? ? ?OMAP: board-rm680: set MMC nomux flag
? ? ?mmc:omap_hsmmc: ensure pbias configuration is always done ? ? ?mmc:omap_hsmmc: fix oops inomap_hsmmc_dma_cb
? ? ?OMAP: hsmmc: add platform data for eMMC hardware reset gpio ? ? ?mmc:omap_hsmmc: add a hardware reset before initializationAndy Shevchenko (8):
? ? ?mmc:omap_hsmmc: move hardcoded frequency constants to definition block ? ? ?mmc:omap_hsmmc: reduce a bit the error handlers inprobe()? ? ?mmc:omap_hsmmc: split duplicate code tocalc_divisor()function ? ? ?mmc:omap_hsmmc: introducestart_clockand re-usestop_clock? ? ?mmc:omap_hsmmc: fix few bugs when set the clock divisor
? ? ?mmc:omap_hsmmc: split same pieces of code to separate functions ? ? ?OMAP: hsmmc: implement clock switcher
? ? ?mmc:omap_hsmmc: adjust host controller clock in regard to current OPPJarkko Lavinen (1):
? ? ?OMAP: hsmmc: Do not mux the slot if non default muxing is already doneSudhir Bera (1):
? ? ?mmc:omap_hsmmc: fix missingmmc_release_host()inno_offcase?arch/arm/mach-omap2/board-rm680.c ? ? | ? ?1 + ?arch/arm/mach-omap2/hsmmc.c ? ? ? ? ? | ?188 +++++++++++++++++- ?arch/arm/mach-omap2/hsmmc.h ? ? ? ? ? | ? ?2 + ?arch/arm/plat-omap/include/plat/mmc.h | ? ?9 + ?drivers/mmc/host/omap_hsmmc.c ? ? ? ? | ?353 ++++++++++++++++++++-------------?5 files changed, 414 insertions(+), 139 deletions(-)
Regards
Adrian--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html
Signature · 1 line
Gra?vydas
v2 cover omap_hsmmc patches
Hi,
Quoted 4 lines · Grazvydas Ignotas
it seems this series got lost in time, at least patches 01, 02, 03, 04, 05, 06, 07, 08, 12 look like valid standalone fixes and improvements to me, they don't touch other trees and still apply cleanly, so would be good to have.
Yeah. I didn't merge them because Tony still has unanswered comments on the OMAP side of the patches, and they're submitted as a single patchset.
I've applied {2, 3, 5, 6, 7, 8, 12} to mmc-next for 3.1 now. 1 doesn't apply because the function doesn't exist anymore. 4 doesn't apply because iclk doesn't exist anymore.
If someone wants to look at rebasing the rest of these against mmc-next and resubmitting, I think that'd be useful.
Thanks,
- Chris.
Signature · 2 lines
Chris Ball <[email protected]> <http://printf.net/> One Laptop Per Child
v2 cover omap_hsmmc patches
Quoted 11 lines · Chris Ball
Hi,
Quoted 4 lines · Grazvydas Ignotas
it seems this series got lost in time, at least patches 01, 02, 03, 04, 05, 06, 07, 08, 12 look like valid standalone fixes and improvements to me, they don't touch other trees and still apply cleanly, so would be good to have.
Yeah. ?I didn't merge them because Tony still has unanswered comments on the OMAP side of the patches, and they're submitted as a single patchset.
Quoted 6 lines
I've applied {2, 3, 5, 6, 7, 8, 12} to mmc-next for 3.1 now. ?1 doesn't apply because the function doesn't exist anymore. ?4 doesn't apply because iclk doesn't exist anymore.
If someone wants to look at rebasing the rest of these against mmc-next and resubmitting, I think that'd be useful.
Thanks! 1 and 4 seem to be unneeded any more (I was trying them on linux-next, not noticing it was not updated for a while), and others have comments pending, so it's all done.
Quoted 8 lines
Thanks,
- Chris.
--
Chris Ball ? <[email protected]> ? <http://printf.net/>
One Laptop Per Child
Signature · 1 line
Gra?vydas
Tony Lindgren
maintainerv2 cover omap_hsmmc patches
Quoted 16 lines · Grazvydas Ignotas
Quoted 15 lines · Chris Ball
Hi,
Quoted 4 lines · Grazvydas Ignotas
it seems this series got lost in time, at least patches 01, 02, 03, 04, 05, 06, 07, 08, 12 look like valid standalone fixes and improvements to me, they don't touch other trees and still apply cleanly, so would be good to have.
Yeah. ?I didn't merge them because Tony still has unanswered comments on the OMAP side of the patches, and they're submitted as a single patchset.
I've applied {2, 3, 5, 6, 7, 8, 12} to mmc-next for 3.1 now. ?1 doesn't apply because the function doesn't exist anymore. ?4 doesn't apply because iclk doesn't exist anymore.
Quoted 6 lines
Quoted 2 lines
If someone wants to look at rebasing the rest of these against mmc-next and resubmitting, I think that'd be useful.
Thanks! 1 and 4 seem to be unneeded any more (I was trying them on linux-next, not noticing it was not updated for a while), and others have comments pending, so it's all done.
So I guess that means I don't need to look at anything, right?
Tony
Quoted 10 lines · Tony Lindgren
Quoted 7 lines · Grazvydas Ignotas
Quoted 2 lines · Chris Ball
If someone wants to look at rebasing the rest of these against mmc-next and resubmitting, I think that'd be useful.
Thanks! 1 and 4 seem to be unneeded any more (I was trying them on linux-next, not noticing it was not updated for a while), and others have comments pending, so it's all done.
So I guess that means I don't need to look at anything, right?
Yeah, these patches hit mainline already.