diff options
author | Simon Horman <horms@verge.net.au> | 2011-06-20 19:00:10 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-07-20 17:20:57 -0400 |
commit | 973ed3af1a570612771ed10dec6506c757767668 (patch) | |
tree | db993034cacfcc3f3388c43d96459a123adc32a2 | |
parent | a11862d3389d4304211eed0758f510d5e573f93c (diff) |
mmc: sdhi: Add write16_hook
Some controllers require waiting for the bus to become idle
before writing to some registers. I have implemented this
by adding a hook to sd_ctrl_write16() and implementing
a hook for SDHI which waits for the bus to become idle.
Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: Magnus Damm <magnus.damm@gmail.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/host/sh_mobile_sdhi.c | 36 | ||||
-rw-r--r-- | drivers/mmc/host/tmio_mmc.h | 5 | ||||
-rw-r--r-- | include/linux/mfd/tmio.h | 8 | ||||
-rw-r--r-- | include/linux/mmc/tmio.h | 1 |
4 files changed, 50 insertions, 0 deletions
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index ce500f03df85..774f6439d7ce 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/mmc/sh_mobile_sdhi.h> | 26 | #include <linux/mmc/sh_mobile_sdhi.h> |
27 | #include <linux/mfd/tmio.h> | 27 | #include <linux/mfd/tmio.h> |
28 | #include <linux/sh_dma.h> | 28 | #include <linux/sh_dma.h> |
29 | #include <linux/delay.h> | ||
29 | 30 | ||
30 | #include "tmio_mmc.h" | 31 | #include "tmio_mmc.h" |
31 | 32 | ||
@@ -55,6 +56,39 @@ static int sh_mobile_sdhi_get_cd(struct platform_device *pdev) | |||
55 | return -ENOSYS; | 56 | return -ENOSYS; |
56 | } | 57 | } |
57 | 58 | ||
59 | static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) | ||
60 | { | ||
61 | int timeout = 1000; | ||
62 | |||
63 | while (--timeout && !(sd_ctrl_read16(host, CTL_STATUS2) & (1 << 13))) | ||
64 | udelay(1); | ||
65 | |||
66 | if (!timeout) { | ||
67 | dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n"); | ||
68 | return -EBUSY; | ||
69 | } | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) | ||
75 | { | ||
76 | switch (addr) | ||
77 | { | ||
78 | case CTL_SD_CMD: | ||
79 | case CTL_STOP_INTERNAL_ACTION: | ||
80 | case CTL_XFER_BLK_COUNT: | ||
81 | case CTL_SD_CARD_CLK_CTL: | ||
82 | case CTL_SD_XFER_LEN: | ||
83 | case CTL_SD_MEM_CARD_OPT: | ||
84 | case CTL_TRANSACTION_CTL: | ||
85 | case CTL_DMA_ENABLE: | ||
86 | return sh_mobile_sdhi_wait_idle(host); | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
58 | static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | 92 | static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) |
59 | { | 93 | { |
60 | struct sh_mobile_sdhi *priv; | 94 | struct sh_mobile_sdhi *priv; |
@@ -86,6 +120,8 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
86 | mmc_data->hclk = clk_get_rate(priv->clk); | 120 | mmc_data->hclk = clk_get_rate(priv->clk); |
87 | mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; | 121 | mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; |
88 | mmc_data->get_cd = sh_mobile_sdhi_get_cd; | 122 | mmc_data->get_cd = sh_mobile_sdhi_get_cd; |
123 | if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT) | ||
124 | mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; | ||
89 | mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; | 125 | mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; |
90 | if (p) { | 126 | if (p) { |
91 | mmc_data->flags = p->tmio_flags; | 127 | mmc_data->flags = p->tmio_flags; |
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 0c22df0f954d..211ef6e7a820 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h | |||
@@ -153,6 +153,11 @@ static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) | |||
153 | 153 | ||
154 | static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) | 154 | static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) |
155 | { | 155 | { |
156 | /* If there is a hook and it returns non-zero then there | ||
157 | * is an error and the write should be skipped | ||
158 | */ | ||
159 | if (host->pdata->write16_hook && host->pdata->write16_hook(host, addr)) | ||
160 | return; | ||
156 | writew(val, host->ctl + (addr << host->bus_shift)); | 161 | writew(val, host->ctl + (addr << host->bus_shift)); |
157 | } | 162 | } |
158 | 163 | ||
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 5a90266c3a5a..0dc98044d8b7 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h | |||
@@ -68,6 +68,11 @@ | |||
68 | * controller and report the event to the driver. | 68 | * controller and report the event to the driver. |
69 | */ | 69 | */ |
70 | #define TMIO_MMC_HAS_COLD_CD (1 << 3) | 70 | #define TMIO_MMC_HAS_COLD_CD (1 << 3) |
71 | /* | ||
72 | * Some controllers require waiting for the SD bus to become | ||
73 | * idle before writing to some registers. | ||
74 | */ | ||
75 | #define TMIO_MMC_HAS_IDLE_WAIT (1 << 4) | ||
71 | 76 | ||
72 | int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base); | 77 | int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base); |
73 | int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base); | 78 | int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base); |
@@ -80,6 +85,8 @@ struct tmio_mmc_dma { | |||
80 | int alignment_shift; | 85 | int alignment_shift; |
81 | }; | 86 | }; |
82 | 87 | ||
88 | struct tmio_mmc_host; | ||
89 | |||
83 | /* | 90 | /* |
84 | * data for the MMC controller | 91 | * data for the MMC controller |
85 | */ | 92 | */ |
@@ -94,6 +101,7 @@ struct tmio_mmc_data { | |||
94 | void (*set_pwr)(struct platform_device *host, int state); | 101 | void (*set_pwr)(struct platform_device *host, int state); |
95 | void (*set_clk_div)(struct platform_device *host, int state); | 102 | void (*set_clk_div)(struct platform_device *host, int state); |
96 | int (*get_cd)(struct platform_device *host); | 103 | int (*get_cd)(struct platform_device *host); |
104 | int (*write16_hook)(struct tmio_mmc_host *host, int addr); | ||
97 | }; | 105 | }; |
98 | 106 | ||
99 | static inline void tmio_mmc_cd_wakeup(struct tmio_mmc_data *pdata) | 107 | static inline void tmio_mmc_cd_wakeup(struct tmio_mmc_data *pdata) |
diff --git a/include/linux/mmc/tmio.h b/include/linux/mmc/tmio.h index 3ae377623db0..a1c1f321e519 100644 --- a/include/linux/mmc/tmio.h +++ b/include/linux/mmc/tmio.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #define CTL_XFER_BLK_COUNT 0xa | 21 | #define CTL_XFER_BLK_COUNT 0xa |
22 | #define CTL_RESPONSE 0x0c | 22 | #define CTL_RESPONSE 0x0c |
23 | #define CTL_STATUS 0x1c | 23 | #define CTL_STATUS 0x1c |
24 | #define CTL_STATUS2 0x1e | ||
24 | #define CTL_IRQ_MASK 0x20 | 25 | #define CTL_IRQ_MASK 0x20 |
25 | #define CTL_SD_CARD_CLK_CTL 0x24 | 26 | #define CTL_SD_CARD_CLK_CTL 0x24 |
26 | #define CTL_SD_XFER_LEN 0x26 | 27 | #define CTL_SD_XFER_LEN 0x26 |