diff options
Diffstat (limited to 'arch/arm/plat-omap/mcbsp.c')
-rw-r--r-- | arch/arm/plat-omap/mcbsp.c | 401 |
1 files changed, 382 insertions, 19 deletions
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index efa0e0111f38..8dc7927906f1 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c | |||
@@ -198,6 +198,170 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) | |||
198 | } | 198 | } |
199 | EXPORT_SYMBOL(omap_mcbsp_config); | 199 | EXPORT_SYMBOL(omap_mcbsp_config); |
200 | 200 | ||
201 | #ifdef CONFIG_ARCH_OMAP34XX | ||
202 | /* | ||
203 | * omap_mcbsp_set_tx_threshold configures how to deal | ||
204 | * with transmit threshold. the threshold value and handler can be | ||
205 | * configure in here. | ||
206 | */ | ||
207 | void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) | ||
208 | { | ||
209 | struct omap_mcbsp *mcbsp; | ||
210 | void __iomem *io_base; | ||
211 | |||
212 | if (!cpu_is_omap34xx()) | ||
213 | return; | ||
214 | |||
215 | if (!omap_mcbsp_check_valid_id(id)) { | ||
216 | printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); | ||
217 | return; | ||
218 | } | ||
219 | mcbsp = id_to_mcbsp_ptr(id); | ||
220 | io_base = mcbsp->io_base; | ||
221 | |||
222 | OMAP_MCBSP_WRITE(io_base, THRSH2, threshold); | ||
223 | } | ||
224 | EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold); | ||
225 | |||
226 | /* | ||
227 | * omap_mcbsp_set_rx_threshold configures how to deal | ||
228 | * with receive threshold. the threshold value and handler can be | ||
229 | * configure in here. | ||
230 | */ | ||
231 | void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) | ||
232 | { | ||
233 | struct omap_mcbsp *mcbsp; | ||
234 | void __iomem *io_base; | ||
235 | |||
236 | if (!cpu_is_omap34xx()) | ||
237 | return; | ||
238 | |||
239 | if (!omap_mcbsp_check_valid_id(id)) { | ||
240 | printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); | ||
241 | return; | ||
242 | } | ||
243 | mcbsp = id_to_mcbsp_ptr(id); | ||
244 | io_base = mcbsp->io_base; | ||
245 | |||
246 | OMAP_MCBSP_WRITE(io_base, THRSH1, threshold); | ||
247 | } | ||
248 | EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold); | ||
249 | |||
250 | /* | ||
251 | * omap_mcbsp_get_max_tx_thres just return the current configured | ||
252 | * maximum threshold for transmission | ||
253 | */ | ||
254 | u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) | ||
255 | { | ||
256 | struct omap_mcbsp *mcbsp; | ||
257 | |||
258 | if (!omap_mcbsp_check_valid_id(id)) { | ||
259 | printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); | ||
260 | return -ENODEV; | ||
261 | } | ||
262 | mcbsp = id_to_mcbsp_ptr(id); | ||
263 | |||
264 | return mcbsp->max_tx_thres; | ||
265 | } | ||
266 | EXPORT_SYMBOL(omap_mcbsp_get_max_tx_threshold); | ||
267 | |||
268 | /* | ||
269 | * omap_mcbsp_get_max_rx_thres just return the current configured | ||
270 | * maximum threshold for reception | ||
271 | */ | ||
272 | u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) | ||
273 | { | ||
274 | struct omap_mcbsp *mcbsp; | ||
275 | |||
276 | if (!omap_mcbsp_check_valid_id(id)) { | ||
277 | printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); | ||
278 | return -ENODEV; | ||
279 | } | ||
280 | mcbsp = id_to_mcbsp_ptr(id); | ||
281 | |||
282 | return mcbsp->max_rx_thres; | ||
283 | } | ||
284 | EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold); | ||
285 | |||
286 | /* | ||
287 | * omap_mcbsp_get_dma_op_mode just return the current configured | ||
288 | * operating mode for the mcbsp channel | ||
289 | */ | ||
290 | int omap_mcbsp_get_dma_op_mode(unsigned int id) | ||
291 | { | ||
292 | struct omap_mcbsp *mcbsp; | ||
293 | int dma_op_mode; | ||
294 | |||
295 | if (!omap_mcbsp_check_valid_id(id)) { | ||
296 | printk(KERN_ERR "%s: Invalid id (%u)\n", __func__, id + 1); | ||
297 | return -ENODEV; | ||
298 | } | ||
299 | mcbsp = id_to_mcbsp_ptr(id); | ||
300 | |||
301 | spin_lock_irq(&mcbsp->lock); | ||
302 | dma_op_mode = mcbsp->dma_op_mode; | ||
303 | spin_unlock_irq(&mcbsp->lock); | ||
304 | |||
305 | return dma_op_mode; | ||
306 | } | ||
307 | EXPORT_SYMBOL(omap_mcbsp_get_dma_op_mode); | ||
308 | |||
309 | static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) | ||
310 | { | ||
311 | /* | ||
312 | * Enable wakup behavior, smart idle and all wakeups | ||
313 | * REVISIT: some wakeups may be unnecessary | ||
314 | */ | ||
315 | if (cpu_is_omap34xx()) { | ||
316 | u16 syscon; | ||
317 | |||
318 | syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); | ||
319 | syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); | ||
320 | |||
321 | spin_lock_irq(&mcbsp->lock); | ||
322 | if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { | ||
323 | syscon |= (ENAWAKEUP | SIDLEMODE(0x02) | | ||
324 | CLOCKACTIVITY(0x02)); | ||
325 | OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, | ||
326 | XRDYEN | RRDYEN); | ||
327 | } else { | ||
328 | syscon |= SIDLEMODE(0x01); | ||
329 | } | ||
330 | spin_unlock_irq(&mcbsp->lock); | ||
331 | |||
332 | OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); | ||
333 | } | ||
334 | } | ||
335 | |||
336 | static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) | ||
337 | { | ||
338 | /* | ||
339 | * Disable wakup behavior, smart idle and all wakeups | ||
340 | */ | ||
341 | if (cpu_is_omap34xx()) { | ||
342 | u16 syscon; | ||
343 | |||
344 | syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); | ||
345 | syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); | ||
346 | /* | ||
347 | * HW bug workaround - If no_idle mode is taken, we need to | ||
348 | * go to smart_idle before going to always_idle, or the | ||
349 | * device will not hit retention anymore. | ||
350 | */ | ||
351 | syscon |= SIDLEMODE(0x02); | ||
352 | OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); | ||
353 | |||
354 | syscon &= ~(SIDLEMODE(0x03)); | ||
355 | OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); | ||
356 | |||
357 | OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, 0); | ||
358 | } | ||
359 | } | ||
360 | #else | ||
361 | static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {} | ||
362 | static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) {} | ||
363 | #endif | ||
364 | |||
201 | /* | 365 | /* |
202 | * We can choose between IRQ based or polled IO. | 366 | * We can choose between IRQ based or polled IO. |
203 | * This needs to be called before omap_mcbsp_request(). | 367 | * This needs to be called before omap_mcbsp_request(). |
@@ -257,6 +421,9 @@ int omap_mcbsp_request(unsigned int id) | |||
257 | clk_enable(mcbsp->iclk); | 421 | clk_enable(mcbsp->iclk); |
258 | clk_enable(mcbsp->fclk); | 422 | clk_enable(mcbsp->fclk); |
259 | 423 | ||
424 | /* Do procedure specific to omap34xx arch, if applicable */ | ||
425 | omap34xx_mcbsp_request(mcbsp); | ||
426 | |||
260 | /* | 427 | /* |
261 | * Make sure that transmitter, receiver and sample-rate generator are | 428 | * Make sure that transmitter, receiver and sample-rate generator are |
262 | * not running before activating IRQs. | 429 | * not running before activating IRQs. |
@@ -305,6 +472,9 @@ void omap_mcbsp_free(unsigned int id) | |||
305 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) | 472 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) |
306 | mcbsp->pdata->ops->free(id); | 473 | mcbsp->pdata->ops->free(id); |
307 | 474 | ||
475 | /* Do procedure specific to omap34xx arch, if applicable */ | ||
476 | omap34xx_mcbsp_free(mcbsp); | ||
477 | |||
308 | clk_disable(mcbsp->fclk); | 478 | clk_disable(mcbsp->fclk); |
309 | clk_disable(mcbsp->iclk); | 479 | clk_disable(mcbsp->iclk); |
310 | 480 | ||
@@ -328,14 +498,15 @@ void omap_mcbsp_free(unsigned int id) | |||
328 | EXPORT_SYMBOL(omap_mcbsp_free); | 498 | EXPORT_SYMBOL(omap_mcbsp_free); |
329 | 499 | ||
330 | /* | 500 | /* |
331 | * Here we start the McBSP, by enabling the sample | 501 | * Here we start the McBSP, by enabling transmitter, receiver or both. |
332 | * generator, both transmitter and receivers, | 502 | * If no transmitter or receiver is active prior calling, then sample-rate |
333 | * and the frame sync. | 503 | * generator and frame sync are started. |
334 | */ | 504 | */ |
335 | void omap_mcbsp_start(unsigned int id) | 505 | void omap_mcbsp_start(unsigned int id, int tx, int rx) |
336 | { | 506 | { |
337 | struct omap_mcbsp *mcbsp; | 507 | struct omap_mcbsp *mcbsp; |
338 | void __iomem *io_base; | 508 | void __iomem *io_base; |
509 | int idle; | ||
339 | u16 w; | 510 | u16 w; |
340 | 511 | ||
341 | if (!omap_mcbsp_check_valid_id(id)) { | 512 | if (!omap_mcbsp_check_valid_id(id)) { |
@@ -348,32 +519,58 @@ void omap_mcbsp_start(unsigned int id) | |||
348 | mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7; | 519 | mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7; |
349 | mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7; | 520 | mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7; |
350 | 521 | ||
351 | /* Start the sample generator */ | 522 | idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | |
352 | w = OMAP_MCBSP_READ(io_base, SPCR2); | 523 | OMAP_MCBSP_READ(io_base, SPCR1)) & 1); |
353 | OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); | 524 | |
525 | if (idle) { | ||
526 | /* Start the sample generator */ | ||
527 | w = OMAP_MCBSP_READ(io_base, SPCR2); | ||
528 | OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); | ||
529 | } | ||
354 | 530 | ||
355 | /* Enable transmitter and receiver */ | 531 | /* Enable transmitter and receiver */ |
532 | tx &= 1; | ||
356 | w = OMAP_MCBSP_READ(io_base, SPCR2); | 533 | w = OMAP_MCBSP_READ(io_base, SPCR2); |
357 | OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1); | 534 | OMAP_MCBSP_WRITE(io_base, SPCR2, w | tx); |
358 | 535 | ||
536 | rx &= 1; | ||
359 | w = OMAP_MCBSP_READ(io_base, SPCR1); | 537 | w = OMAP_MCBSP_READ(io_base, SPCR1); |
360 | OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1); | 538 | OMAP_MCBSP_WRITE(io_base, SPCR1, w | rx); |
361 | 539 | ||
362 | udelay(100); | 540 | /* |
541 | * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec | ||
542 | * REVISIT: 100us may give enough time for two CLKSRG, however | ||
543 | * due to some unknown PM related, clock gating etc. reason it | ||
544 | * is now at 500us. | ||
545 | */ | ||
546 | udelay(500); | ||
363 | 547 | ||
364 | /* Start frame sync */ | 548 | if (idle) { |
365 | w = OMAP_MCBSP_READ(io_base, SPCR2); | 549 | /* Start frame sync */ |
366 | OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); | 550 | w = OMAP_MCBSP_READ(io_base, SPCR2); |
551 | OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); | ||
552 | } | ||
553 | |||
554 | if (cpu_is_omap2430() || cpu_is_omap34xx()) { | ||
555 | /* Release the transmitter and receiver */ | ||
556 | w = OMAP_MCBSP_READ(io_base, XCCR); | ||
557 | w &= ~(tx ? XDISABLE : 0); | ||
558 | OMAP_MCBSP_WRITE(io_base, XCCR, w); | ||
559 | w = OMAP_MCBSP_READ(io_base, RCCR); | ||
560 | w &= ~(rx ? RDISABLE : 0); | ||
561 | OMAP_MCBSP_WRITE(io_base, RCCR, w); | ||
562 | } | ||
367 | 563 | ||
368 | /* Dump McBSP Regs */ | 564 | /* Dump McBSP Regs */ |
369 | omap_mcbsp_dump_reg(id); | 565 | omap_mcbsp_dump_reg(id); |
370 | } | 566 | } |
371 | EXPORT_SYMBOL(omap_mcbsp_start); | 567 | EXPORT_SYMBOL(omap_mcbsp_start); |
372 | 568 | ||
373 | void omap_mcbsp_stop(unsigned int id) | 569 | void omap_mcbsp_stop(unsigned int id, int tx, int rx) |
374 | { | 570 | { |
375 | struct omap_mcbsp *mcbsp; | 571 | struct omap_mcbsp *mcbsp; |
376 | void __iomem *io_base; | 572 | void __iomem *io_base; |
573 | int idle; | ||
377 | u16 w; | 574 | u16 w; |
378 | 575 | ||
379 | if (!omap_mcbsp_check_valid_id(id)) { | 576 | if (!omap_mcbsp_check_valid_id(id)) { |
@@ -385,16 +582,33 @@ void omap_mcbsp_stop(unsigned int id) | |||
385 | io_base = mcbsp->io_base; | 582 | io_base = mcbsp->io_base; |
386 | 583 | ||
387 | /* Reset transmitter */ | 584 | /* Reset transmitter */ |
585 | tx &= 1; | ||
586 | if (cpu_is_omap2430() || cpu_is_omap34xx()) { | ||
587 | w = OMAP_MCBSP_READ(io_base, XCCR); | ||
588 | w |= (tx ? XDISABLE : 0); | ||
589 | OMAP_MCBSP_WRITE(io_base, XCCR, w); | ||
590 | } | ||
388 | w = OMAP_MCBSP_READ(io_base, SPCR2); | 591 | w = OMAP_MCBSP_READ(io_base, SPCR2); |
389 | OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1)); | 592 | OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~tx); |
390 | 593 | ||
391 | /* Reset receiver */ | 594 | /* Reset receiver */ |
595 | rx &= 1; | ||
596 | if (cpu_is_omap2430() || cpu_is_omap34xx()) { | ||
597 | w = OMAP_MCBSP_READ(io_base, RCCR); | ||
598 | w |= (tx ? RDISABLE : 0); | ||
599 | OMAP_MCBSP_WRITE(io_base, RCCR, w); | ||
600 | } | ||
392 | w = OMAP_MCBSP_READ(io_base, SPCR1); | 601 | w = OMAP_MCBSP_READ(io_base, SPCR1); |
393 | OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1)); | 602 | OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~rx); |
394 | 603 | ||
395 | /* Reset the sample rate generator */ | 604 | idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | |
396 | w = OMAP_MCBSP_READ(io_base, SPCR2); | 605 | OMAP_MCBSP_READ(io_base, SPCR1)) & 1); |
397 | OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); | 606 | |
607 | if (idle) { | ||
608 | /* Reset the sample rate generator */ | ||
609 | w = OMAP_MCBSP_READ(io_base, SPCR2); | ||
610 | OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); | ||
611 | } | ||
398 | } | 612 | } |
399 | EXPORT_SYMBOL(omap_mcbsp_stop); | 613 | EXPORT_SYMBOL(omap_mcbsp_stop); |
400 | 614 | ||
@@ -883,6 +1097,149 @@ void omap_mcbsp_set_spi_mode(unsigned int id, | |||
883 | } | 1097 | } |
884 | EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); | 1098 | EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); |
885 | 1099 | ||
1100 | #ifdef CONFIG_ARCH_OMAP34XX | ||
1101 | #define max_thres(m) (mcbsp->pdata->buffer_size) | ||
1102 | #define valid_threshold(m, val) ((val) <= max_thres(m)) | ||
1103 | #define THRESHOLD_PROP_BUILDER(prop) \ | ||
1104 | static ssize_t prop##_show(struct device *dev, \ | ||
1105 | struct device_attribute *attr, char *buf) \ | ||
1106 | { \ | ||
1107 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ | ||
1108 | \ | ||
1109 | return sprintf(buf, "%u\n", mcbsp->prop); \ | ||
1110 | } \ | ||
1111 | \ | ||
1112 | static ssize_t prop##_store(struct device *dev, \ | ||
1113 | struct device_attribute *attr, \ | ||
1114 | const char *buf, size_t size) \ | ||
1115 | { \ | ||
1116 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ | ||
1117 | unsigned long val; \ | ||
1118 | int status; \ | ||
1119 | \ | ||
1120 | status = strict_strtoul(buf, 0, &val); \ | ||
1121 | if (status) \ | ||
1122 | return status; \ | ||
1123 | \ | ||
1124 | if (!valid_threshold(mcbsp, val)) \ | ||
1125 | return -EDOM; \ | ||
1126 | \ | ||
1127 | mcbsp->prop = val; \ | ||
1128 | return size; \ | ||
1129 | } \ | ||
1130 | \ | ||
1131 | static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store); | ||
1132 | |||
1133 | THRESHOLD_PROP_BUILDER(max_tx_thres); | ||
1134 | THRESHOLD_PROP_BUILDER(max_rx_thres); | ||
1135 | |||
1136 | static const char *dma_op_modes[] = { | ||
1137 | "element", "threshold", "frame", | ||
1138 | }; | ||
1139 | |||
1140 | static ssize_t dma_op_mode_show(struct device *dev, | ||
1141 | struct device_attribute *attr, char *buf) | ||
1142 | { | ||
1143 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
1144 | int dma_op_mode, i = 0; | ||
1145 | ssize_t len = 0; | ||
1146 | const char * const *s; | ||
1147 | |||
1148 | spin_lock_irq(&mcbsp->lock); | ||
1149 | dma_op_mode = mcbsp->dma_op_mode; | ||
1150 | spin_unlock_irq(&mcbsp->lock); | ||
1151 | |||
1152 | for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) { | ||
1153 | if (dma_op_mode == i) | ||
1154 | len += sprintf(buf + len, "[%s] ", *s); | ||
1155 | else | ||
1156 | len += sprintf(buf + len, "%s ", *s); | ||
1157 | } | ||
1158 | len += sprintf(buf + len, "\n"); | ||
1159 | |||
1160 | return len; | ||
1161 | } | ||
1162 | |||
1163 | static ssize_t dma_op_mode_store(struct device *dev, | ||
1164 | struct device_attribute *attr, | ||
1165 | const char *buf, size_t size) | ||
1166 | { | ||
1167 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); | ||
1168 | const char * const *s; | ||
1169 | int i = 0; | ||
1170 | |||
1171 | for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) | ||
1172 | if (sysfs_streq(buf, *s)) | ||
1173 | break; | ||
1174 | |||
1175 | if (i == ARRAY_SIZE(dma_op_modes)) | ||
1176 | return -EINVAL; | ||
1177 | |||
1178 | spin_lock_irq(&mcbsp->lock); | ||
1179 | if (!mcbsp->free) { | ||
1180 | size = -EBUSY; | ||
1181 | goto unlock; | ||
1182 | } | ||
1183 | mcbsp->dma_op_mode = i; | ||
1184 | |||
1185 | unlock: | ||
1186 | spin_unlock_irq(&mcbsp->lock); | ||
1187 | |||
1188 | return size; | ||
1189 | } | ||
1190 | |||
1191 | static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store); | ||
1192 | |||
1193 | static const struct attribute *additional_attrs[] = { | ||
1194 | &dev_attr_max_tx_thres.attr, | ||
1195 | &dev_attr_max_rx_thres.attr, | ||
1196 | &dev_attr_dma_op_mode.attr, | ||
1197 | NULL, | ||
1198 | }; | ||
1199 | |||
1200 | static const struct attribute_group additional_attr_group = { | ||
1201 | .attrs = (struct attribute **)additional_attrs, | ||
1202 | }; | ||
1203 | |||
1204 | static inline int __devinit omap_additional_add(struct device *dev) | ||
1205 | { | ||
1206 | return sysfs_create_group(&dev->kobj, &additional_attr_group); | ||
1207 | } | ||
1208 | |||
1209 | static inline void __devexit omap_additional_remove(struct device *dev) | ||
1210 | { | ||
1211 | sysfs_remove_group(&dev->kobj, &additional_attr_group); | ||
1212 | } | ||
1213 | |||
1214 | static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) | ||
1215 | { | ||
1216 | mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; | ||
1217 | if (cpu_is_omap34xx()) { | ||
1218 | mcbsp->max_tx_thres = max_thres(mcbsp); | ||
1219 | mcbsp->max_rx_thres = max_thres(mcbsp); | ||
1220 | /* | ||
1221 | * REVISIT: Set dmap_op_mode to THRESHOLD as default | ||
1222 | * for mcbsp2 instances. | ||
1223 | */ | ||
1224 | if (omap_additional_add(mcbsp->dev)) | ||
1225 | dev_warn(mcbsp->dev, | ||
1226 | "Unable to create additional controls\n"); | ||
1227 | } else { | ||
1228 | mcbsp->max_tx_thres = -EINVAL; | ||
1229 | mcbsp->max_rx_thres = -EINVAL; | ||
1230 | } | ||
1231 | } | ||
1232 | |||
1233 | static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) | ||
1234 | { | ||
1235 | if (cpu_is_omap34xx()) | ||
1236 | omap_additional_remove(mcbsp->dev); | ||
1237 | } | ||
1238 | #else | ||
1239 | static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {} | ||
1240 | static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) {} | ||
1241 | #endif /* CONFIG_ARCH_OMAP34XX */ | ||
1242 | |||
886 | /* | 1243 | /* |
887 | * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. | 1244 | * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. |
888 | * 730 has only 2 McBSP, and both of them are MPU peripherals. | 1245 | * 730 has only 2 McBSP, and both of them are MPU peripherals. |
@@ -953,6 +1310,10 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev) | |||
953 | mcbsp->dev = &pdev->dev; | 1310 | mcbsp->dev = &pdev->dev; |
954 | mcbsp_ptr[id] = mcbsp; | 1311 | mcbsp_ptr[id] = mcbsp; |
955 | platform_set_drvdata(pdev, mcbsp); | 1312 | platform_set_drvdata(pdev, mcbsp); |
1313 | |||
1314 | /* Initialize mcbsp properties for OMAP34XX if needed / applicable */ | ||
1315 | omap34xx_device_init(mcbsp); | ||
1316 | |||
956 | return 0; | 1317 | return 0; |
957 | 1318 | ||
958 | err_fclk: | 1319 | err_fclk: |
@@ -976,6 +1337,8 @@ static int __devexit omap_mcbsp_remove(struct platform_device *pdev) | |||
976 | mcbsp->pdata->ops->free) | 1337 | mcbsp->pdata->ops->free) |
977 | mcbsp->pdata->ops->free(mcbsp->id); | 1338 | mcbsp->pdata->ops->free(mcbsp->id); |
978 | 1339 | ||
1340 | omap34xx_device_exit(mcbsp); | ||
1341 | |||
979 | clk_disable(mcbsp->fclk); | 1342 | clk_disable(mcbsp->fclk); |
980 | clk_disable(mcbsp->iclk); | 1343 | clk_disable(mcbsp->iclk); |
981 | clk_put(mcbsp->fclk); | 1344 | clk_put(mcbsp->fclk); |