diff options
author | Balaji T K <balajitk@ti.com> | 2014-01-21 09:24:42 -0500 |
---|---|---|
committer | Chris Ball <chris@printf.net> | 2014-03-04 11:46:49 -0500 |
commit | a2e771522c2a60459a79844004722f109cb4e13d (patch) | |
tree | 1c51cac9288636b69191adf8dbaf7afd130784b2 /drivers/mmc/host/omap_hsmmc.c | |
parent | bf129e1ca19f973731d56478297be3de3181efcb (diff) |
mmc: omap_hsmmc: add autocmd23 support
Add support for autocmd23 support
Signed-off-by: Balaji T K <balajitk@ti.com>
Signed-off-by: Chris Ball <chris@printf.net>
Diffstat (limited to 'drivers/mmc/host/omap_hsmmc.c')
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 476c6a632bfc..e91ee21549d0 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -45,6 +45,7 @@ | |||
45 | /* OMAP HSMMC Host Controller Registers */ | 45 | /* OMAP HSMMC Host Controller Registers */ |
46 | #define OMAP_HSMMC_SYSSTATUS 0x0014 | 46 | #define OMAP_HSMMC_SYSSTATUS 0x0014 |
47 | #define OMAP_HSMMC_CON 0x002C | 47 | #define OMAP_HSMMC_CON 0x002C |
48 | #define OMAP_HSMMC_SDMASA 0x0100 | ||
48 | #define OMAP_HSMMC_BLK 0x0104 | 49 | #define OMAP_HSMMC_BLK 0x0104 |
49 | #define OMAP_HSMMC_ARG 0x0108 | 50 | #define OMAP_HSMMC_ARG 0x0108 |
50 | #define OMAP_HSMMC_CMD 0x010C | 51 | #define OMAP_HSMMC_CMD 0x010C |
@@ -58,6 +59,7 @@ | |||
58 | #define OMAP_HSMMC_STAT 0x0130 | 59 | #define OMAP_HSMMC_STAT 0x0130 |
59 | #define OMAP_HSMMC_IE 0x0134 | 60 | #define OMAP_HSMMC_IE 0x0134 |
60 | #define OMAP_HSMMC_ISE 0x0138 | 61 | #define OMAP_HSMMC_ISE 0x0138 |
62 | #define OMAP_HSMMC_AC12 0x013C | ||
61 | #define OMAP_HSMMC_CAPA 0x0140 | 63 | #define OMAP_HSMMC_CAPA 0x0140 |
62 | 64 | ||
63 | #define VS18 (1 << 26) | 65 | #define VS18 (1 << 26) |
@@ -81,6 +83,7 @@ | |||
81 | #define DTO_MASK 0x000F0000 | 83 | #define DTO_MASK 0x000F0000 |
82 | #define DTO_SHIFT 16 | 84 | #define DTO_SHIFT 16 |
83 | #define INIT_STREAM (1 << 1) | 85 | #define INIT_STREAM (1 << 1) |
86 | #define ACEN_ACMD23 (2 << 2) | ||
84 | #define DP_SELECT (1 << 21) | 87 | #define DP_SELECT (1 << 21) |
85 | #define DDIR (1 << 4) | 88 | #define DDIR (1 << 4) |
86 | #define DMAE 0x1 | 89 | #define DMAE 0x1 |
@@ -111,13 +114,21 @@ | |||
111 | #define DTO_EN (1 << 20) | 114 | #define DTO_EN (1 << 20) |
112 | #define DCRC_EN (1 << 21) | 115 | #define DCRC_EN (1 << 21) |
113 | #define DEB_EN (1 << 22) | 116 | #define DEB_EN (1 << 22) |
117 | #define ACE_EN (1 << 24) | ||
114 | #define CERR_EN (1 << 28) | 118 | #define CERR_EN (1 << 28) |
115 | #define BADA_EN (1 << 29) | 119 | #define BADA_EN (1 << 29) |
116 | 120 | ||
117 | #define INT_EN_MASK (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\ | 121 | #define INT_EN_MASK (BADA_EN | CERR_EN | ACE_EN | DEB_EN | DCRC_EN |\ |
118 | DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \ | 122 | DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \ |
119 | BRR_EN | BWR_EN | TC_EN | CC_EN) | 123 | BRR_EN | BWR_EN | TC_EN | CC_EN) |
120 | 124 | ||
125 | #define CNI (1 << 7) | ||
126 | #define ACIE (1 << 4) | ||
127 | #define ACEB (1 << 3) | ||
128 | #define ACCE (1 << 2) | ||
129 | #define ACTO (1 << 1) | ||
130 | #define ACNE (1 << 0) | ||
131 | |||
121 | #define MMC_AUTOSUSPEND_DELAY 100 | 132 | #define MMC_AUTOSUSPEND_DELAY 100 |
122 | #define MMC_TIMEOUT_MS 20 /* 20 mSec */ | 133 | #define MMC_TIMEOUT_MS 20 /* 20 mSec */ |
123 | #define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */ | 134 | #define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */ |
@@ -129,6 +140,7 @@ | |||
129 | #define VDD_3V0 3000000 /* 300000 uV */ | 140 | #define VDD_3V0 3000000 /* 300000 uV */ |
130 | #define VDD_165_195 (ffs(MMC_VDD_165_195) - 1) | 141 | #define VDD_165_195 (ffs(MMC_VDD_165_195) - 1) |
131 | 142 | ||
143 | #define AUTO_CMD23 (1 << 1) /* Auto CMD23 support */ | ||
132 | /* | 144 | /* |
133 | * One controller can have multiple slots, like on some omap boards using | 145 | * One controller can have multiple slots, like on some omap boards using |
134 | * omap.c controller driver. Luckily this is not currently done on any known | 146 | * omap.c controller driver. Luckily this is not currently done on any known |
@@ -193,6 +205,7 @@ struct omap_hsmmc_host { | |||
193 | int use_reg; | 205 | int use_reg; |
194 | int req_in_progress; | 206 | int req_in_progress; |
195 | unsigned long clk_rate; | 207 | unsigned long clk_rate; |
208 | unsigned int flags; | ||
196 | struct omap_hsmmc_next next_data; | 209 | struct omap_hsmmc_next next_data; |
197 | struct omap_mmc_platform_data *pdata; | 210 | struct omap_mmc_platform_data *pdata; |
198 | }; | 211 | }; |
@@ -813,6 +826,11 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, | |||
813 | 826 | ||
814 | cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22); | 827 | cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22); |
815 | 828 | ||
829 | if ((host->flags & AUTO_CMD23) && mmc_op_multi(cmd->opcode) && | ||
830 | host->mrq->sbc) { | ||
831 | cmdreg |= ACEN_ACMD23; | ||
832 | OMAP_HSMMC_WRITE(host->base, SDMASA, host->mrq->sbc->arg); | ||
833 | } | ||
816 | if (data) { | 834 | if (data) { |
817 | cmdreg |= DP_SELECT | MSBS | BCE; | 835 | cmdreg |= DP_SELECT | MSBS | BCE; |
818 | if (data->flags & MMC_DATA_READ) | 836 | if (data->flags & MMC_DATA_READ) |
@@ -905,7 +923,7 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) | |||
905 | host->cmd = NULL; | 923 | host->cmd = NULL; |
906 | 924 | ||
907 | if (host->mrq->sbc && (host->cmd == host->mrq->sbc) && | 925 | if (host->mrq->sbc && (host->cmd == host->mrq->sbc) && |
908 | !host->mrq->sbc->error) { | 926 | !host->mrq->sbc->error && !(host->flags & AUTO_CMD23)) { |
909 | omap_hsmmc_start_dma_transfer(host); | 927 | omap_hsmmc_start_dma_transfer(host); |
910 | omap_hsmmc_start_command(host, host->mrq->cmd, | 928 | omap_hsmmc_start_command(host, host->mrq->cmd, |
911 | host->mrq->data); | 929 | host->mrq->data); |
@@ -1048,6 +1066,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) | |||
1048 | { | 1066 | { |
1049 | struct mmc_data *data; | 1067 | struct mmc_data *data; |
1050 | int end_cmd = 0, end_trans = 0; | 1068 | int end_cmd = 0, end_trans = 0; |
1069 | int error = 0; | ||
1051 | 1070 | ||
1052 | data = host->data; | 1071 | data = host->data; |
1053 | dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status); | 1072 | dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status); |
@@ -1062,6 +1081,20 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) | |||
1062 | else if (status & (CCRC_EN | DCRC_EN)) | 1081 | else if (status & (CCRC_EN | DCRC_EN)) |
1063 | hsmmc_command_incomplete(host, -EILSEQ, end_cmd); | 1082 | hsmmc_command_incomplete(host, -EILSEQ, end_cmd); |
1064 | 1083 | ||
1084 | if (status & ACE_EN) { | ||
1085 | u32 ac12; | ||
1086 | ac12 = OMAP_HSMMC_READ(host->base, AC12); | ||
1087 | if (!(ac12 & ACNE) && host->mrq->sbc) { | ||
1088 | end_cmd = 1; | ||
1089 | if (ac12 & ACTO) | ||
1090 | error = -ETIMEDOUT; | ||
1091 | else if (ac12 & (ACCE | ACEB | ACIE)) | ||
1092 | error = -EILSEQ; | ||
1093 | host->mrq->sbc->error = error; | ||
1094 | hsmmc_command_incomplete(host, error, end_cmd); | ||
1095 | } | ||
1096 | dev_dbg(mmc_dev(host->mmc), "AC12 err: 0x%x\n", ac12); | ||
1097 | } | ||
1065 | if (host->data || host->response_busy) { | 1098 | if (host->data || host->response_busy) { |
1066 | end_trans = !end_cmd; | 1099 | end_trans = !end_cmd; |
1067 | host->response_busy = 0; | 1100 | host->response_busy = 0; |
@@ -1513,7 +1546,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) | |||
1513 | mmc_request_done(mmc, req); | 1546 | mmc_request_done(mmc, req); |
1514 | return; | 1547 | return; |
1515 | } | 1548 | } |
1516 | if (req->sbc) { | 1549 | if (req->sbc && !(host->flags & AUTO_CMD23)) { |
1517 | omap_hsmmc_start_command(host, req->sbc, NULL); | 1550 | omap_hsmmc_start_command(host, req->sbc, NULL); |
1518 | return; | 1551 | return; |
1519 | } | 1552 | } |