diff options
Diffstat (limited to 'arch/arm/mach-msm/dma.c')
-rw-r--r-- | arch/arm/mach-msm/dma.c | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c index f5420f9585c5..3d725ae518e4 100644 --- a/arch/arm/mach-msm/dma.c +++ b/arch/arm/mach-msm/dma.c | |||
@@ -13,6 +13,8 @@ | |||
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/err.h> | ||
16 | #include <linux/io.h> | 18 | #include <linux/io.h> |
17 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
18 | #include <mach/dma.h> | 20 | #include <mach/dma.h> |
@@ -26,6 +28,7 @@ enum { | |||
26 | }; | 28 | }; |
27 | 29 | ||
28 | static DEFINE_SPINLOCK(msm_dmov_lock); | 30 | static DEFINE_SPINLOCK(msm_dmov_lock); |
31 | static struct clk *msm_dmov_clk; | ||
29 | static unsigned int channel_active; | 32 | static unsigned int channel_active; |
30 | static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; | 33 | static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; |
31 | static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; | 34 | static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; |
@@ -54,6 +57,9 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) | |||
54 | unsigned int status; | 57 | unsigned int status; |
55 | 58 | ||
56 | spin_lock_irqsave(&msm_dmov_lock, irq_flags); | 59 | spin_lock_irqsave(&msm_dmov_lock, irq_flags); |
60 | if (!channel_active) | ||
61 | clk_enable(msm_dmov_clk); | ||
62 | dsb(); | ||
57 | status = readl(DMOV_STATUS(id)); | 63 | status = readl(DMOV_STATUS(id)); |
58 | if (list_empty(&ready_commands[id]) && | 64 | if (list_empty(&ready_commands[id]) && |
59 | (status & DMOV_STATUS_CMD_PTR_RDY)) { | 65 | (status & DMOV_STATUS_CMD_PTR_RDY)) { |
@@ -70,6 +76,8 @@ void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) | |||
70 | channel_active |= 1U << id; | 76 | channel_active |= 1U << id; |
71 | writel(cmd->cmdptr, DMOV_CMD_PTR(id)); | 77 | writel(cmd->cmdptr, DMOV_CMD_PTR(id)); |
72 | } else { | 78 | } else { |
79 | if (!channel_active) | ||
80 | clk_disable(msm_dmov_clk); | ||
73 | if (list_empty(&active_commands[id])) | 81 | if (list_empty(&active_commands[id])) |
74 | PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status); | 82 | PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status); |
75 | 83 | ||
@@ -165,6 +173,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) | |||
165 | "for %p, result %x\n", id, cmd, ch_result); | 173 | "for %p, result %x\n", id, cmd, ch_result); |
166 | if (cmd) { | 174 | if (cmd) { |
167 | list_del(&cmd->list); | 175 | list_del(&cmd->list); |
176 | dsb(); | ||
168 | cmd->complete_func(cmd, ch_result, NULL); | 177 | cmd->complete_func(cmd, ch_result, NULL); |
169 | } | 178 | } |
170 | } | 179 | } |
@@ -181,6 +190,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) | |||
181 | PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); | 190 | PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); |
182 | if (cmd) { | 191 | if (cmd) { |
183 | list_del(&cmd->list); | 192 | list_del(&cmd->list); |
193 | dsb(); | ||
184 | cmd->complete_func(cmd, ch_result, &errdata); | 194 | cmd->complete_func(cmd, ch_result, &errdata); |
185 | } | 195 | } |
186 | } | 196 | } |
@@ -198,6 +208,7 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) | |||
198 | PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); | 208 | PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, errdata.flush[0]); |
199 | if (cmd) { | 209 | if (cmd) { |
200 | list_del(&cmd->list); | 210 | list_del(&cmd->list); |
211 | dsb(); | ||
201 | cmd->complete_func(cmd, ch_result, &errdata); | 212 | cmd->complete_func(cmd, ch_result, &errdata); |
202 | } | 213 | } |
203 | /* this does not seem to work, once we get an error */ | 214 | /* this does not seem to work, once we get an error */ |
@@ -219,8 +230,10 @@ static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) | |||
219 | PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); | 230 | PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); |
220 | } | 231 | } |
221 | 232 | ||
222 | if (!channel_active) | 233 | if (!channel_active) { |
223 | disable_irq(INT_ADM_AARM); | 234 | disable_irq_nosync(INT_ADM_AARM); |
235 | clk_disable(msm_dmov_clk); | ||
236 | } | ||
224 | 237 | ||
225 | spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); | 238 | spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); |
226 | return IRQ_HANDLED; | 239 | return IRQ_HANDLED; |
@@ -230,11 +243,17 @@ static int __init msm_init_datamover(void) | |||
230 | { | 243 | { |
231 | int i; | 244 | int i; |
232 | int ret; | 245 | int ret; |
246 | struct clk *clk; | ||
247 | |||
233 | for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { | 248 | for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { |
234 | INIT_LIST_HEAD(&ready_commands[i]); | 249 | INIT_LIST_HEAD(&ready_commands[i]); |
235 | INIT_LIST_HEAD(&active_commands[i]); | 250 | INIT_LIST_HEAD(&active_commands[i]); |
236 | writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); | 251 | writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); |
237 | } | 252 | } |
253 | clk = clk_get(NULL, "adm_clk"); | ||
254 | if (IS_ERR(clk)) | ||
255 | return PTR_ERR(clk); | ||
256 | msm_dmov_clk = clk; | ||
238 | ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); | 257 | ret = request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); |
239 | if (ret) | 258 | if (ret) |
240 | return ret; | 259 | return ret; |