邹卫军 wrote: > Hello! > I am doing a project which involes in the use of Davinci DM6446. I > need the SPI device of DM6446 > to finish the communication with other devices. But I have poor > knowledge about the SPI driver under > the DM6446. How can I get any help from the community?
I haven't tested this on anything later than 2.6.28, and it is missing a few different read/write widths. Supposedly TI was going to be releasing a SPI driver for DM6446, DM355 and DM6467 back in March, so I stopped adding support which I did not require.
/* * drivers/spi/spi_davinci.c * * Copyright (C) Advanced Communication Design * * Based on code from spi_bfin5xx.c and atmel_spi.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ //#define DEBUG #include <linux/kernel.h> #include <linux/init.h> #include <linux/clk.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/spi/spi.h> #include <linux/sched.h> #include <linux/workqueue.h> #include <linux/device.h> #include <linux/completion.h> #include <asm/arch/clock.h> #include <asm/arch/gpio.h> #include <asm/arch/hardware.h> #include <asm/arch/io.h> #include <asm/arch/mux.h> #define START_STATE ((void *)0) #define RUNNING_STATE ((void *)1) #define DONE_STATE ((void *)2) #define ERROR_STATE ((void *)-1) #define QUEUE_RUNNING 0 #define QUEUE_STOPPED 1 struct davinci_spi { struct platform_device *pdev; struct spi_master *master; void __iomem *regs_base; int irq; u16 *pin_req; struct clk *clk; struct workqueue_struct *workqueue; struct work_struct pump_messages; spinlock_t lock; struct list_head queue; int busy; int run; struct tasklet_struct pump_transfers; struct completion rx_done; struct spi_message *cur_msg; struct spi_transfer *cur_transfer; size_t len_in_bytes; size_t len; void *tx; void *tx_end; void *rx; void *rx_end; void (*wr) (struct davinci_spi *); void (*rd) (struct davinci_spi *); void (*duplex) (struct davinci_spi *); }; /* SPI Register Addresses */ #define SPIGCR0 (0x00) /** SPI General Control Register 0 */ #define SPIGCR1 (0x04) /** SPI General Control Register 1 */ #define SPIINT (0x08) /** SPI Interrupt Register */ #define SPILVL (0x0c) /** SPI Pin Level Register */ #define SPIFLG (0x10) /** SPI Flag Status Register */ #define SPIPC0 (0x14) /** SPI Pin Control Register 0 */ #define SPIPC2 (0x1c) /** SPI Pin Control Register 2 */ #define SPIDAT1 (0x3c) /** SPI Shift Register 1 */ #define SPIBUF (0x40) /** SPI Buffer Register */ #define SPIEMU (0x44) /** SPI Emulation Register */ #define SPIDELAY (0x48) /** SPI Delay Register */ #define SPIDEF (0x4c) /** SPI Default Chip Select Register */ #define SPIFMT0 (0x50) /** SPI Data Format Register 0 */ #define SPIFMT1 (0x54) /** SPI Data Format Register 1 */ #define SPIFMT2 (0x58) /** SPI Data Format Register 2 */ #define SPIFMT3 (0x5c) /** SPI Data Format Register 3 */ #define INTVEC0 (0x60) /** SPI Interrupt Vector Register 0 */ #define INTVEC1 (0x64) /** SPI Interrupt Vector Register 1 */ /* SPI Register bit definitions */ #define SPIGCR0_RESET (1 << 0) #define SPIGCR1_SPIEN (1 << 24) #define SPIGCR1_CLKMOD (1 << 1) #define SPIGCR1_MASTER (1 << 0) #define SPIINT_DMAREQEN (1 << 16) #define SPIINT_RXINTEN (1 << 8) #define SPIINT_OVRNINTEN (1 << 6) #define SPIINT_BITERRENA (1 << 4) #define SPIFMTX_POLARITY (1 << 17) #define SPIFMTX_PHASE (1 << 16) #define SPIFMTX_PRESCALE_VAL (7 << 8) #define SPIFLG_RXINTFLG (1 << 8) #define SPIFLG_OVRNINTFLG (1 << 6) #define SPIFLG_BITERRFLG (1 << 4) #define SPIPC0_DIFUN (1 << 11) #define SPIPC0_DOFUN (1 << 10) #define SPIPC0_CLKFUN (1 << 9) #define SPIPC0_EN1FUN (1 << 1) #define SPIPC0_EN0FUN (1 << 0) #define SPIDAT1_CSHOLD (1 << 28) #define SPIDAT1_CSNR1 (1 << 16) #define SPIDAT1_CSNR0 (2 << 16) #define SPIDELAY_C2TDELAY_VAL (6 << 24) #define SPIDELAY_T2CDELAY_VAL (3 << 16) #define SPIDEF_EN1DEF (1 << 1) #define SPIDEF_EN0DEF (1 << 0) #define MODEBITS (SPI_CPOL | SPI_CPHA) static void u16_duplex(struct davinci_spi *dvspi) { while (dvspi->tx < dvspi->tx_end) { iowrite32(SPIDAT1_CSHOLD | SPIDAT1_CSNR0 | (*(u16 *) (dvspi->tx)), dvspi->regs_base+SPIDAT1); dev_dbg(&dvspi->pdev->dev, "u16_duplex: wr=%x\n", *(u16 *) (dvspi->tx)); if (wait_for_completion_timeout(&dvspi->rx_done, 1 * HZ) == 0) { dev_err(&dvspi->pdev->dev, "rx timeout\n"); } *(u16 *) (dvspi->rx) = ioread16(dvspi->regs_base+SPIBUF); dev_dbg(&dvspi->pdev->dev, "u16_duplex: rd=%x\n", *(u16 *) (dvspi->rx)); dvspi->rx += 2; dvspi->tx += 2; } } static void u16_write(struct davinci_spi *dvspi) { while (dvspi->tx < dvspi->tx_end) { iowrite32(SPIDAT1_CSHOLD | SPIDAT1_CSNR0 | (*(u16 *) (dvspi->tx)), dvspi->regs_base+SPIDAT1); dev_dbg(&dvspi->pdev->dev, "u16_write: wr=%x\n", *(u16 *) (dvspi->tx)); dvspi->tx += 2; } } static void u16_read(struct davinci_spi *dvspi) { while (dvspi->rx < dvspi->rx_end) { if (wait_for_completion_timeout(&dvspi->rx_done, 1 * HZ) == 0) { dev_err(&dvspi->pdev->dev, "rx timeout\n"); } *(u16 *) (dvspi->rx) = ioread16(dvspi->regs_base+SPIBUF); dev_dbg(&dvspi->pdev->dev, "u16_read: rd=%x\n", *(u16 *) (dvspi->rx)); dvspi->rx += 2; } } /*************************************************** * spi_davinci_giveback * *-------------------------------------------------* * Message transfer completed. Queue next message * and run message's complete function if set. ***************************************************/ static void spi_davinci_giveback(struct davinci_spi *dvspi) { struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *message; dev_dbg(&dvspi->pdev->dev, "spi_davinci_giveback: m=%p, t=%p\n", dvspi->cur_msg, dvspi->cur_transfer); spin_lock_irqsave(&dvspi->lock, flags); message = dvspi->cur_msg; dvspi->cur_msg = NULL; dvspi->cur_transfer = NULL; queue_work(dvspi->workqueue, &dvspi->pump_messages); spin_unlock_irqrestore(&dvspi->lock, flags); last_transfer = list_entry(message->transfers.prev, struct spi_transfer, transfer_list); message->state = NULL; if (message->complete) { dev_dbg(&dvspi->pdev->dev, "spi_davinci_giveback: message complete\n"); message->complete(message->context); } } /*************************************************** * spi_davinci_next_transfer * *-------------------------------------------------* * Update current transfer in message transfer * list. ***************************************************/ static void *spi_davinci_next_transfer(struct davinci_spi *dvspi) { struct spi_message *message; struct spi_transfer *transfer; dev_dbg(&dvspi->pdev->dev, "spi_davinci_next_transfer: m=%p, t=%p\n", dvspi->cur_msg, dvspi->cur_transfer); message = dvspi->cur_msg; transfer = dvspi->cur_transfer; dev_dbg(&dvspi->pdev->dev, "spi_davinci_next_transfer: list.next=%p, message->transfers=%p\n", transfer->transfer_list.next, &message->transfers); if (transfer->transfer_list.next != &message->transfers) { dvspi->cur_transfer = list_entry(transfer->transfer_list.next, struct spi_transfer, transfer_list); return RUNNING_STATE; } return DONE_STATE; } /*************************************************** * spi_davinci_pump_transfers * *-------------------------------------------------* * Send data over SPI bus for a single message * transfer. ***************************************************/ static void spi_davinci_pump_transfers(unsigned long data) { struct davinci_spi *dvspi = (struct davinci_spi *) data; struct spi_message *message = NULL; struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; int transfer_success = 1; unsigned long flags; dev_dbg(&dvspi->pdev->dev, "spi_davinci_pump_transfers, m=%p, t=%p\n", dvspi->cur_msg, dvspi->cur_transfer); spin_lock_irqsave(&dvspi->lock, flags); message = dvspi->cur_msg; transfer = dvspi->cur_transfer; spin_unlock_irqrestore(&dvspi->lock, flags); /* handle abort */ if (message->state == ERROR_STATE) { dev_dbg(&dvspi->pdev->dev, "spi_davinci_pump_transfers: ERROR STATE\n"); message->status = -EIO; spi_davinci_giveback(dvspi); return; } /* handle end of message */ if (message->state == DONE_STATE) { dev_dbg(&dvspi->pdev->dev, "spi_davinci_pump_transfers: DONE STATE\n"); message->status = 0; spi_davinci_giveback(dvspi); return; } if (message->state == RUNNING_STATE) { previous = list_entry(transfer->transfer_list.prev, struct spi_transfer, transfer_list); if (previous->delay_usecs) { udelay(previous->delay_usecs); } } spin_lock_irqsave(&dvspi->lock, flags); if (transfer->tx_buf != NULL) { dvspi->tx = (void *) transfer->tx_buf; dvspi->tx_end = dvspi->tx + transfer->len; } else { dvspi->tx = NULL; } if (transfer->tx_buf != NULL) { dvspi->rx = transfer->rx_buf; dvspi->rx_end = dvspi->rx + transfer->len; } else { dvspi->rx = NULL; } // configure for 16byte messages dvspi->len = transfer->len >> 1; dvspi->len_in_bytes = transfer->len; message->state = RUNNING_STATE; /* Write - then - Read */ if (dvspi->tx != NULL && dvspi->rx != NULL) { if (dvspi->duplex) { dvspi->duplex(dvspi); } if (dvspi->tx != dvspi->tx_end) { transfer_success = 0; } } else if (dvspi->tx != NULL) { if (dvspi->wr) { dvspi->wr(dvspi); } if (dvspi->tx != dvspi->tx_end) { transfer_success = 0; } } else if (dvspi->rx != NULL) { if (dvspi->rd) { dvspi->rd(dvspi); } if (dvspi->rx != dvspi->rx_end) { transfer_success = 0; } } dev_dbg(&dvspi->pdev->dev, "spi_davinci_pump_transfers: success=%d\n", transfer_success); if (!(transfer_success)) { message->state = ERROR_STATE; } else { message->actual_length += dvspi->len; message->state = spi_davinci_next_transfer(dvspi); } tasklet_schedule(&dvspi->pump_transfers); spin_unlock_irqrestore(&dvspi->lock, flags); } /*************************************************** * spi_davinci_pump_messages * *-------------------------------------------------* * Send a message. Schedules transfer tasklet * which kickstarts sending a messages transfer * list. ***************************************************/ static void spi_davinci_pump_messages(struct work_struct *work) { struct davinci_spi *dvspi; unsigned long flags; dvspi = container_of(work, struct davinci_spi, pump_messages); dev_dbg(&dvspi->pdev->dev, "spi_davinci_pump_messages: m=%p, t=%p\n", dvspi->cur_msg, dvspi->cur_transfer); spin_lock_irqsave(&dvspi->lock, flags); dev_dbg(&dvspi->pdev->dev, "spi_davinci_pump_messages: list empty=%d\n", list_empty(&dvspi->queue)); if (list_empty(&dvspi->queue) || dvspi->run == QUEUE_STOPPED) { dvspi->busy = 0; spin_unlock_irqrestore(&dvspi->lock, flags); return; } if (dvspi->cur_msg) { spin_unlock_irqrestore(&dvspi->lock, flags); return; } dvspi->cur_msg = list_entry(dvspi->queue.next, struct spi_message, queue); list_del_init(&dvspi->cur_msg->queue); dev_dbg(&dvspi->pdev->dev, "spi_davinci_pump_messages: mq=%p, qn=%p\n", &dvspi->queue.next, &dvspi->cur_msg->queue); iowrite8(0, dvspi->regs_base+(SPIDAT1 + 3)); dvspi->cur_msg->state = START_STATE; dvspi->cur_transfer = list_entry(dvspi->cur_msg->transfers.next, struct spi_transfer, transfer_list); tasklet_schedule(&dvspi->pump_transfers); dvspi->busy = 1; spin_unlock_irqrestore(&dvspi->lock, flags); } /*************************************************** * spi_davinci_intr * *-------------------------------------------------* * Interrupt handler is only used to update the * length of the message being transmitted. ***************************************************/ static irqreturn_t spi_davinci_intr(int irq, void *dev_id) { struct davinci_spi *dvspi = (struct davinci_spi *) dev_id; unsigned short status; struct spi_message *message = NULL; dev_dbg(&dvspi->pdev->dev, "spi_davinci_intr\n"); spin_lock(&dvspi->lock); status = ioread16(dvspi->regs_base+SPIFLG); iowrite16(status, dvspi->regs_base+SPIFLG); message = dvspi->cur_msg; spin_unlock(&dvspi->lock); if (status & SPIFLG_RXINTFLG) { if (message) { message->actual_length += dvspi->len_in_bytes; complete(&dvspi->rx_done); } return IRQ_HANDLED; } return IRQ_NONE; } /*************************************************** * spi_davinci_setup * *-------------------------------------------------* * Configure the chip select on the davinci and * setup the transfer function pointers for davinci. ***************************************************/ static int spi_davinci_setup(struct spi_device *spi) { unsigned long csr; unsigned int bits = spi->bits_per_word; struct davinci_spi *dvspi = spi_master_get_devdata(spi->master); if (spi->chip_select > spi->master->num_chipselect) { dev_err(&spi->dev, "setup: invalid chipselect %u (%u defined)\n", spi->chip_select, spi->master->num_chipselect); return -EINVAL; } if (bits == 0) { bits = 8; } if (bits < 8 || bits > 16) { dev_dbg(&spi->dev, "setup: invalid bits_per_word %u\n", bits); return -EINVAL; } if (spi->mode & ~MODEBITS) { dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", spi->mode & ~MODEBITS); return -EINVAL; } /* disable SPI before changing params */ iowrite32(0, dvspi->regs_base+SPIGCR1); csr = SPIFMTX_PRESCALE_VAL | bits; if (spi->mode & SPI_CPOL) { csr |= SPIFMTX_POLARITY; } if (spi->mode & SPI_CPHA) { csr |= SPIFMTX_PHASE; } dvspi->wr = u16_write; dvspi->rd = u16_read; dvspi->duplex = u16_duplex; iowrite32(csr, dvspi->regs_base+(SPIFMT0 + (spi->chip_select * 4))); /* enable SPI, CLK and Master modes */ iowrite32(SPIGCR1_SPIEN | SPIGCR1_CLKMOD | SPIGCR1_MASTER, dvspi->regs_base+SPIGCR1); return 0; } /*************************************************** * spi_davinci_cleanup * *-------------------------------------------------* * ***************************************************/ static void spi_davinci_cleanup(struct spi_device *spi) { return; } /*************************************************** * spi_davinci_transfer * *-------------------------------------------------* * Append transfer to message queue and trigger * pump_messages. ***************************************************/ static int spi_davinci_transfer(struct spi_device *spi, struct spi_message *msg) { struct davinci_spi *dvspi = spi_master_get_devdata(spi->master); unsigned long flags; dev_dbg(&dvspi->pdev->dev, "spi_davinci_transfer: m=%p, t=%p\n", dvspi->cur_msg, dvspi->cur_transfer); spin_lock_irqsave(&dvspi->lock, flags); if (dvspi->run == QUEUE_STOPPED) { spin_unlock_irqrestore(&dvspi->lock, flags); return -ESHUTDOWN; } msg->actual_length = 0; msg->status = -EINPROGRESS; msg->state = START_STATE; dev_dbg(&dvspi->pdev->dev, "spi_davinci_transfer: message=%p\n", msg); list_add_tail(&msg->queue, &dvspi->queue); if (dvspi->run == QUEUE_RUNNING) { queue_work(dvspi->workqueue, &dvspi->pump_messages); } spin_unlock_irqrestore(&dvspi->lock, flags); return 0; } /*************************************************** * spi_davinci_init_queue * *-------------------------------------------------* * Initialize work queue for message handling. ***************************************************/ static inline int spi_davinci_init_queue(struct davinci_spi *dvspi) { INIT_LIST_HEAD(&dvspi->queue); spin_lock_init(&dvspi->lock); dvspi->run = QUEUE_STOPPED; dvspi->busy = 0; tasklet_init(&dvspi->pump_transfers, spi_davinci_pump_transfers, (unsigned long) dvspi); INIT_WORK(&dvspi->pump_messages, spi_davinci_pump_messages); dvspi->workqueue = create_singlethread_workqueue(dvspi->master->dev.parent-> bus_id); if (!(dvspi->workqueue)) { return -EBUSY; } return 0; } /*************************************************** * spi_davinci_start_queue * *-------------------------------------------------* * Enable work queue. ***************************************************/ static inline int spi_davinci_start_queue(struct davinci_spi *dvspi) { unsigned long flags; spin_lock_irqsave(&dvspi->lock, flags); if (dvspi->run == QUEUE_RUNNING || dvspi->busy) { spin_unlock_irqrestore(&dvspi->lock, flags); return -EBUSY; } dvspi->run = QUEUE_RUNNING; dvspi->cur_msg = NULL; dvspi->cur_transfer = NULL; spin_unlock_irqrestore(&dvspi->lock, flags); queue_work(dvspi->workqueue, &dvspi->pump_messages); return 0; } /*************************************************** * spi_davinci_probe * *-------------------------------------------------* * Detect davinci SPI and configure davinci SPI * bus. ***************************************************/ static int __init spi_davinci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct spi_master *master; struct davinci_spi *dvspi; struct resource *res; int status = 0; int irq; irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "cannot get platform irq\n"); return irq; } master = spi_alloc_master(dev, sizeof(struct davinci_spi)); if (!(master)) { dev_err(dev, "cannot alloc spi master\n"); return -ENOMEM; } dvspi = spi_master_get_devdata(master); dvspi->master = master; dvspi->pdev = pdev; dvspi->irq = irq; dvspi->clk = clk_get(&pdev->dev, "SPICLK"); init_completion(&dvspi->rx_done); if (!(dvspi->clk) || IS_ERR(dvspi->clk)) { dev_err(dev, "spi_davinci_probe: bad clock\n"); } master->bus_num = pdev->id; master->num_chipselect = 2; master->cleanup = spi_davinci_cleanup; master->setup = spi_davinci_setup; master->transfer = spi_davinci_transfer; status = request_irq(irq, spi_davinci_intr, 0, pdev->dev.bus_id, dvspi); if (status) { dev_err(dev, "cannot get interrupt\n"); goto error_request_irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(dev, "cannot get IORESOURCE_MEM\n"); status = -ENOENT; goto error_get_resource; } dvspi->regs_base = ioremap(res->start, (res->end - res->start + 1)); if (dvspi->regs_base == NULL) { dev_err(dev, "cannot map io\n"); status = -ENXIO; goto error_ioremap; } status = spi_davinci_init_queue(dvspi); if (status != 0) { dev_err(dev, "cannot initialize queue\n"); goto error_init_queue; } clk_enable(dvspi->clk); /* reset SPI */ iowrite32(0, dvspi->regs_base+SPIGCR0); mdelay(1); /* remove from reset */ iowrite32(SPIGCR0_RESET, dvspi->regs_base+SPIGCR0); /* enable pins: DI, DO, CLK, EN0 */ iowrite32(SPIPC0_DIFUN | SPIPC0_DOFUN | SPIPC0_CLKFUN | SPIPC0_EN0FUN, dvspi->regs_base+SPIPC0); /* set hold time and setup time */ iowrite32(SPIDELAY_T2CDELAY_VAL | SPIDELAY_C2TDELAY_VAL, dvspi->regs_base+SPIDELAY); /* set chip select for SPI_EN0 only */ iowrite32(SPIDAT1_CSNR0, dvspi->regs_base+SPIDAT1); /* errata says initialize twice */ iowrite32(SPIDAT1_CSNR0, dvspi->regs_base+SPIDAT1); /* SPI_EN0 and SPI_EN1 to 1 when idle */ iowrite32(SPIDEF_EN1DEF | SPIDEF_EN0DEF, dvspi->regs_base+SPIDEF); /* enable interrupts */ iowrite32(SPIINT_RXINTEN | SPIINT_OVRNINTEN | SPIINT_BITERRENA, dvspi->regs_base+SPIINT); status = spi_davinci_start_queue(dvspi); if (status != 0) { dev_err(dev, "cannot start queue\n"); goto error_start_queue; } platform_set_drvdata(pdev, dvspi); status = spi_register_master(master); if (status != 0) { dev_err(dev, "cannot register spi master\n"); goto error_register_master; } dev_info(&pdev->dev, "DaVinci SPI Controller at 0x%08lx (irq %d)\n", (unsigned long) res->start, irq); return 0; error_register_master: error_start_queue: error_init_queue: free_irq(irq, master); error_ioremap: iounmap(dvspi->regs_base); error_get_resource: error_request_irq: clk_put(dvspi->clk); spi_master_put(master); return status; } /*************************************************** * spi_davinci_remove * *-------------------------------------------------* * Shutdown davinci SPI bus. ***************************************************/ static int __exit spi_davinci_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct davinci_spi *dvspi = spi_master_get_devdata(master); struct spi_message *msg; dev_dbg(&pdev->dev, "spi_davinci_remove\n"); /* Terminate remaining queued transfers */ list_for_each_entry(msg, &dvspi->queue, queue) { /* REVISIT unmapping the dma is a NOP on ARM and AVR32 * but we shouldn't depend on that... */ msg->status = -ESHUTDOWN; msg->complete(msg->context); } /* Place SPI peripheral into reset */ iowrite32(0, dvspi->regs_base+SPIGCR0); /* Disable the clock thus removing power from the peripheral */ clk_disable(dvspi->clk); clk_put(dvspi->clk); free_irq(dvspi->irq, master); spi_unregister_master(master); return 0; } #ifdef CONFIG_PM static int spi_davinci_suspend(struct platform_device *pdev, pm_message_t mesg) { struct spi_master *master = platform_get_drvdata(pdev); struct davinci_spi *dvspi = spi_master_get_devdata(master); clk_disable(dvspi->clk); return 0; } static int spi_davinci_resume(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct davinci_spi *dvspi = spi_master_get_devdata(master); clk_enable(dvspi->clk); return 0; } #else #define spi_davinci_suspend NULL #define spi_davinci_resume NULL #endif static struct platform_driver spi_davinci_driver = { .driver = { .name = "spi_davinci", .owner = THIS_MODULE, }, .suspend = spi_davinci_suspend, .resume = spi_davinci_resume, .remove = __exit_p(spi_davinci_remove), }; static int __init spi_davinci_init(void) { return platform_driver_probe(&spi_davinci_driver, spi_davinci_probe); } static void __exit spi_davinci_exit(void) { platform_driver_unregister(&spi_davinci_driver); } module_init(spi_davinci_init); module_exit(spi_davinci_exit); MODULE_DESCRIPTION("DaVinci SPI Controller driver"); MODULE_AUTHOR("Brian Rhodes <b...@acdstar.com>"); MODULE_LICENSE("GPL");
_______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source@linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source