aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/mcbsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/mcbsp.c')
-rw-r--r--arch/arm/plat-omap/mcbsp.c401
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}
199EXPORT_SYMBOL(omap_mcbsp_config); 199EXPORT_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 */
207void 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}
224EXPORT_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 */
231void 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}
248EXPORT_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 */
254u16 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}
266EXPORT_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 */
272u16 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}
284EXPORT_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 */
290int 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}
307EXPORT_SYMBOL(omap_mcbsp_get_dma_op_mode);
308
309static 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
336static 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
361static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {}
362static 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)
328EXPORT_SYMBOL(omap_mcbsp_free); 498EXPORT_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 */
335void omap_mcbsp_start(unsigned int id) 505void 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}
371EXPORT_SYMBOL(omap_mcbsp_start); 567EXPORT_SYMBOL(omap_mcbsp_start);
372 568
373void omap_mcbsp_stop(unsigned int id) 569void 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}
399EXPORT_SYMBOL(omap_mcbsp_stop); 613EXPORT_SYMBOL(omap_mcbsp_stop);
400 614
@@ -883,6 +1097,149 @@ void omap_mcbsp_set_spi_mode(unsigned int id,
883} 1097}
884EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); 1098EXPORT_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) \
1104static 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 \
1112static 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 \
1131static DEVICE_ATTR(prop, 0644, prop##_show, prop##_store);
1132
1133THRESHOLD_PROP_BUILDER(max_tx_thres);
1134THRESHOLD_PROP_BUILDER(max_rx_thres);
1135
1136static const char *dma_op_modes[] = {
1137 "element", "threshold", "frame",
1138};
1139
1140static 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
1163static 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
1185unlock:
1186 spin_unlock_irq(&mcbsp->lock);
1187
1188 return size;
1189}
1190
1191static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store);
1192
1193static 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
1200static const struct attribute_group additional_attr_group = {
1201 .attrs = (struct attribute **)additional_attrs,
1202};
1203
1204static inline int __devinit omap_additional_add(struct device *dev)
1205{
1206 return sysfs_create_group(&dev->kobj, &additional_attr_group);
1207}
1208
1209static inline void __devexit omap_additional_remove(struct device *dev)
1210{
1211 sysfs_remove_group(&dev->kobj, &additional_attr_group);
1212}
1213
1214static 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
1233static 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
1239static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {}
1240static 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
958err_fclk: 1319err_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);