mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-01 07:49:22 +02:00
438 lines
12 KiB
Diff
438 lines
12 KiB
Diff
|
From 98e15babf1e25868d22c024dac6133cc29059d39 Mon Sep 17 00:00:00 2001
|
||
|
From: Kurt Mahan <kmahan@freescale.com>
|
||
|
Date: Sun, 9 Dec 2007 02:24:13 -0700
|
||
|
Subject: [PATCH] Fix DMA mode and cleanup driver.
|
||
|
|
||
|
LTIBName: m5445x-ssi-cleanup
|
||
|
Signed-off-by: Kurt Mahan <kmahan@freescale.com>
|
||
|
---
|
||
|
drivers/spi/ssi_audio.c | 207 ++++++++++++++++++++++++-----------------------
|
||
|
1 files changed, 104 insertions(+), 103 deletions(-)
|
||
|
|
||
|
--- a/drivers/spi/ssi_audio.c
|
||
|
+++ b/drivers/spi/ssi_audio.c
|
||
|
@@ -2,7 +2,7 @@
|
||
|
* MCF5445x audio driver.
|
||
|
*
|
||
|
* Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
|
||
|
- * Copyright Freescale Semiconductor, Inc. 2006
|
||
|
+ * Copyright Freescale Semiconductor, Inc. 2006, 2007
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
@@ -25,9 +25,11 @@
|
||
|
|
||
|
#include <asm/coldfire.h>
|
||
|
#include <asm/coldfire_edma.h>
|
||
|
+#ifdef CONFIG_M54455
|
||
|
#include <asm/mcf5445x_ssi.h>
|
||
|
#include <asm/mcf5445x_ccm.h>
|
||
|
#include <asm/mcf5445x_gpio.h>
|
||
|
+#endif
|
||
|
|
||
|
#define SOUND_DEVICE_NAME "sound"
|
||
|
#define DRIVER_NAME "ssi_audio"
|
||
|
@@ -47,8 +49,8 @@
|
||
|
|
||
|
/* TLV320DAC23 audio chip registers */
|
||
|
|
||
|
-#define CODEC_LEFT_IN_REG (0x00)
|
||
|
-#define CODEC_RIGHT_IN_REG (0x01)
|
||
|
+#define CODEC_LEFT_IN_REG (0x00)
|
||
|
+#define CODEC_RIGHT_IN_REG (0x01)
|
||
|
#define CODEC_LEFT_HP_VOL_REG (0x02)
|
||
|
#define CODEC_RIGHT_HP_VOL_REG (0x03)
|
||
|
#define CODEC_ANALOG_APATH_REG (0x04)
|
||
|
@@ -57,7 +59,7 @@
|
||
|
#define CODEC_DIGITAL_IF_FMT_REG (0x07)
|
||
|
#define CODEC_SAMPLE_RATE_REG (0x08)
|
||
|
#define CODEC_DIGITAL_IF_ACT_REG (0x09)
|
||
|
-#define CODEC_RESET_REG (0x0f)
|
||
|
+#define CODEC_RESET_REG (0x0f)
|
||
|
|
||
|
#define CODEC_SAMPLE_8KHZ (0x0C)
|
||
|
#define CODEC_SAMPLE_16KHZ (0x58)
|
||
|
@@ -71,21 +73,21 @@
|
||
|
/* DMA transfer size */
|
||
|
#define DMASIZE (16*1024)
|
||
|
|
||
|
-/* transmit eDMA channel for SSI channel 0 */
|
||
|
-#define DMA_TCD 10
|
||
|
-/* transmit eDMA channel for SSI channel 1 */
|
||
|
-#define DMA_TCD2 11
|
||
|
+/* eDMA channel for SSI channel 0 TX */
|
||
|
+#define DMA_TCD MCF_EDMA_CHAN_TIMER2
|
||
|
+/* eDMA channel for SSI channel 1 TX */
|
||
|
+#define DMA_TCD2 MCF_EDMA_CHAN_TIMER3
|
||
|
|
||
|
struct ssi_audio {
|
||
|
- struct spi_device *spi;
|
||
|
+ struct spi_device *spi;
|
||
|
u32 speed;
|
||
|
u32 stereo;
|
||
|
u32 bits;
|
||
|
u32 format;
|
||
|
- u8 isopen;
|
||
|
- u8 dmaing;
|
||
|
- u8 ssi_enabled;
|
||
|
- u8 channel;
|
||
|
+ u8 isopen;
|
||
|
+ u8 dmaing;
|
||
|
+ u8 ssi_enabled;
|
||
|
+ u8 channel;
|
||
|
spinlock_t lock;
|
||
|
u8* audio_buf;
|
||
|
};
|
||
|
@@ -129,7 +131,8 @@ static void ssi_audio_setsamplesize(int
|
||
|
}
|
||
|
|
||
|
#ifdef AUDIO_DEBUG
|
||
|
- printk(DRIVER_NAME ":ssi_audio_setsamplesize %d %d\n", audio_device->format, audio_device->bits);
|
||
|
+ printk(DRIVER_NAME ":ssi_audio_setsamplesize %d %d\n",
|
||
|
+ audio_device->format, audio_device->bits);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
@@ -157,62 +160,57 @@ void __inline__ ssi_audio_dmarun(void)
|
||
|
{
|
||
|
set_edma_params(DMA_TCD,
|
||
|
#ifdef USE_MMU
|
||
|
- virt_to_phys(&(audio_device->audio_buf[audio_start])),
|
||
|
+ virt_to_phys(&(audio_device->audio_buf[audio_start])),
|
||
|
#else
|
||
|
- (u32)&(audio_device->audio_buf[audio_start]),
|
||
|
+ (u32)&(audio_device->audio_buf[audio_start]),
|
||
|
#endif
|
||
|
- (u32)&MCF_SSI_TX0,
|
||
|
- MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
|
||
|
- 8,
|
||
|
- 4,
|
||
|
- 0,
|
||
|
- audio_count/8,
|
||
|
- audio_count/8,
|
||
|
- 0,
|
||
|
- 0,
|
||
|
- 0, // major_int
|
||
|
- 0 // disable_req
|
||
|
- );
|
||
|
+ (u32)&MCF_SSI_TX0,
|
||
|
+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
|
||
|
+ 8,
|
||
|
+ 4,
|
||
|
+ 0,
|
||
|
+ audio_count/8,
|
||
|
+ audio_count/8,
|
||
|
+ 0,
|
||
|
+ 0,
|
||
|
+ 0, // major_int
|
||
|
+ 0 // disable_req
|
||
|
+ );
|
||
|
|
||
|
set_edma_params(DMA_TCD2,
|
||
|
#ifdef USE_MMU
|
||
|
- virt_to_phys(&(audio_device->audio_buf[audio_start+4])),
|
||
|
+ virt_to_phys(&(audio_device->audio_buf[audio_start+4])),
|
||
|
#else
|
||
|
- (u32)&(audio_device->audio_buf[audio_start+4]),
|
||
|
+ (u32)&(audio_device->audio_buf[audio_start+4]),
|
||
|
#endif
|
||
|
- (u32)&MCF_SSI_TX1,
|
||
|
- MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
|
||
|
- 8,
|
||
|
- 4,
|
||
|
- 0,
|
||
|
- audio_count/8,
|
||
|
- audio_count/8,
|
||
|
- 0,
|
||
|
- 0,
|
||
|
- 1, // major_int
|
||
|
- 0 // disable_req
|
||
|
- );
|
||
|
+ (u32)&MCF_SSI_TX1,
|
||
|
+ MCF_EDMA_TCD_ATTR_SSIZE_32BIT | MCF_EDMA_TCD_ATTR_DSIZE_32BIT,
|
||
|
+ 8,
|
||
|
+ 4,
|
||
|
+ 0,
|
||
|
+ audio_count/8,
|
||
|
+ audio_count/8,
|
||
|
+ 0,
|
||
|
+ 0,
|
||
|
+ 1, // major_int
|
||
|
+ 0 // disable_req
|
||
|
+ );
|
||
|
|
||
|
audio_device->dmaing = 1;
|
||
|
audio_txbusy = 1;
|
||
|
|
||
|
start_edma_transfer(DMA_TCD);
|
||
|
start_edma_transfer(DMA_TCD2);
|
||
|
-#if 0
|
||
|
- MCF_EDMA_ERQ |= (1<<DMA_TCD) | (1<<DMA_TCD2);
|
||
|
- MCF_EDMA_SSRT = DMA_TCD;
|
||
|
- MCF_EDMA_SSRT = DMA_TCD2;
|
||
|
-#endif
|
||
|
-
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * Start DMA'ing a new buffer of data if any available.
|
||
|
+/**
|
||
|
+ * ssi_audio_dmabuf - Start DMA'ing a new buffer of data if any available.
|
||
|
*/
|
||
|
static void ssi_audio_dmabuf(void)
|
||
|
{
|
||
|
#ifdef AUDIO_DEBUG
|
||
|
- printk(DRIVER_NAME ":ssi_audio_dmabuf(): append=%x start=%x\n", audio_append, audio_appstart);
|
||
|
+ printk(DRIVER_NAME ":ssi_audio_dmabuf(): append=%x start=%x\n",
|
||
|
+ audio_append, audio_appstart);
|
||
|
#endif
|
||
|
|
||
|
/* If already running then nothing to do... */
|
||
|
@@ -241,7 +239,8 @@ static void ssi_audio_dmabuf(void)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-void __inline__ stop_dma(void) {
|
||
|
+void __inline__ stop_dma(void)
|
||
|
+{
|
||
|
stop_edma_transfer(DMA_TCD);
|
||
|
stop_edma_transfer(DMA_TCD2);
|
||
|
}
|
||
|
@@ -283,7 +282,6 @@ static void init_dma(void)
|
||
|
|
||
|
#endif /* CONFIG_SSIAUDIO_USE_EDMA */
|
||
|
|
||
|
-
|
||
|
/* Write CODEC register using SPI
|
||
|
* address - CODEC register address
|
||
|
* data - data to be written into register
|
||
|
@@ -296,7 +294,8 @@ static int codec_write(u8 addr, u16 data
|
||
|
return -ENODEV;
|
||
|
|
||
|
spi_word = ((addr & 0x7F)<<9)|(data & 0x1FF);
|
||
|
- return spi_write(audio_device->spi, (const u8*)&spi_word, sizeof(spi_word));
|
||
|
+ return spi_write(audio_device->spi, (const u8*)&spi_word,
|
||
|
+ sizeof(spi_word));
|
||
|
}
|
||
|
|
||
|
static inline void enable_ssi(void)
|
||
|
@@ -359,7 +358,7 @@ static void init_audio_codec(void)
|
||
|
codec_write(CODEC_DIGITAL_APATH_REG, 0x007); /* Set A path */
|
||
|
|
||
|
/* set sample rate */
|
||
|
- adjust_codec_speed();
|
||
|
+ adjust_codec_speed();
|
||
|
|
||
|
codec_write(CODEC_LEFT_HP_VOL_REG, 0x075); /* set volume */
|
||
|
codec_write(CODEC_RIGHT_HP_VOL_REG, 0x075); /* set volume */
|
||
|
@@ -375,13 +374,12 @@ static void chip_init(void)
|
||
|
#endif
|
||
|
|
||
|
/* Enable the SSI pins */
|
||
|
- MCF_GPIO_PAR_SSI = ( 0
|
||
|
- | MCF_GPIO_PAR_SSI_MCLK
|
||
|
- | MCF_GPIO_PAR_SSI_STXD(3)
|
||
|
- | MCF_GPIO_PAR_SSI_SRXD(3)
|
||
|
- | MCF_GPIO_PAR_SSI_FS(3)
|
||
|
- | MCF_GPIO_PAR_SSI_BCLK(3) );
|
||
|
-
|
||
|
+ MCF_GPIO_PAR_SSI = (0
|
||
|
+ | MCF_GPIO_PAR_SSI_MCLK
|
||
|
+ | MCF_GPIO_PAR_SSI_STXD(3)
|
||
|
+ | MCF_GPIO_PAR_SSI_SRXD(3)
|
||
|
+ | MCF_GPIO_PAR_SSI_FS(3)
|
||
|
+ | MCF_GPIO_PAR_SSI_BCLK(3) );
|
||
|
}
|
||
|
|
||
|
static void init_ssi(void)
|
||
|
@@ -430,8 +428,8 @@ static void init_ssi(void)
|
||
|
;
|
||
|
|
||
|
MCF_SSI_FCSR = 0
|
||
|
- | MCF_SSI_FCSR_TFWM0(0)
|
||
|
- | MCF_SSI_FCSR_TFWM1(0)
|
||
|
+ | MCF_SSI_FCSR_TFWM0(2)
|
||
|
+ | MCF_SSI_FCSR_TFWM1(2)
|
||
|
;
|
||
|
|
||
|
MCF_SSI_IER = 0 // interrupts
|
||
|
@@ -459,9 +457,8 @@ static int ssi_audio_isr(int irq, void *
|
||
|
{
|
||
|
unsigned long *bp;
|
||
|
|
||
|
- if (audio_txbusy==0) {
|
||
|
+ if (audio_txbusy==0)
|
||
|
return IRQ_HANDLED;
|
||
|
- }
|
||
|
|
||
|
spin_lock(&(audio_device->lock));
|
||
|
|
||
|
@@ -560,7 +557,8 @@ static int ssi_audio_close(struct inode
|
||
|
}
|
||
|
|
||
|
/* write to audio device */
|
||
|
-static ssize_t ssi_audio_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
|
||
|
+static ssize_t ssi_audio_write(struct file *filp, const char *buf,
|
||
|
+ size_t count, loff_t *ppos)
|
||
|
{
|
||
|
unsigned long *dp, *buflp;
|
||
|
unsigned short *bufwp;
|
||
|
@@ -568,10 +566,12 @@ static ssize_t ssi_audio_write(struct fi
|
||
|
unsigned int slen, bufcnt, i, s, e;
|
||
|
|
||
|
#ifdef AUDIO_DEBUG
|
||
|
- printk(DRIVER_NAME ":ssi_audio_write(buf=%x,count=%d)\n", (int) buf, count);
|
||
|
+ printk(DRIVER_NAME ":ssi_audio_write(buf=%x,count=%d)\n",
|
||
|
+ (int)buf, count);
|
||
|
#endif
|
||
|
|
||
|
- if (audio_device==NULL) return (-ENODEV);
|
||
|
+ if (audio_device==NULL)
|
||
|
+ return (-ENODEV);
|
||
|
|
||
|
if (count <= 0)
|
||
|
return 0;
|
||
|
@@ -592,8 +592,8 @@ static ssize_t ssi_audio_write(struct fi
|
||
|
|
||
|
tryagain:
|
||
|
/*
|
||
|
- * Get a snapshot of buffer, so we can figure out how
|
||
|
- * much data we can fit in...
|
||
|
+ * Get a snapshot of buffer, so we can figure out how
|
||
|
+ * much data we can fit in...
|
||
|
*/
|
||
|
s = audio_start;
|
||
|
e = audio_append;
|
||
|
@@ -613,11 +613,12 @@ tryagain:
|
||
|
goto tryagain;
|
||
|
}
|
||
|
|
||
|
- /* For DMA we need to have data as 32 bit
|
||
|
- values (since SSI TX register is 32 bit).
|
||
|
- So, the incomming 16 bit data must be put to buffer as 32 bit values.
|
||
|
- Also, the endianess is converted if needed
|
||
|
- */
|
||
|
+ /*
|
||
|
+ * For DMA we need to have data as 32 bit
|
||
|
+ * values (since SSI TX register is 32 bit).
|
||
|
+ * So, the incoming 16 bit data must be put to buffer as 32 bit values.
|
||
|
+ * Also, the endianess is converted if needed
|
||
|
+ */
|
||
|
if (audio_device->stereo) {
|
||
|
if (audio_device->bits == 16) {
|
||
|
if (audio_device->format==AFMT_S16_LE) {
|
||
|
@@ -678,16 +679,19 @@ tryagain:
|
||
|
}
|
||
|
|
||
|
/* ioctl: control the driver */
|
||
|
-static int ssi_audio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
|
||
|
+static int ssi_audio_ioctl(struct inode *inode, struct file *filp,
|
||
|
+ unsigned int cmd, unsigned long arg)
|
||
|
{
|
||
|
- long val;
|
||
|
- int rc = 0;
|
||
|
+ long val;
|
||
|
+ int rc = 0;
|
||
|
|
||
|
#ifdef AUDIO_DEBUG
|
||
|
- printk(DRIVER_NAME ":ssi_audio_ioctl(cmd=%x,arg=%x)\n", (int) cmd, (int) arg);
|
||
|
+ printk(DRIVER_NAME ":ssi_audio_ioctl(cmd=%x,arg=%x)\n",
|
||
|
+ (int)cmd, (int)arg);
|
||
|
#endif
|
||
|
|
||
|
- if (audio_device==NULL) return (-ENODEV);
|
||
|
+ if (audio_device==NULL)
|
||
|
+ return (-ENODEV);
|
||
|
|
||
|
switch (cmd) {
|
||
|
|
||
|
@@ -744,8 +748,6 @@ static int ssi_audio_ioctl(struct inode
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
-/****************************************************************************/
|
||
|
-
|
||
|
struct file_operations ssi_audio_fops = {
|
||
|
open: ssi_audio_open, /* open */
|
||
|
release: ssi_audio_close, /* close */
|
||
|
@@ -756,8 +758,8 @@ struct file_operations ssi_audio_fops =
|
||
|
/* initialize audio driver */
|
||
|
static int __devinit ssi_audio_probe(struct spi_device *spi)
|
||
|
{
|
||
|
- struct ssi_audio *audio;
|
||
|
- int err;
|
||
|
+ struct ssi_audio *audio;
|
||
|
+ int err;
|
||
|
|
||
|
#ifdef AUDIO_DEBUG
|
||
|
printk(DRIVER_NAME": probe\n");
|
||
|
@@ -804,7 +806,7 @@ static int __devinit ssi_audio_probe(str
|
||
|
audio->spi = spi;
|
||
|
|
||
|
#ifndef CONFIG_SSIAUDIO_USE_EDMA
|
||
|
- if (request_irq(spi->irq, ssi_audio_isr, SA_INTERRUPT, spi->dev.bus_id, audio)) {
|
||
|
+ if (request_irq(spi->irq, ssi_audio_isr, IRQF_DISABLED, spi->dev.bus_id, audio)) {
|
||
|
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
|
||
|
err = -EBUSY;
|
||
|
goto err_free_mem;
|
||
|
@@ -813,25 +815,21 @@ static int __devinit ssi_audio_probe(str
|
||
|
#else
|
||
|
/* request 2 eDMA channels since two channel output mode is used */
|
||
|
if (request_edma_channel(DMA_TCD,
|
||
|
- ssi_audio_dma_handler_empty,
|
||
|
- NULL,
|
||
|
- audio,
|
||
|
- &(audio_device->lock),
|
||
|
- DRIVER_NAME
|
||
|
- )!=0)
|
||
|
- {
|
||
|
+ ssi_audio_dma_handler_empty,
|
||
|
+ NULL,
|
||
|
+ audio,
|
||
|
+ &(audio_device->lock),
|
||
|
+ DRIVER_NAME)!=0) {
|
||
|
dev_dbg(&spi->dev, "DMA channel %d busy?\n", DMA_TCD);
|
||
|
err = -EBUSY;
|
||
|
goto err_free_mem;
|
||
|
}
|
||
|
if (request_edma_channel(DMA_TCD2,
|
||
|
- ssi_audio_dma_handler,
|
||
|
- NULL,
|
||
|
- audio,
|
||
|
- &(audio_device->lock),
|
||
|
- DRIVER_NAME
|
||
|
- )!=0)
|
||
|
- {
|
||
|
+ ssi_audio_dma_handler,
|
||
|
+ NULL,
|
||
|
+ audio,
|
||
|
+ &(audio_device->lock),
|
||
|
+ DRIVER_NAME)!=0) {
|
||
|
dev_dbg(&spi->dev, "DMA channel %d busy?\n", DMA_TCD2);
|
||
|
err = -EBUSY;
|
||
|
goto err_free_mem;
|
||
|
@@ -870,11 +868,13 @@ static int __devexit ssi_audio_remove(st
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int ssi_audio_suspend(struct spi_device *spi, pm_message_t message) {
|
||
|
+static int ssi_audio_suspend(struct spi_device *spi, pm_message_t message)
|
||
|
+{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int ssi_audio_resume(struct spi_device *spi) {
|
||
|
+static int ssi_audio_resume(struct spi_device *spi)
|
||
|
+{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -902,5 +902,6 @@ static void __exit ssi_audio_exit(void)
|
||
|
}
|
||
|
module_exit(ssi_audio_exit);
|
||
|
|
||
|
-MODULE_DESCRIPTION("SSI/I2S Audio Driver");
|
||
|
MODULE_LICENSE("GPL");
|
||
|
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||
|
+MODULE_DESCRIPTION("SSI/I2S Audio Driver");
|